代码之家  ›  专栏  ›  技术社区  ›  yoonghm

使用Pandas计算频率和计数记录[重复]

  •  0
  • yoonghm  · 技术社区  · 6 年前

    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
    

    但是,这只适用于序列groupby对象。当dict以类似的方式传递给groupby数据帧时,它希望键是将应用该函数的列名。

    某些函数将依赖于groupby对象中的其他列 (就像sumif函数)。我当前的解决方案是逐列执行,并执行类似于上面的代码的操作,对依赖于其他行的函数使用lambdas。但这需要很长时间(我认为遍历groupby对象需要很长时间)。我必须更改它,以便在一次运行中遍历整个groupby对象,但我想知道pandas中是否有一种内置的方法可以更干净地完成此操作。

    例如,我试过

    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(因为keys必须是一列,如果 agg 从数据帧调用)。

    是否有任何内置的方法来完成我想做的事情,或者有可能添加此功能,或者我只需要手动遍历groupby?

    0 回复  |  直到 12 年前
        1
  •  236
  •   JejeBelfort Ted Petrou    5 年前

    目前接受的答案的后半部分已经过时,并有两种反对意见。首先也是最重要的是,你不能再把字典传给 agg groupby方法。第二,不要使用 .ix

    如果您希望同时使用两个独立的列,我建议您使用 apply 方法,该方法隐式地将数据帧传递给应用的函数。让我们使用一个类似于上面的数据帧

    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.864569  0.446069  0.466054  0.969921  0.341399
    1      1.478872  0.843026  0.687672  1.754877  0.672401
    

    如果不喜欢这个难看的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.864569  0.446069  0.466054  0.969921      0.341399
    1      1.478872  0.843026  0.687672  1.754877      0.672401
    

    应用 并返回一系列

    聚合 ,它隐式地将序列传递给聚合函数。使用时 应用 整个组作为数据帧传递到函数中。

    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.864569  0.446069  0.466054     0.173711
    1      1.478872  0.843026  0.687672     0.630494
    

    如果您喜欢多索引,您仍然可以返回一个包含以下内容的序列:

        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.864569  0.446069  0.466054  0.173711
    1      1.478872  0.843026  0.687672  0.630494
    
        2
  •  164
  •   RK1 w--    6 年前

    在第一部分中,可以传递键的列名dict和值的函数列表:

    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:

    由于聚合函数在序列上工作,因此对其他列名的引用将丢失。要解决这个问题,可以引用完整的数据帧,并使用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将是一个系列。经过 g.index df.ix[] 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
    
        3
  •  17
  •   r2evans    6 年前

    df.groupby('group') \
      .apply(lambda x: pd.Series({
          'a_sum'       : x['a'].sum(),
          'a_max'       : x['a'].max(),
          'b_mean'      : x['b'].mean(),
          'c_d_prodsum' : (x['c'] * x['d']).sum()
      })
    )
    
              a_sum     a_max    b_mean  c_d_prodsum
    group                                           
    0      0.530559  0.374540  0.553354     0.488525
    1      1.433558  0.832443  0.460206     0.053313
    

    我觉得它更让人想起 dplyr 管道和 data.table def 这些类型操作的函数。这只是一种选择,未必更好。)


    我以与Ted相同的方式生成数据,我将添加一个种子以实现再现性。

    import numpy as np
    np.random.seed(42)
    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.374540  0.950714  0.731994  0.598658      0
    1  0.156019  0.155995  0.058084  0.866176      0
    2  0.601115  0.708073  0.020584  0.969910      1
    3  0.832443  0.212339  0.181825  0.183405      1
    
        4
  •  16
  •   Erfan    5 年前

    Pandas >= 0.25.0

    从熊猫版开始 0.25.0 named aggregations 接受 tuple . 现在我们可以同时聚合+重命名为更具信息性的列名:

    例子 :

    df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
    df['group'] = [0, 0, 1, 1]
    
              a         b         c         d  group
    0  0.521279  0.914988  0.054057  0.125668      0
    1  0.426058  0.828890  0.784093  0.446211      0
    2  0.363136  0.843751  0.184967  0.467351      1
    3  0.241012  0.470053  0.358018  0.525032      1
    

    GroupBy.agg 使用命名聚合:

    df.groupby('group').agg(
                 a_sum=('a', 'sum'),
                 a_mean=('a', 'mean'),
                 b_mean=('b', 'mean'),
                 c_sum=('c', 'sum'),
                 d_range=('d', lambda x: x.max() - x.min())
    )
    
              a_sum    a_mean    b_mean     c_sum   d_range
    group                                                  
    0      0.947337  0.473668  0.871939  0.838150  0.320543
    1      0.604149  0.302074  0.656902  0.542985  0.057681
    
        5
  •  4
  •   exan    5 年前

    New in version 0.25.0.

    为了支持对输出列名进行控制的列特定聚合,pandas接受 ,称为 命名聚合 ,其中

    • 值是元组,其第一个元素是要选择的列,第二个元素是要应用于该列的聚合。Pandas为Pandas.namedag namedtuple提供字段['column','aggfunc']以使其更清楚地说明参数是什么。与往常一样,聚合可以是可调用的别名或字符串别名。
        In [79]: animals = pd.DataFrame({'kind': ['cat', 'dog', 'cat', 'dog'],
           ....:                         'height': [9.1, 6.0, 9.5, 34.0],
           ....:                         'weight': [7.9, 7.5, 9.9, 198.0]})
           ....: 
    
        In [80]: animals
        Out[80]: 
          kind  height  weight
        0  cat     9.1     7.9
        1  dog     6.0     7.5
        2  cat     9.5     9.9
        3  dog    34.0   198.0
    
        In [81]: animals.groupby("kind").agg(
           ....:     min_height=pd.NamedAgg(column='height', aggfunc='min'),
           ....:     max_height=pd.NamedAgg(column='height', aggfunc='max'),
           ....:     average_weight=pd.NamedAgg(column='weight', aggfunc=np.mean),
           ....: )
           ....: 
        Out[81]: 
              min_height  max_height  average_weight
        kind                                        
        cat          9.1         9.5            8.90
        dog          6.0        34.0          102.75
    

        In [82]: animals.groupby("kind").agg(
           ....:     min_height=('height', 'min'),
           ....:     max_height=('height', 'max'),
           ....:     average_weight=('weight', np.mean),
           ....: )
           ....: 
        Out[82]: 
              min_height  max_height  average_weight
        kind                                        
        cat          9.1         9.5            8.90
        dog          6.0        34.0          102.75
    

    其他关键字参数不会传递给聚合函数。只应将成对(column,aggfunc)作为**kwargs传递。如果聚合函数需要其他参数,请使用functools.partial()部分应用它们。

    命名聚合也适用于序列groupby聚合。在这种情况下没有列选择,因此值只是函数。

        In [84]: animals.groupby("kind").height.agg(
           ....:     min_height='min',
           ....:     max_height='max',
           ....: )
           ....: 
        Out[84]: 
              min_height  max_height
        kind                        
        cat          9.1         9.5
        dog          6.0        34.0
    
        6
  •  1
  •   campo    6 年前

    创建数据帧

    df=pd.DataFrame({'a': [1,2,3,4,5,6], 'b': [1,1,0,1,1,0], 'c': ['x','x','y','y','z','z']})
    
    
       a  b  c
    0  1  1  x
    1  2  1  x
    2  3  0  y
    3  4  1  y
    4  5  1  z
    5  6  0  z
    

    使用apply进行分组和聚合(使用多个列)

    df.groupby('c').apply(lambda x: x['a'][(x['a']>1) & (x['b']==1)].mean())
    
    c
    x    2.0
    y    4.0
    z    5.0
    

    使用聚合进行分组和聚合(使用多个列)

    现在看来很明显,但只要你不选择感兴趣的列 ,您将可以从聚合函数中访问数据帧的所有列。

    仅访问选定列

    df.groupby('c')['a'].aggregate(lambda x: x[x>1].mean())
    

    访问所有列,因为选择毕竟是魔术

    df.groupby('c').aggregate(lambda x: x[(x['a']>1) & (x['b']==1)].mean())['a']
    

    或类似

    df.groupby('c').aggregate(lambda x: x['a'][(x['a']>1) & (x['b']==1)].mean())
    

    我希望这能有帮助。