利用Python进行数据分析--数据聚合与分组运算

转载自:http://blog.csdn.net/ssw_1990/article/details/22422971

 

1、quantile计算Series或DataFrame列的样本分位数:

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> import numpy as np  
  2. >>> import pandas as pd  
  3. >>> df = pd.DataFrame({'key1':['a''a''b''b''a'],  
  4. ...     'key2':['one''two''one''two''one'],  
  5. ...     'data1':np.random.randn(5),  
  6. ...     'data2':np.random.randn(5)})  
  7. >>> df  
  8.       data1     data2 key1 key2  
  9. 0  0.228507 -1.820634    a  one  
  10. 1 -1.253050  0.285551    a  two  
  11. 2  1.412322  1.985010    b  one  
  12. 3  1.080160 -0.125354    b  two  
  13. 4  0.077132 -1.168355    a  one  
  14. >>> grouped = df.groupby('key1')  
  15. >>> grouped  
  16. <pandas.core.groupby.DataFrameGroupBy object at 0x03EB3510>  
  17. >>> grouped['data1']  
  18. <pandas.core.groupby.SeriesGroupBy object at 0x03EB3490>  
  19. >>> grouped['data1'].quantile(0.9)  
  20. key1  
  21. a       0.198232  
  22. b       1.379106  
  23. dtype: float64  

说明:

 

(1)虽然quantile并没有明确地实现于GroupBy,但它是一个Series方法,所以这里是能用的。实际上,GroupBy会高效地对Series进行切片,然后对各片调用piece.quantile(0.9),最后将这些结果组装成最终结果。

(2)如果传入的百分位上没有值,则quantile会进行线性插值。

(3)四分位数(Quartile),即统计学中,把所有数值由小到大排列并分成四等份,处于三个分割点位置的得分就是四分位数。

(4)线性插值经常用于补充表格中的间隔部分。假设一个表格列出了一个国家 1970年、1980年、1990年以及 2000年的人口,那么如果需要估计 1994年的人口的话,线性插值就是一种简便的方法。

 

2、有些方法(如describe)也是可以用在这里的,即时严格来讲,它们并非聚合运算:

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> grouped.describe()  
  2.                data1     data2  
  3. key1                            
  4. a    count  3.000000  3.000000  
  5.      mean  -0.315804 -0.901146  
  6.      std    0.815200  1.078218  
  7.      min   -1.253050 -1.820634  
  8.      25%   -0.587959 -1.494495  
  9.      50%    0.077132 -1.168355  
  10.      75%    0.152819 -0.441402  
  11.      max    0.228507  0.285551  
  12. b    count  2.000000  2.000000  
  13.      mean   1.246241  0.929828  
  14.      std    0.234874  1.492253  
  15.      min    1.080160 -0.125354  
  16.      25%    1.163201  0.402237  
  17.      50%    1.246241  0.929828  
  18.      75%    1.329282  1.457419  
  19.      max    1.412322  1.985010  
经过优化的groupby的方法
函数名说明
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进行分组:

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> import numpy as np  
  2. >>> import pandas as pd  
  3. >>> tips = pd.read_csv('tips.csv')  
  4. >>> # 添加“小费占总额百分比”的列  
  5. >>> tips['tip_pct'] = tips['tip']/tips['total_bill']  
  6. >>> tips[:6]  
  7.    total_bill   tip     sex smoker  day    time  size   tip_pct  
  8. 0       16.99  1.01  Female     No  Sun  Dinner     2  0.059447  
  9. 1       10.34  1.66    Male     No  Sun  Dinner     3  0.160542  
  10. 2       21.01  3.50    Male     No  Sun  Dinner     3  0.166587  
  11. 3       23.68  3.31    Male     No  Sun  Dinner     2  0.139780  
  12. 4       24.59  3.61  Female     No  Sun  Dinner     4  0.146808  
  13. 5       25.29  4.71    Male     No  Sun  Dinner     4  0.186240  
