two - python分組




將多個函數應用於多個groupby列 (2)

對於第一部分,您可以傳遞鍵的列名稱的字典和值的函數列表:

In [28]: df
Out[28]:
          A         B         C         D         E  GRP
0  0.395670  0.219560  0.600644  0.613445  0.242893    0
1  0.323911  0.464584  0.107215  0.204072  0.927325    0
2  0.321358  0.076037  0.166946  0.439661  0.914612    1
3  0.133466  0.447946  0.014815  0.130781  0.268290    1

In [26]: f = {'A':['sum','mean'], 'B':['prod']}

In [27]: df.groupby('GRP').agg(f)
Out[27]:
            A                   B
          sum      mean      prod
GRP
0    0.719580  0.359790  0.102004
1    0.454824  0.227412  0.034060

更新1:

由於聚合函數在Series上起作用,因此對其他列名的引用將丟失。 為了解決這個問題,您可以引用完整的數據框並使用lambda函數中的組索引對其進行索引。

這是一個很好的解決方法:

In [67]: f = {'A':['sum','mean'], 'B':['prod'], 'D': lambda g: df.loc[g.index].E.sum()}

In [69]: df.groupby('GRP').agg(f)
Out[69]:
            A                   B         D
          sum      mean      prod  <lambda>
GRP
0    0.719580  0.359790  0.102004  1.170219
1    0.454824  0.227412  0.034060  1.182901

這裡,結果'D'列由總和'E'值組成。

更新2:

以下是我認為可以滿足你所要求的一切的一種方法。 首先製作一個自定義lambda函數。 下面,g引用該組。 匯總時,g將是一個系列。 將df.ix[]傳遞給df.ix[]將從df中選擇當前組。 然後我測試C列是否小於0.5。 返回的布爾序列被傳遞給g[] ,它只選擇那些滿足條件的行。

In [95]: cust = lambda g: g[df.loc[g.index]['C'] < 0.5].sum()

In [96]: f = {'A':['sum','mean'], 'B':['prod'], 'D': {'my name': cust}}

In [97]: df.groupby('GRP').agg(f)
Out[97]:
            A                   B         D
          sum      mean      prod   my name
GRP
0    0.719580  0.359790  0.102004  0.204072
1    0.454824  0.227412  0.034060  0.570441

docs展示瞭如何在輸出列名作為關鍵字的情況下使用dict一次在groupby對像上應用多個函數:

In [563]: grouped['D'].agg({'result1' : np.sum,
   .....:                   'result2' : np.mean})
   .....:
Out[563]: 
      result2   result1
A                      
bar -0.579846 -1.739537
foo -0.280588 -1.402938

但是,這僅適用於Series groupby對象。 當一個字典同樣通過DataFrame傳遞給一個組時,它期望這些鍵是該函數將應用於的列名。

我想要做的是將多個函數應用於多個列(但某些列將多次運行)。 此外, 一些函數將取決於groupby對中的其他列 (如sumif函數)。 我目前的解決方案是逐列,並執行類似上面的代碼,使用lambdas函數依賴其他行。 但是這需要很長時間,(我認為遍歷groupby對象需要很長時間)。 我必須改變它,以便在一次運行中遍歷整個groupby對象,但是我想知道是否有一個內置的熊貓內置方式來做到這一點乾淨。

例如,我試過類似的東西

grouped.agg({'C_sum' : lambda x: x['C'].sum(),
             'C_std': lambda x: x['C'].std(),
             'D_sum' : lambda x: x['D'].sum()},
             'D_sumifC3': lambda x: x['D'][x['C'] == 3].sum(), ...)

但正如所料,我得到一個KeyError(因為如果從DataFrame調用agg ,鍵必須是一個列)。

是否有內置的方法來執行我想要做的事情,或者可能會添加此功能,或者我只需要手動迭代groupby;

謝謝


目前接受的答案的後半部分已過時,並且有兩個棄用。 首先也是最重要的,你不能再將字典字典傳遞給agg groupby方法。 其次,不要使用.ix

如果你希望同時使用兩個單獨的列,我會建議使用apply方法,它將DataFrame傳遞給應用函數。 讓我們使用與上麵類似的數據框

df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df

          a         b         c         d  group
0  0.418500  0.030955  0.874869  0.145641      0
1  0.446069  0.901153  0.095052  0.487040      0
2  0.843026  0.936169  0.926090  0.041722      1
3  0.635846  0.439175  0.828787  0.714123      1

從列名映射到聚合函數的字典仍然是執行聚合的完美方式。

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': lambda x: x.max() - x.min()})

              a                   b         c         d
            sum       max      mean       sum  <lambda>
group                                                  
0      0.560541  0.507058  0.418546  1.707651  0.129667
1      0.187757  0.157958  0.887315  0.533531  0.652427

如果你不喜歡這個醜陋的lambda列名稱,你可以使用一個普通的函數,並提供一個自定義的名字給這個特殊的__name__屬性:

def max_min(x):
    return x.max() - x.min()

max_min.__name__ = 'Max minus Min'

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': max_min})

              a                   b         c             d
            sum       max      mean       sum Max minus Min
group                                                      
0      0.560541  0.507058  0.418546  1.707651      0.129667
1      0.187757  0.157958  0.887315  0.533531      0.652427

使用apply並返回一個Series

現在,如果您有多個需要一起交互的列,那麼您不能使用agg ,這會隱式地將一個Series傳遞給聚合函數。 當使用apply整個組作為DataFrame被傳遞到函數。

我建議製作一個自定義函數,返回一系列所有聚合。 將系列索引用作新列的標籤:

def f(x):
    d = {}
    d['a_sum'] = x['a'].sum()
    d['a_max'] = x['a'].max()
    d['b_mean'] = x['b'].mean()
    d['c_d_prodsum'] = (x['c'] * x['d']).sum()
    return pd.Series(d, index=['a_sum', 'a_max', 'b_mean', 'c_d_prodsum'])

df.groupby('group').apply(f)
          a_sum     a_max    b_mean  c_d_prodsum
group                                           
0      0.560541  0.507058  0.418546     0.118106
1      0.187757  0.157958  0.887315     0.276808

如果你愛上了MultiIndexes,你仍然可以像這樣返回一個Series:

    def f_mi(x):
        d = []
        d.append(x['a'].sum())
        d.append(x['a'].max())
        d.append(x['b'].mean())
        d.append((x['c'] * x['d']).sum())
        return pd.Series(d, index=[['a', 'a', 'b', 'c_d'], 
                                   ['sum', 'max', 'mean', 'prodsum']])

df.groupby('group').apply(f_mi)

              a                   b       c_d
            sum       max      mean   prodsum
group                                        
0      0.560541  0.507058  0.418546  0.118106
1      0.187757  0.157958  0.887315  0.276808






pandas