转载自:http://blog.csdn.net/ssw_1990/article/details/22422971
1、quantile计算Series或DataFrame列的样本分位数:
- >>> import numpy as np
- >>> import pandas as pd
- >>> df = pd.DataFrame({'key1':['a', 'a', 'b', 'b', 'a'],
- ... 'key2':['one', 'two', 'one', 'two', 'one'],
- ... 'data1':np.random.randn(5),
- ... 'data2':np.random.randn(5)})
- >>> df
- data1 data2 key1 key2
- 0 0.228507 -1.820634 a one
- 1 -1.253050 0.285551 a two
- 2 1.412322 1.985010 b one
- 3 1.080160 -0.125354 b two
- 4 0.077132 -1.168355 a one
- >>> grouped = df.groupby('key1')
- >>> grouped
- <pandas.core.groupby.DataFrameGroupBy object at 0x03EB3510>
- >>> grouped['data1']
- <pandas.core.groupby.SeriesGroupBy object at 0x03EB3490>
- >>> grouped['data1'].quantile(0.9)
- key1
- a 0.198232
- b 1.379106
- dtype: float64
说明:
(1)虽然quantile并没有明确地实现于GroupBy,但它是一个Series方法,所以这里是能用的。实际上,GroupBy会高效地对Series进行切片,然后对各片调用piece.quantile(0.9),最后将这些结果组装成最终结果。
(2)如果传入的百分位上没有值,则quantile会进行线性插值。
(3)四分位数(Quartile),即统计学中,把所有数值由小到大排列并分成四等份,处于三个分割点位置的得分就是四分位数。
(4)线性插值经常用于补充表格中的间隔部分。假设一个表格列出了一个国家 1970年、1980年、1990年以及 2000年的人口,那么如果需要估计 1994年的人口的话,线性插值就是一种简便的方法。
2、有些方法(如describe)也是可以用在这里的,即时严格来讲,它们并非聚合运算:
- >>> grouped.describe()
- data1 data2
- key1
- a count 3.000000 3.000000
- mean -0.315804 -0.901146
- std 0.815200 1.078218
- min -1.253050 -1.820634
- 25% -0.587959 -1.494495
- 50% 0.077132 -1.168355
- 75% 0.152819 -0.441402
- max 0.228507 0.285551
- b count 2.000000 2.000000
- mean 1.246241 0.929828
- std 0.234874 1.492253
- min 1.080160 -0.125354
- 25% 1.163201 0.402237
- 50% 1.246241 0.929828
- 75% 1.329282 1.457419
- max 1.412322 1.985010
函数名 | 说明 |
count | 分组中非NA值的数量 |
sum | 非NA值的和 |
mean | 非NA值的平均数 |
median | 非NA值的算术中位数 |
std、var | 无偏(分母为n-1)标准差和方差 |
min、max | 非NA值的最小值和最大值 |
prod | 非NA值的积 |
first、last | 第一个和最后一个非NA值 |
3、面向列的多函数应用
对Series或DataFrame列的聚合运算其实就是使用aggregate(使用自定义函数)或者调用mean、std之类的方法。然而,可能希望对不同的列使用不同的聚合函数,或一次应用多个函数,其实这也好办。根据sex和smoker对tips进行分组:
- >>> import numpy as np
- >>> import pandas as pd
- >>> tips = pd.read_csv('tips.csv')
- >>> # 添加“小费占总额百分比”的列
- >>> tips['tip_pct'] = tips['tip']/tips['total_bill']
- >>> tips[:6]
- total_bill tip sex smoker day time size tip_pct
- 0 16.99 1.01 Female No Sun Dinner 2 0.059447
- 1 10.34 1.66 Male No Sun Dinner 3 0.160542
- 2 21.01 3.50 Male No Sun Dinner 3 0.166587
- 3 23.68 3.31 Male No Sun Dinner 2 0.139780
- 4 24.59 3.61 Female No Sun Dinner 4 0.146808
- 5 25.29 4.71 Male No Sun Dinner 4 0.186240
- >>> grouped = tips.groupby(['sex', 'smoker'])
- >>> grouped_pct = grouped['tip_pct']
- >>> grouped
- <pandas.core.groupby.DataFrameGroupBy object at 0x03EB3050>
- >>> grouped_pct
- <pandas.core.groupby.SeriesGroupBy object at 0x03EB3290>
- >>> grouped_pct.agg('mean')
- sex smoker
- Female No 0.156921
- Yes 0.182150
- Male No 0.160669
- Yes 0.152771
- Name: tip_pct, dtype: float64
如果传入一组函数或函数名,得到的DataFrame的列就会以相应的函数命名:
- >>> grouped_pct.agg(['mean', 'std'])
- mean std
- sex smoker
- Female No 0.156921 0.036421
- Yes 0.182150 0.071595
- Male No 0.160669 0.041849
- Yes 0.152771 0.090588
如果传入的是一个由(name, function)元组组成的列表,则各元组的第一个元素就会被用作DataFrame的列名(可以将这种二元元组列表看做一个有序映射):
- >>> grouped_pct.agg([('mean', 'std'), ('bar', np.std)])
- mean bar
- sex smoker
- Female No 0.036421 0.036421
- Yes 0.071595 0.071595
- Male No 0.041849 0.041849
- Yes 0.090588 0.090588
4、假设我们想要对tip_pct和total_bill列计算三个统计信息:
- >>> functions = ['count', 'mean', 'max']
- >>> result = grouped['tip_pct', 'total_bill'].agg(functions)
- >>> result
- tip_pct total_bill
- count mean max count mean max
- sex smoker
- Female No 54 0.156921 0.252672 54 18.105185 35.83
- Yes 33 0.182150 0.416667 33 17.977879 44.30
- Male No 97 0.160669 0.291990 97 19.791237 48.33
- Yes 60 0.152771 0.710345 60 22.284500 50.81
说明:
(1)对于DataFrame,可以定义一组应用于全部列的函数,或不同的列应用不同的函数。
(2)结果DataFrame拥有层次化的列,这相当于分别对各列进行聚合,然后用concat将结果组装到一起(列名用作keys参数)。
- >>> result['tip_pct']
- count mean max
- sex smoker
- Female No 54 0.156921 0.252672
- Yes 33 0.182150 0.416667
- Male No 97 0.160669 0.291990
- Yes 60 0.152771 0.710345
跟前面一样,这里也可以传入带有自定义名称的元组列表:
- >>> ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)]
- >>> grouped['tip_pct', 'total_bill'].agg(ftuples)
- tip_pct total_bill
- Durchschnitt Abweichung Durchschnitt Abweichung
- sex smoker
- Female No 0.156921 0.001327 18.105185 53.092422
- Yes 0.182150 0.005126 17.977879 84.451517
- Male No 0.160669 0.001751 19.791237 76.152961
- Yes 0.152771 0.008206 22.284500 98.244673
如果想要对不同的列应用不同的函数,具体的办法是向agg传入一个从列名映射到函数的字典:
- >>> grouped.agg({'tip':np.max, 'size':'sum'})
- tip size
- sex smoker
- Female No 5.2 140
- Yes 6.5 74
- Male No 9.0 263
- Yes 10.0 150
- >>> grouped.agg({'tip_pct':['min', 'max', 'mean', 'std'],
- ... 'size':'sum'})
- tip_pct size
- min max mean std sum
- sex smoker
- Female No 0.056797 0.252672 0.156921 0.036421 140
- Yes 0.056433 0.416667 0.182150 0.071595 74
- Male No 0.071804 0.291990 0.160669 0.041849 263
- Yes 0.035638 0.710345 0.152771 0.090588 150
说明:
只有将多个函数应用到至少一列时,DataFrame才会拥有层次化的列。
5、以“无索引”的形式返回聚合数据
到目前为止,所有示例中的聚合数据都有由唯一的分组键组成的索引(可能还是层次化的)。由于并不总是需要如此,所以你可以向groupby传入as_index=False以禁用该功能。
- >>> tips.groupby(['sex', 'smoker'], as_index=False).mean()
- sex smoker total_bill tip size tip_pct
- 0 Female No 18.105185 2.773519 2.592593 0.156921
- 1 Female Yes 17.977879 2.931515 2.242424 0.182150
- 2 Male No 19.791237 3.113402 2.711340 0.160669
- 3 Male Yes 22.284500 3.051167 2.500000 0.152771
- >>> tips.groupby(['sex', 'smoker'], as_index=True).mean()
- total_bill tip size tip_pct
- sex smoker
- Female No 18.105185 2.773519 2.592593 0.156921
- Yes 17.977879 2.931515 2.242424 0.182150
- Male No 19.791237 3.113402 2.711340 0.160669
- Yes 22.284500 3.051167 2.500000 0.152771
6、参考文献
[1] 四分位数:http://baike.baidu.com/link?url=c744i_30IlKA4Jck9nB-Ti5vn3wJnJUGuHO96O_9ZQYQHi_ai42kQtmM3v-J79MS
[2] 线性插值: http://zh.wikipedia.org/wiki/%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC
[3]《利用Python进行数据分析》