专栏名称: 挖地兔
金融数据采集与挖掘,开启量化金融的第一扇大门。
目录
相关文章推荐
E药经理人  ·  完整版回放重磅上线 | ... ·  2 天前  
E药经理人  ·  60亿索赔“惊魂记”!诺和诺德怒告KBP,B ... ·  2 天前  
医学影像沙龙  ·  看完1000张CT的脖子,这下有救了! ·  2 天前  
解螺旋  ·  DeepSeek超全指令曝光,复制就能用!还 ... ·  2 天前  
赛柏蓝  ·  2025|中成药集采后,产品如何卖? ·  3 天前  
51好读  ›  专栏  ›  挖地兔

Pandas必备技能之“分组聚合操作”

挖地兔  · 公众号  ·  · 2019-06-27 05:08

正文



T U SHARE 金融与技术学习兴趣小组


翻译整理 | 一只小绿怪兽



在处理数据的过程中,知道如何对数据集进行 分组、聚合 操作是一项必备的技能,能够大大提升数据分析的效率。



分组 是指根据一个或多个键将数据拆分为多个组的过程,这里的键可以理解为分组的条件。 聚合 指的是任何能够从数组产生标量值的数据转换过程。 分组、聚合 操作一般会同时出现,用于计算分组数据的统计值或实现其他功能。



本文会介绍如何利用 Pandas 中提供的 groupby 功能,灵活高效地对数据集进行 分组、聚合 操作。



【工具】Python 3

【数据】 Tushare

【注】示例注重的是方法的讲解,请大家灵活掌握。




01


原理



Pandas中用 groupby 机制进行分组、聚合操作的原理可以分为三个阶段,即 “拆分split-应用apply-合并combine” 下图就是一个简单的分组聚合过程。





第一阶段,数据会根据一个或多个键 key 被拆分 split 成多组,然后将一个函数应用 apply 到各个分组并产生一个新值,最后所有这些函数的执行结果会被合并 combine 到最终的结果对象中。




02


groupby函数



用Pandas中提供的分组函数 groupby 【1】能够很方便地对表格进行分组操作。我们先从 tushare.pro 上面获取一个包含三只股票日线行情数据的表格。



import tushare as ts
import pandas as pd


pd.set_option('expand_frame_repr'False)  # 显示所有列
ts.set_token('your token')
pro = ts.pro_api()

code_list = ['000001.SZ''600000.SH''000002.SZ']
stock_data = pd.DataFrame()
for code in code_list:
    print(code)
    df = pro.daily(ts_code=code, start_date='20180101', end_date='20180104')
    stock_data = stock_data.append(df, ignore_index=True)

print(stock_data)


000001.SZ
600000.SH
000002.SZ
     ts_code trade_date   open   high    low  close  pre_close  change  pct_chg         vol       amount
0   000001.SZ   20180104  13.32  13.37  13.13  13.25      13.33   -0.08    -0.60  1854509.48  2454543.516
1  000001.SZ   20180103  13.73  13.86  13.20  13.33      13.70   -0.37    -2.70  2962498.38  4006220.766
2  000001.SZ   20180102  13.35  13.93  13.32  13.70      13.30    0.40     3.01  2081592.55  2856543.822
3  600000.SH   20180104  12.70  12.73  12.62  12.66      12.66    0.00     0.00   278838.04   353205.838
4  600000.SH   20180103  12.73  12.80  12.66  12.66      12.72   -0.06    -0.47   378391.01   480954.809
5  600000.SH   20180102  12.61  12.77  12.60  12.72      12.59    0.13     1.03   313230.53   398614.966
6  000002.SZ   20180104  32.76  33.53  32.10  33.12      32.33    0.79     2.44   529085.80  1740602.533
7  000002.SZ   20180103  32.50  33.78  32.23  32.33      32.56   -0.23    -0.71   646870.20  2130249.691
8  000002.SZ   20180102  31.45  32.99  31.45  32.56      31.06    1.50     4.83   683433.50   2218502.766



接下来,我们以股票代码'ts_code'这一列为键,用 groupby 函数对表格进行分组,代码如下。



grouped = stock_data.groupby('ts_code')
print(grouped)




注意,这里并没有打印出表格,而是一个 GroupBy 对象,因为我们还没有对分组进行计算。也就是说,目前只完成了上面提到的第一个阶段的 拆分split 操作,需要继续调用聚合函数完成计算。




03


聚合函数



常用的聚合函数如下,我们继续用上面的表格数据进行演示。



① 按列'ts_code'分组,用函数 .mean() 计算分组中收盘价列'close'的平均值。



     ts_code trade_date   open   high    low  close  pre_close  change  pct_chg         vol       amount
0  000001.SZ   20180104  13.32  13.37  13.13  13.25      13.33   -0.08    -0.60  1854509.48  2454543.516
1  000001.SZ   20180103  13.73  13.86  13.20  13.33      13.70   -0.37    -2.70  2962498.38  4006220.766
2  000001.SZ   20180102  13.35  13.93  13.32  13.70      13.30    0.40     3.01  2081592.55  2856543.822
3  600000.SH   20180104  12.70  12.73  12.62  12.66      12.66    0.00     0.00   278838.04   353205.838
4  600000.SH   20180103  12.73  12.80  12.66  12.66      12.72   -0.06    -0.47   378391.01   480954.809
5  600000.SH   20180102   12.61  12.77  12.60  12.72      12.59    0.13     1.03   313230.53   398614.966
6  000002.SZ   20180104  32.76  33.53  32.10  33.12      32.33    0.79     2.44   529085.80  1740602.533
7  000002.SZ   20180103  32.50  33.78  32.23  32.33      32.56   -0.23    -0.71   646870.20  2130249.691
8  000002.SZ   20180102  31.45  32.99  31.45  32.56      31.06    1.50     4.83   683433.50  2218502.766

