【问题标题】:Pass percentiles to pandas agg function将百分位数传递给 pandas agg 函数
【发布时间】:2013-07-08 19:46:34
【问题描述】:

我想通过 pandas 的 agg() 函数传递 numpy percentile() 函数,就像我在下面使用各种其他 numpy 统计函数一样。

现在我有一个如下所示的数据框:

AGGREGATE   MY_COLUMN
A           10
A           12
B           5
B           9
A           84
B           22

我的代码如下所示:

grouped = dataframe.groupby('AGGREGATE')
column = grouped['MY_COLUMN']
column.agg([np.sum, np.mean, np.std, np.median, np.var, np.min, np.max])

上面的代码有效,但我想做类似的事情

column.agg([np.sum, np.mean, np.percentile(50), np.percentile(95)])

即,指定从agg() 返回的各种百分位数。

这应该怎么做?

【问题讨论】:

标签: python pandas numpy aggregate


【解决方案1】:

也许效率不高,但一种方法是自己创建一个函数:

def percentile(n):
    def percentile_(x):
        return np.percentile(x, n)
    percentile_.__name__ = 'percentile_%s' % n
    return percentile_

然后将其包含在您的agg

In [11]: column.agg([np.sum, np.mean, np.std, np.median,
                     np.var, np.min, np.max, percentile(50), percentile(95)])
Out[11]:
           sum       mean        std  median          var  amin  amax  percentile_50  percentile_95
AGGREGATE
A          106  35.333333  42.158431      12  1777.333333    10    84             12           76.8
B           36  12.000000   8.888194       9    79.000000     5    22             12           76.8

请注意确保这是应该完成的方式...

【讨论】:

【解决方案2】:

更具体地说,如果您只想使用 percentile 函数聚合您的 pandas groupby 结果,python lambda 函数提供了一个非常简洁的解决方案。使用问题的符号,按百分位数 95 汇总,应该是:

dataframe.groupby('AGGREGATE').agg(lambda x: np.percentile(x['COL'], q = 95))

您还可以将此函数分配给一个变量,并将其与其他聚合函数结合使用。

【讨论】:

  • 我收到错误 TypeError: Must provide 'func' or tuples of '(column, aggfunc).知道会发生什么吗?
  • 虽然这看起来很漂亮但是def。如果您使用大数据,则效率很高
【解决方案3】:

试试这个 50% 和 95% 的百分位数:

column.describe(percentiles=[0.5, 0.95])

