第10章 数据聚合与分组运算

10.1 groupby机制

将数据集进行分组并对各组应用一个函数通常书数据分析工作中的重要环节

"split-apply-combine"(拆分-应用-合并):对pandans等对象的某一个轴拆分成多个组,在对各个组应用函数,将各组得到的结果合并到一个新的对象中

image.png

按照列key1进行分组,并求出每组的平均值

grouped=df.groupby('key1')
grouped.mean()
image.png
df
image.png

按照key1对data1的数据进行分组求平均值:

df['data1'].groupby(df['key1']).mean()
image.png

Series根据分组键进行聚合,再进行函数运算后返回一个新的Series对象
分组键也可以是列表

df['data1'].groupby([df['key1'],df['key2']]).mean()
image.png

实际上,分组键可以是任何长度适当的数组

states = np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
years = np.array([2005, 2005, 2006, 2005, 2006])
df['data1'].groupby([states,years]).mean()

直接对DataFrame进行分组聚合

df.groupby(['key1']).mean()
image.png

返回的结果中没有key2列,因为df['key2']不是数值列,所以被认为是‘麻烦列’,会在结果中自动滤除

返回各个分组大小的Series对象:groupby().size()

对分组进行迭代

for name,group in df.groupby(['key1','key2']):
    print(name)
    print('...seperator...')
    print(group)
image.png

默认情况下分组是在0轴上进行的,也可以更改axis使之在1轴上传播。
如下,使得df根据每列的数据类型进行分组

df

grouped=df.groupby(df.dtypes,axis=1)
for key,value in grouped:
    print(key)
    print(value)
df.dtypes
image.png

选取一列或列的子集

通过字典或Series进行分组

传入字典,则可以在分组的同时,分配组名

mapping = {'a': 'red', 'b': 'red', 'c': 'blue',
   ....:            'd': 'blue', 'e': 'red', 'f' : 'orange'}

by_column=people.groupby(mapping,axis=1)
In [62]: by_column.sum()
Out[62]:
            blue       red
Joe     2.640600  0.535645
Steve  -1.027999 -0.109327
Wes     1.114823  1.684028
Jim    -1.004846  2.967557
Travis -0.546900  1.540500

通过函数进行分组

被当作分组键的函数会对所有索引都调用一次

people.groupby(len).sum()

根据索引级别分组

10.2 数据聚合

常见聚合运算

image.png

要使用自定义聚合函数只需将行数传入agg方法即可

grouped.agg(my_fun)

面向列的多函数应用

对于前面表的描述统计方法,可以函数名以字符串的形式传入(支持传入列表)

grouped_pct.agg(['mean','std'])

image.png

这样使得自定义函数可以和自带的聚合函数混合使用
也可由给聚合函数添加名字:传递元组

grouped_pct.agg([('平均值','mean'),('标准差','std')])

更方便的写法

functions=[('平均值','mean'),('标准差','std')]
grouped_pct.agg(functions)

10.3 apply:一般性的“拆分-应用-合并

相比agg,agg只是对每个分组使用聚合运算,而app则是将分组中的每块DataFrame对象进行运算,因此更具一般性。

使用范例:

def top(df,n=5,column='tip_pct'):
    return df.sort_values(by=column)[-5:]
tips.groupby('day').apply(top)

groupby对象的apply方法:
groupby对象的每一块都是一个DataFrame对象,对其用apply就相当于将参数函数应用到每一个DataFrame块,因此要求参数函数也要能返回一个DataFrame对象。

apply和agg方法的区别:
agg方法是对一组数据执行的操作,而apply是对一块数据(DataFrame对象)执行的操作

ps:实际上对groupby对象调用describe方法等价于:

tips.groupby('day').apply(lambda x:x.describe())
image.png

禁止分组键

使用参数:group_keys=Flase即可禁止分组键

tips.groupby('day',group_keys=False).apply(lambda x:x.describe())

分位数和桶分析

按数值区间分类
pd.cut
按个数区间分类
pd.qcut

示例1:对特定的分组填充不同的值

使用groupby+apply+填充函数

示例2: 随机采样和排列

创建一个德州扑克Series对象

suits=['H','S','C','D']
card_val=(list(range(1,11))+[10]*3)*4
base_names=['A']+list(range(2,11))+['J','K','Q']
for suit in suits:
    cards.extend(str(num)+suit for num in base_names)
In [139]: deck.head(10)
Out[139]:
AH      1
2H      2
3H      3
4H      4
5H      5
6H      6
7H      7
8H      8
9H      9
10H    10

使用sample随机选取5张扑克:

deck.sample(5)

从每种花色中随机抽取两张牌
分组标准:卡名的最后一个字母即花色。

def fun(se):
    return se.sample(2)
grouped=deck.groupby([x[-1] for x in deck.index])
grouped.apply(fun)

示例:分组加权平均数和相关系数

分组加权平均数
先分组,再对groupby对象调用average函数(可接收权重参数的mean)即可
分组相关系数
先分组,再对groupby对象调用corrwith

示例3:组级别的线性回归

10.4 透视表和交叉表

df.pivot_table:可以实现和groupby的相同功能,但简化了使用方式。
回到之前的消费的例子

In [254]: df.head(10)
Out[254]:
   total_bill   tip smoker  day    time  size   tip_pct
0       16.99  1.01     No  Sun  Dinner     2  0.059447
1       10.34  1.66     No  Sun  Dinner     3  0.160542
2       21.01  3.50     No  Sun  Dinner     3  0.166587
3       23.68  3.31     No  Sun  Dinner     2  0.139780
4       24.59  3.61     No  Sun  Dinner     4  0.146808
5       25.29  4.71     No  Sun  Dinner     4  0.186240
6        8.77  2.00     No  Sun  Dinner     2  0.228050
7       26.88  3.12     No  Sun  Dinner     4  0.116071
8       15.04  1.96     No  Sun  Dinner     2  0.130319
9       14.78  3.23     No  Sun  Dinner     2  0.218539
In [258]: df.pivot_table(['tip_pct','size'],index=['time','day'],columns='smoker')
Out[258]:
                 size             tip_pct
smoker             No       Yes        No       Yes
time   day
Dinner Fri   2.000000  2.222222  0.139622  0.165347
       Sat   2.555556  2.476190  0.158048  0.147906
       Sun   2.929825  2.578947  0.160113  0.187250
       Thur  2.000000       NaN  0.159744       NaN
Lunch  Fri   3.000000  1.833333  0.187735  0.188937
       Thur  2.500000  2.352941  0.160311  0.163863
image.png

交叉表:crosstab

交叉表(cross-tabulation,简称crosstab)是一种用于计算分组频率的特殊透视表。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,183评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,850评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,766评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,854评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,871评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,457评论 1 311
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,999评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,914评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,465评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,543评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,675评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,354评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,029评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,514评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,616评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,091评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,685评论 2 360

推荐阅读更多精彩内容