将百分位数传递给 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中的分位数/百分点/百分位数/逆累积分布函数