grouped = stock_data.groupby('ts_code')
print(grouped['close'].mean())

ts_code
000001.SZ    13.426667
000002.SZ    32.670000
600000.SH    12.680000
Name: close, dtype: float64



② 按列'ts_code'分组,用函数 .sum() 计算分组中收盘价涨跌幅(%)列'pct_chg'的和。



print(grouped['pct_chg'].sum())

ts_code
000001.SZ   -0.29
000002.SZ    6.56
600000.SH    0.56
Namepct_chgdtypefloat64



按列'ts_code'分组,用函数 .count() 计算分组中收盘价列'close'的数量。



print(grouped['close'].count())

ts_code
000001.SZ    3
000002.SZ    3
600000.SH    3
Nameclosedtypeint64



按列'ts_code'分组,用函数 .max() .min() 计算分组中收盘价列'close'的最大、最小值。



print(grouped['close'].max())
print(grouped['close'].min())

ts_code
000001.SZ    13.70
000002.SZ    33.12
600000.SH    12.72
Nameclosedtypefloat64

ts_code
000001.SZ    13.25
000002.SZ    32.33
600000.SH    12.66
Nameclosedtypefloat64



按列'ts_code'分组,用函数 .median() 计算分组中收盘价列'close'的算术中位数。



print(grouped['close'].median())

ts_code
000001.SZ    13.33
000002.SZ    32.56
600000.SH    12.66
Nameclosedtypefloat64



我们也可以用 多个键 进行分组聚合。示例中以['ts_code', 'trade_date']为键,从左到右的先后顺序分组,然后调用.count()函数计算分组中的数量。



by_mult = stock_data.groupby(['ts_code''trade_date'])
print(by_mult['close'].count())

ts_code    trade_date
000001.SZ  20180102      1
           20180103      1
           20180104      1
000002.SZ  20180102      1
           20180103      1
           20180104      1
600000.SH  20180102      1
           20180103      1
           20180104      1
Name: close, dtype: int64



如果不想把分组键设置为索引,可以向groupby传⼊参数 as_index=False



by_mult = stock_data.groupby(['ts_code''trade_date'], as_index=False)
print(by_mult['close'].count())

     ts_code trade_date  close
0  000001.SZ   20180102      1
1  000001.SZ   20180103      1
2  000001.SZ   20180104      1
3  000002.SZ   20180102      1
4  000002.SZ   20180103      1
5  000002.SZ   20180104      1
6  600000.SH   20180102      1
7  600000.SH   20180103      1
8  600000.SH   20180104      1



如果想要 一次应用多个聚合函数 可以调用 .agg() 【2】方法。



aggregated = grouped['close'].agg(['max''median'])
print(aggregated)

           close       
             max median
ts_code                
000001.SZ  13.70  13.33
000002.SZ  33.12  32.56
600000.SH  12.72  12.66



也可以对 多个列 一次应用多个聚合函数。



aggregated = grouped['pre_close''close'].agg(['max''median'])
print(aggregated)

          pre_close         close        
                max median    max median
ts_code                                 
000001.SZ     13.70  13.33  13.70  13.33
000002.SZ     32.56  32.33  33.12  32.56
600000.SH     12.72  12.66  12.72  12.66



还可以对 不同列 应用 不同的聚合函数 这里我们先自己定义一个聚合函数spread,用于计算最大值和最小值之间的差值,再 调用 .agg() 方法,传⼊⼀个从列名映射到函数的字典。



def spread(series):
    return series.max() - series.min()

aggregator = {'close''mean''vol''sum''pct_chg': spread}
aggregated = grouped.agg(aggregator)
print(aggregated)

               close         vol  pct_chg
ts_code                                  
000001.SZ  13.426667  6898600.41     5.71
000002.SZ  32.670000  1859389.50     5.54
600000.SH  12.680000   970459.58     1.50




04


巧用apply函数



巧用 apply 【3】并传入自定义函数,可以实现更一般性的“拆分-应用-合并”的操作,传入的自定义函数可以是任何你想要实现的功能。下面举几个实例。



用分组平均值填充NaN值。



     ts_code trade_date         vol
0  000001.SZ   20180102  2081592.55
1  000001.SZ   20180103  2962498.38
2  000001.SZ   20180104         NaN
3  600000.SH   20180102   313230.53
4  600000.SH   20180103   378391.01
5  600000.SH   20180104         NaN
6  000002.SZ   20180102   683433.50
7  000002.SZ   20180103   646870.20
8  000002.SZ   20180104         NaN

fill_mean = lambda g: g.fillna(g.mean())
stock_data = stock_data.groupby('ts_code', as_index=False, group_keys=False).apply(fill_mean)
print(stock_data)

    ts_code trade_date          vol
0  000001.SZ   20180102  2081592.550
1  000001.SZ   20180103  2962498.380
2  000001.SZ   20180104  2522045.465
6  000002.SZ   20180102   683433.500






请到「今天看啥」查看全文