【讨论】:

    【解决方案4】:

    多个函数可以调用如下:

    import pandas as pd
    
    import numpy as np
    
    import random
    
    C = ['Ram', 'Ram', 'Shyam', 'Shyam', 'Mahima', 'Ram', 'Ram', 'Shyam', 'Shyam', 'Mahima']
    
    A = [ random.randint(0,100) for i in range(10) ]
    
    B = [ random.randint(0,100) for i in range(10) ]
    
    df = pd.DataFrame({ 'field_A': A, 'field_B': B, 'field_C': C })
    
    print(df)
    
    d = df.groupby('field_C')['field_A'].describe()[['mean', 'count', '25%', '50%', '75%']]
    print(d)
    

    我无法在此调用中位数,但可以使用其他功能。

    【讨论】:

    • 这会调用所有这些,但会选择一些。这对性能不利,这就是为什么你会使用 agg 而不是描述的原因。
    • @SebastianWozny 可能您可以更新您在处理大数据时推荐哪种解决方案的评论
    【解决方案5】:

    我真的很喜欢the solution Andy Hayden gave,但是,这对我来说有很多问题:

    • 如果数据框有多个列,它会聚合列而不是行?
    • 对我来说,行名是 percentile_0.5(点而不是下划线)。不知道是什么原因造成的,可能是我使用的是 Python 3。
    • 还需要导入 numpy 而不是留在 pandas 中(我知道,numpy 是在 pandas 中隐式导入的...)

    以下是修复这些问题的更新版本:

    def percentile(n):
        def percentile_(x):
            return x.quantile(n)
        percentile_.__name__ = 'percentile_{:2.0f}'.format(n*100)
        return percentile_
    

    【讨论】:

    • 你打算在你的版本中使用return x.quantile(n)吗?
    • 不错的收获!我确实做到了,谢谢你提到它。我会编辑它。
    • 我认为{:02.0f} 格式会更好地避免个位数百分比值的空格。
    【解决方案6】:

    如果您只需要describe 的一个子集(通常是最常见的所需统计信息),您可以只索引返回的 pandas 系列而不需要任何额外的函数。

    例如,我通常发现自己只需要展示第 25 个、中位数、第 75 个和计数。这可以在一行中完成,如下所示:

    columns.agg('describe')[['25%', '50%', '75%', 'count']]
    

    对于指定您自己的一组百分位数,选择的答案是一个不错的选择,但对于简单的用例,不需要额外的函数。

    【讨论】:

      【解决方案7】:

      您可以让agg() 使用自定义函数在指定列上执行:

      # 50th Percentile
      def q50(x):
          return x.quantile(0.5)
      
      # 90th Percentile
      def q90(x):
          return x.quantile(0.9)
      
      my_DataFrame.groupby(['AGGREGATE']).agg({'MY_COLUMN': [q50, q90, 'max']})
      

      【讨论】:

        【解决方案8】:

        我相信在 pandas 中执行此操作的惯用方式是:

        df.groupby("AGGREGATE").quantile([0, 0.25, 0.5, 0.75, 0.95, 1])
        

        【讨论】:

          【解决方案9】:
          df.groupby("AGGREGATE").describe(percentiles=[0, 0.25, 0.5, 0.75, 0.95, 1])
          

          默认describe函数给我们mean, count, std, min, max,通过百分位数数组你可以选择需要的百分位数。

          【讨论】:

            【解决方案10】:

            只是为了将更通用的解决方案投入到环中。假设您有一个只有一列要分组的 DF:

            df = pd.DataFrame((('A',10),('A',12),('B',5),('B',9),('A',84),('B',22)), 
                                columns=['My_KEY', 'MY_COL1'])
            

            基本上可以使用匿名 (lambda) 函数列表聚合和计算任何描述性指标,例如:

            df.groupby(['My_KEY']).agg( [np.sum, np.mean, lambda x: np.percentile(x, q=25)] )
            

            但是,如果要聚合多个列,则必须调用非匿名函数或显式调用列:

            df = pd.DataFrame((('A',10,3),('A',12,4),('B',5,6),('B',9,3),('A',84,2),('B',22,1)), 
                                columns=['My_KEY', 'MY_COL1', 'MY_COL2'])
            
            # non-anonymous function
            def percentil25 (x): 
                return np.percentile(x, q=25)
            
            # type 1: call for both columns 
            df.groupby(['My_KEY']).agg( [np.sum, np.mean, percentil25 ]  )
            
            # type 2: call each column separately
            df.groupby(['My_KEY']).agg( {'MY_COL1': [np.sum, np.mean, lambda x: np.percentile(x, q=25)],
                                         'MY_COL2': np.size})
            

            【讨论】:

              【解决方案11】:

              使用pandas.Series.quantile 方法更有效的解决方案:

              df.groupby("AGGREGATE").agg(("YOUR_COL_NAME", lambda x: x.quantile(0.5))
              

              有几个百分位值

              percentiles = [0.5, 0.9, 0.99]
              quantile_funcs = [(p, lambda x: x.quantile(p)) for p in percentiles]
              df.groupby("AGGREGATE").agg(quantile_funcs)
              

              【讨论】:

                【解决方案12】:

                您也可以使用 lambda 来实现相同的目的。类似于下面的代码:

                        agg(
                            lambda x: [
                                np.min(a=x), 
                                np.percentile(q=25,a=x), 
                                np.median(a=x), 
                                np.percentile(q=75,a=x), 
                                np.max(a=x)
                    ]
                )
                

                【讨论】:

                • 这与接受的答案有何不同?
                • 嗯,唯一不同的是,您不需要定义新函数。节省了几行代码。
                • 如何命名这些函数头?像 np.min(a=x) 你如何命名该函数的标题?
                猜你喜欢
                • 2017-11-18
                • 2014-12-08
                • 1970-01-01
                • 2020-12-05
                • 2019-01-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-07-28
                相关资源
                最近更新 更多