与Pandas groupby/aggregate结合的百分位数
我正在尝试创建一个函数,用来计算数据框中多个变量的不同百分位数。我使用了一个字典,并结合Pandas的聚合函数,如下所示:
dfG = df.groupby('ClinicalEpisode')
dfA = dfG.agg( { 'Total LOS' :
{'Total LOS P5' : 'pd.quantile(.05)',
'Total LOS P10' : 'pd.quantile(.10)',
'Total LOS P15' : 'pd.quantile(.15)',
'Total LOS P20' : 'pd.quantile(.20)',
'Total LOS P25' : 'pd.quantile(.25)',
'Total LOS P30' : 'pd.quantile(.30)',
'Total LOS P33' : 'pd.quantile(.333333)',
'Total LOS P35' : 'pd.quantile(.35)',
'Total LOS P40' : 'pd.quantile(.40)',
'Total LOS P50' : 'pd.quantile(.50)',
'Total LOS P75' : 'pd.quantile(.75)',
'Total LOS P80' : 'pd.quantile(.80)',
'Total LOS P90' : 'pd.quantile(.90)'},
'Trigger SNF LOS' :
{'Trigger SNF LOS P5' : 'pd.quantile(.05)',
'Trigger SNF LOS P10' : 'pd.quantile(.10)',
'Trigger SNF LOS P15' : 'pd.quantile(.15)',
'Trigger SNF LOS P20' : 'pd.quantile(.20)',
'Trigger SNF LOS P25' : 'pd.quantile(.25)',
'Trigger SNF LOS P30' : 'pd.quantile(.30)',
'Trigger SNF LOS P33' : 'pd.quantile(.333333)',
'Trigger SNF LOS P35' : 'pd.quantile(.35)',
'Trigger SNF LOS P40' : 'pd.quantile(.40)',
'Trigger SNF LOS P50' : 'pd.quantile(.50)',
'Trigger SNF LOS P75' : 'pd.quantile(.75)',
'Trigger SNF LOS P80' : pd.quantile(.80),
'Trigger SNF LOS P90' : pd.quantile(.90)}
})
我尝试了很多不同的函数,但用字典的方式似乎都不行。
顺便说一下,我可以用下面的代码一次计算一个变量的这些分位数:
dfA = df.groupby('ClinicalEpisode')['Total LOS'].quantile(
[.05, .1, .15, .2, .25, .3, .3333, .35, .4, .5, .6, .7, .75, .8, .9, .95])
不过,我真的很想用字典的方法来实现这个功能。现在我卡住了。
1 个回答
7
顺便说一下,提供一些示例数据和你期望的输出结果会很有帮助。你也应该比“我卡住了”说得更清楚一些。
你遇到了两个问题:
- 没有一个叫做 pandas 的
quantile
方法。其实有一个DataFrame.quantile
方法,但我们不能用这个。这和你第二个问题有关。 - 在你的 GroupBy 对象上,聚合方法期待的是一些函数,这些函数需要接受一个数组并返回一个单一的值。我们将使用 numpy 的
percentile
,它需要一个数组和一个百分位数q
,这个百分位数的范围在 0 到 100 之间。正如我所说,groupby 期待的是一个只接受数组的函数,所以我们需要用functools.partial
来修正这个问题。
下面是怎么做的:
In [62]: percentiles = [5, 10, 15, 20, 25, 30, 33, 35, 40, 50, 75, 80, 90]
In [64]: from functools import partial
In [65]: aggs = {'P {}'.format(q): partial(np.percentile, q=q) for q in percentiles}
In [66]: aggs
Out[66]:
{'P 40': functools.partial(<function percentile at 0x10abde378>, q=40),
'P 90': functools.partial(<function percentile at 0x10abde378>, q=90),
...}
现在我们可以传入 aggs
了。
In [71]: df = pd.DataFrame(np.random.randn(20, 4))
In [72]: df['g'] = np.random.randint(0, 2, 20)
In [73]: df.groupby('g').agg({0: aggs, 1: aggs, 2:aggs})
Out[73]:
0 \
P 40 P 90 P 80 P 20 P 30 P 35 P 75
g
0 -1.451969 -0.134986 -0.466439 -1.726501 -1.475623 -1.463796 -0.632166
1 0.249210 1.363307 1.029008 -0.644655 -0.241753 0.180993 0.952654
1 \
P 5 P 15 P 25 P 33 P 50 P 10 P 40
g
0 -2.443653 -1.965552 -1.487451 -2.666927 -1.428315 -2.204603 -1.359988
1 -1.423351 -0.728314 -0.491645 -1.507900 0.381779 -1.126839 0.261025
....
如果你想要有 Total LOS ...
,可以修改字典中的键。我只用了 P [percentile]
,因为它们来自的列在 MultiIndex 的上层。