将百分位数传递给 pandas agg 函数

Posted

技术标签:

【中文标题】将百分位数传递给 pandas agg 函数【英文标题】:Pass percentiles to pandas agg function 【发布时间】: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() 返回的各种百分位数。

这应该怎么做?

【问题讨论】:

这可能是 Pandas 的一个较新的方面,但请查看 ***.com/questions/19894939/…。 TLDR:df.groupby('C').quantile(.95) 【参考方案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

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

【讨论】:

这对我来说有多个问题,请参阅my answer below。【参考方案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) 你如何命名该函数的标题?

以上是关于将百分位数传递给 pandas agg 函数的主要内容,如果未能解决你的问题,请参考以下文章

Pandas .. 分位数函数是不是需要排序数据来计算百分位数?

Python Pandas:将参数传递给 agg() 中的函数

滚动百分位数 - 熊猫

JavaScript中的分位数/百分点/百分位数/逆累积分布函数

Python Pandas - 如何通过描述函数计算 25 个百分位数

15、pandas的设置数字格式,小数位数、百分号、千位分隔符