[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> grouped = tips.groupby(['sex''smoker'])  
  2. >>> grouped_pct = grouped['tip_pct']  
  3. >>> grouped  
  4. <pandas.core.groupby.DataFrameGroupBy object at 0x03EB3050>  
  5. >>> grouped_pct  
  6. <pandas.core.groupby.SeriesGroupBy object at 0x03EB3290>  
  7. >>> grouped_pct.agg('mean')  
  8. sex     smoker  
  9. Female  No        0.156921  
  10.         Yes       0.182150  
  11. Male    No        0.160669  
  12.         Yes       0.152771  
  13. Name: tip_pct, dtype: float64  

如果传入一组函数或函数名,得到的DataFrame的列就会以相应的函数命名:

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> grouped_pct.agg(['mean''std'])  
  2.                    mean       std  
  3. sex    smoker                      
  4. Female No      0.156921  0.036421  
  5.        Yes     0.182150  0.071595  
  6. Male   No      0.160669  0.041849  
  7.        Yes     0.152771  0.090588  

如果传入的是一个由(name, function)元组组成的列表,则各元组的第一个元素就会被用作DataFrame的列名(可以将这种二元元组列表看做一个有序映射):

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> grouped_pct.agg([('mean''std'), ('bar', np.std)])  
  2.                    mean       bar  
  3. sex    smoker                      
  4. Female No      0.036421  0.036421  
  5.        Yes     0.071595  0.071595  
  6. Male   No      0.041849  0.041849  
  7.        Yes     0.090588  0.090588  

 

 

4、假设我们想要对tip_pct和total_bill列计算三个统计信息:

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> functions = ['count''mean''max']  
  2. >>> result = grouped['tip_pct''total_bill'].agg(functions)  
  3. >>> result  
  4.                tip_pct                      total_bill                    
  5.                  count      mean       max       count       mean    max  
  6. sex    smoker                                                             
  7. Female No           54  0.156921  0.252672          54  18.105185  35.83  
  8.        Yes          33  0.182150  0.416667          33  17.977879  44.30  
  9. Male   No           97  0.160669  0.291990          97  19.791237  48.33  
  10.        Yes          60  0.152771  0.710345          60  22.284500  50.81  

说明:

 

(1)对于DataFrame,可以定义一组应用于全部列的函数,或不同的列应用不同的函数。

(2)结果DataFrame拥有层次化的列,这相当于分别对各列进行聚合,然后用concat将结果组装到一起(列名用作keys参数)。

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> result['tip_pct']  
  2.                count      mean       max  
  3. sex    smoker                             
  4. Female No         54  0.156921  0.252672  
  5.        Yes        33  0.182150  0.416667  
  6. Male   No         97  0.160669  0.291990  
  7.        Yes        60  0.152771  0.710345  

跟前面一样,这里也可以传入带有自定义名称的元组列表:

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> ftuples = [('Durchschnitt''mean'), ('Abweichung', np.var)]  
  2. >>> grouped['tip_pct''total_bill'].agg(ftuples)  
  3.                     tip_pct                total_bill              
  4.                Durchschnitt  Abweichung  Durchschnitt  Abweichung  
  5. sex    smoker                                                      
  6. Female No          0.156921    0.001327     18.105185   53.092422  
  7.        Yes         0.182150    0.005126     17.977879   84.451517  
  8. Male   No          0.160669    0.001751     19.791237   76.152961  
  9.        Yes         0.152771    0.008206     22.284500   98.244673  

 

如果想要对不同的列应用不同的函数,具体的办法是向agg传入一个从列名映射到函数的字典:

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> grouped.agg({'tip':np.max, 'size':'sum'})  
  2.                 tip  size  
  3. sex    smoker              
  4. Female No       5.2   140  
  5.        Yes      6.5    74  
  6. Male   No       9.0   263  
  7.        Yes     10.0   150  
  8. >>> grouped.agg({'tip_pct':['min''max''mean''std'],  
  9. ...     'size':'sum'})  
  10.                 tip_pct                                size  
  11.                     min       max      mean       std   sum  
  12. sex    smoker                                                
  13. Female No      0.056797  0.252672  0.156921  0.036421   140  
  14.        Yes     0.056433  0.416667  0.182150  0.071595    74  
  15. Male   No      0.071804  0.291990  0.160669  0.041849   263  
  16.        Yes     0.035638  0.710345  0.152771  0.090588   150  

说明:

 

只有将多个函数应用到至少一列时,DataFrame才会拥有层次化的列。

 

5、以“无索引”的形式返回聚合数据

        到目前为止,所有示例中的聚合数据都有由唯一的分组键组成的索引(可能还是层次化的)。由于并不总是需要如此,所以你可以向groupby传入as_index=False以禁用该功能。

 

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. >>> tips.groupby(['sex''smoker'], as_index=False).mean()  
  2.       sex smoker  total_bill       tip      size   tip_pct  
  3. 0  Female     No   18.105185  2.773519  2.592593  0.156921  
  4. 1  Female    Yes   17.977879  2.931515  2.242424  0.182150  
  5. 2    Male     No   19.791237  3.113402  2.711340  0.160669  
  6. 3    Male    Yes   22.284500  3.051167  2.500000  0.152771  
  7. >>> tips.groupby(['sex''smoker'], as_index=True).mean()  
  8.                total_bill       tip      size   tip_pct  
  9. sex    smoker                                            
  10. Female No       18.105185  2.773519  2.592593  0.156921  
  11.        Yes      17.977879  2.931515  2.242424  0.182150  
  12. Male   No       19.791237  3.113402  2.711340  0.160669  
  13.        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进行数据分析》

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值