Pandas数据分析groupby函数深度总结(2)

本文为系列(2),总结应用函数转换:apply , agg(regate) , transform 以及 filter,代码采用jupyter notebook演示。

应用函数转换:apply , agg(regate) , transform 以及 filter

系列(1)深度讨论了如何对数据进行各种情况分组,本系列讨论在把分组数据合并前,如何对数据进行映射计算处理。

主要为以下四个函数:

  1. apply;
  2. agg(regate);
  3. transform;
  4. filter

通常情况下,第1、2个方法使用的比较频繁,例如

group = df.groupby('GROUP')
group.apply(mean)
group.agg(mean)
group['INTERSTING COLUMN'].apply(mean)
group.agg({'INTERSTING COLUMN':mean})
group.mean()

以上所有的处理都ok,但是apply和agg还是有一些区别的。并且更重要的是,还有很强大的两个函数transform和filter很少被使用。

apply

首先从apply函数开始说起。apply函数沿着DataFrame的某个axis进行映射,即安招columns或者rows。并且apply在除了groupby的条件下,也可以使用,如下所示,apply可以直接应用到整个DataFrame。
输入:

_ = pd.DataFrame(
    np.random.random((2,6)),
    columns=list('ABCDEF')
)
_

输出:


A	B	C	D	E	F
0	0.984852	0.531421	0.119650	0.634738	0.400878	0.611369
1	0.949040	0.387844	0.280624	0.087846	0.722161	0.045949

输入:

_.apply(sum, axis=0) # axis=0 is default, so you can drop that

输出:

A    0.436743
B    1.694425
C    0.759197
D    0.583244
E    1.509123
F    1.501406
dtype: float64

输入:

_.apply(sum, axis=1)

输出:

0    3.376695
1    3.107443
dtype: float64

apply也可以用在groupby的条件下,因为每个group本质上来说就是一个DataFrame的子集,apply默认是按列进行函数映射。
输入:

df.groupby(
    pd.Grouper(key='Date',freq='Y')
)['Sale'].apply(sum)

输出:

Date
2014-12-31    3681
2015-12-31    3800
2016-12-31    3881
2017-12-31    3068
2018-12-31    2478
Freq: A-DEC, Name: Sale, dtype: int64

输入:

df.groupby(
    pd.Grouper(key='Date',freq='Y')
)[['Val','Sale']].apply(sum)

输出:

                 Val	Sale
Date		
2014-12-31	100422394	3681
2015-12-31	101724648	3800
2016-12-31	101789642	3881
2017-12-31	101957784	3068
2018-12-31	100399962	2478

agg

首先我们来看一张agg函数分组应用数学函数进行映射的示意图:
在这里插入图片描述
该图说明在分组应用agg函数后,每个类别都只输出一个最终的映射结果。

例:
输入:

df.groupby('Sales Rep').agg({
    'Order Id':'size',
    'Val':['sum','mean'],
    'Sale':['sum','mean']
})

输出:

                            Order Id	Val	Sale
                    size	sum	   mean	 sum	mean
Sales Rep					
Aaron Hendrickson	292	1550608	5310.301370	46	0.157534
Adam Sawyer	324	1587828	4900.703704	48	0.148148
Adele Kimmel	115	527339	4585.556522	20	0.173913
Adrian Daugherty	369	1841274	4989.902439	51	0.138211
Adrianna Shelton	37	186651	5044.621622	8	0.216216
...	...	...	...	...	...
Willie Lin	44	254128	5775.636364	6	0.136364
Willie Rau	95	434918	4578.084211	19	0.200000
Willie Sanchez	309	1525229	4936.016181	52	0.168285
Yvonne Jones	74	416388	5626.864865	12	0.162162
Yvonne Lindsey	67	324334	4840.805970	18	0.268657
499 rows × 5 columns

我们将字典传递给聚合函数,其中key(例如Order Id, Val, Sale)是列的值,(‘size’, [‘sum’,‘mean’], [‘sum’,‘mean’])是格列需要各自进行的映射。请注意,该函数可以是单个函数或函数列表(其中每个都将应用)。另外,请注意agg可以使用函数名(如字符串)或函数(如Python对象)。
目前支持的自带方法如下:

df.mean() # 返回所有列的均值
df.mean(1) # 返回所有行的均值,下同
df.corr() # 返回列与列之间的相关系数
df.count() # 返回每一列中的非空值的个数
df.max() # 返回每一列的最大值
df.min() # 返回每一列的最小值
df.abs() # 绝对值
df.median() # 返回每一列的中位数
df.std() # 返回每一列的标准差, 贝塞尔校正的样本标准偏差
df.var() # 无偏方差
df.sem() # 平均值的标准误差
df.mode() # 众数
df.prod() # 连乘
df.mad() # 平均绝对偏差
df.cumprod() # 累积连乘,累乘
df.cumsum(axis=0) # 累积连加,累加
df.nunique() # 去重数量,不同值的量
df.idxmax() # 每列最大的值的索引名
df.idxmin() # 最小
df.cummax() # 累积最大值
df.cummin() # 累积最小值
df.skew() # 样本偏度 (第三阶)
df.kurt() # 样本峰度 (第四阶)
df.quantile() # 样本分位数 (不同 % 的值)

也可以使用自定义函数,并且还可以直接在聚合字典中修改列名。
例:
输入:

def cr(x):
    return round(np.mean(x),2)

aggregation = {
    'Potential Sales':('Val','size'),
    'Sales':('Sale','sum'),
    'Conversion Rate':('Sale',cr)
}

df.groupby('Sales Rep').agg(**aggregation)

输出:

Potential Sales	Sales	Conversion Rate
Sales Rep			
Aaron Hendrickson	292	46	0.16
Adam Sawyer	324	48	0.15
Adele Kimmel	115	20	0.17
Adrian Daugherty	369	51	0.14
Adrianna Shelton	37	8	0.22
...	...	...	...
Willie Lin	44	6	0.14
Willie Rau	95	19	0.20
Willie Sanchez	309	52	0.17
Yvonne Jones	74	12	0.16
Yvonne Lindsey	67	18	0.27
499 rows × 3 columns

结果与下面相同,但比以下方法更有效:
输入:

def cr(x):
    return round(np.mean(x),2)

_ = df.groupby('Sales Rep').agg({
    'Val':'size',
    'Sale':['sum',cr]
})

_.columns = ['Potential Sales','Sales','Conversion Rate']
_

输出:


Potential Sales	Sales	Conversion Rate
Sales Rep			
Aaron Hendrickson	292	46	0.16
Adam Sawyer	324	48	0.15
Adele Kimmel	115	20	0.17
Adrian Daugherty	369	51	0.14
Adrianna Shelton	37	8	0.22
...	...	...	...
Willie Lin	44	6	0.14
Willie Rau	95	19	0.20
Willie Sanchez	309	52	0.17
Yvonne Jones	74	12	0.16
Yvonne Lindsey	67	18	0.27
499 rows × 3 columns

更高阶的agg使用示例:
输入:
```python
# Grouping by 3 evenly cut "Order Value" buckets
df.groupby(
    pd.qcut(df['Val'],3,['low','mid','high'])
).agg({'Val':['mean','std'],'Sale':['sum','size']})

输出:

                         Val	   Sale
         mean        std	sum	    size
Val				
low	1759.218063	955.198008	5653	33339
mid	5078.456234	957.488032	5577	33336
high	8352.541395	945.261300	5678	33325

输入:

# Grouping by cutom "Order Value" buckets
df.groupby(
    pd.cut(df['Val'],[0,3000,5000,7000,10000])
).agg({'Val':['mean','std'],'Sale':['sum','size']})

输出:

                                  Val	    Sale
                 mean	    std	    sum	    size
Val				
(0, 3000]	1555.837474	839.194392	4913	29220
(3000, 5000]	3998.367283	579.842580	3389	19892
(5000, 7000]	5999.759369	582.543076	3399	20359
(7000, 10000]	8488.592355	868.442376	5207	30529

在高阶的还有:
输入:

df.groupby(
    pd.cut(df['Val'],[0,5000,10000],labels=['low','high'])
).agg(
    **{'Conversion Rate':pd.NamedAgg(column='Sale',aggfunc=lambda x: sum(x)/len(x))}
)

输出:

Conversion Rate
Val	
low	    0.169042
high	0.169116

输入:

# grouping by year and a cut oder value column
df.groupby(
    [pd.Grouper(key='Date',freq='Y'),pd.qcut(df['Val'],3,['low','mid','high'])]
).agg(
    **{'Conversion Rate':pd.NamedAgg(column='Sale',aggfunc=lambda x: sum(x)/len(x))}
).unstack()

输出:

                        Conversion    Rate
         Val	low	       mid	      high
Date			
2014-12-31	0.185964	0.185123	0.182244
2015-12-31	0.192487	0.184618	0.191403
2016-12-31	0.193346	0.189693	0.195297
2017-12-31	0.151350	0.151591	0.155423
2018-12-31	0.123520	0.124867	0.127470

transform

在这里插入图片描述
agg函数返回的是每个组的一个输出,而transform返回的是与列长度相同的一一映射输出,典型示例如下:
输入:

df.groupby('Sales Rep')['Val'].transform(lambda x: x/sum(x))

输出:

0        0.004991
1        0.005693
2        0.003976
3        0.000799
4        0.003300
           ...   
99995    0.012088
99996    0.000711
99997    0.013741
99998    0.010695
99999    0.001533
Name: Val, Length: 100000, dtype: float64

与agg不同的是,transform通常是为了在原始数据中生成新的一列。

df['%'] = df.groupby('Sales Rep')['Val'].transform(
  lambda x: x/sum(x)
)

filter

在这里插入图片描述
如图所示为分组后的filter处理过程,可以看到filter主要是为了过滤不符合条件的分组,把复合条件的分组留下。
示例:
输入:

df.groupby('Sales Rep').filter(
  lambda x: (x['Val'] * x['Sale']).sum() > 200000
)

输出:

Order Id	Company Id	Company Name	Date	Val	Sale	Sales Rep	Sales Rep Id
0	HZSXLI1IS9RGABZW	D0AUXPP07H6AVSGD	Melancholy Social-Role	2017-10-13	6952	0	William Taylor	ZTZA0ZLYZR85PTUJ
1	582WPS3OW8T6YT0R	D0AUXPP07H6AVSGD	Melancholy Social-Role	2017-09-02	7930	0	William Taylor	ZTZA0ZLYZR85PTUJ
2	KRF65MQZBOYG4Y9T	D0AUXPP07H6AVSGD	Melancholy Social-Role	2016-12-21	5538	1	William Taylor	ZTZA0ZLYZR85PTUJ
3	N3EDZ5V1WGSWW828	D0AUXPP07H6AVSGD	Melancholy Social-Role	2018-06-03	1113	0	William Taylor	ZTZA0ZLYZR85PTUJ
4	QXBC8COXEXGFSPLP	D0AUXPP07H6AVSGD	Melancholy Social-Role	2014-07-26	4596	0	William Taylor	ZTZA0ZLYZR85PTUJ
...	...	...	...	...	...	...	...	...
99129	GVRNNUAPFE0IUBHW	BLURX3WQK51RI6P7	Baptismal Tensions	2014-01-11	2677	0	Richard Dugas	Y43HS5H6PAP34ER5
99130	GX4S2LXPU3VZOS4Z	BLURX3WQK51RI6P7	Baptismal Tensions	2018-05-12	6877	0	Richard Dugas	Y43HS5H6PAP34ER5
99131	FU4ELGDQEGSGOHFZ	BLURX3WQK51RI6P7	Baptismal Tensions	2014-10-16	9189	0	Richard Dugas	Y43HS5H6PAP34ER5
99132	S553MU5UDAUID8TG	BLURX3WQK51RI6P7	Baptismal Tensions	2016-05-01	2013	0	Richard Dugas	Y43HS5H6PAP34ER5
99133	CV3ANPEYZAGVDGGT	BLURX3WQK51RI6P7	Baptismal Tensions	2016-06-20	4543	0	Richard Dugas	Y43HS5H6PAP34ER5
68313 rows × 8 columns

示例:
输入:

# Let's add this for verification
df['cr'] = df.groupby('Sales Rep')['Sale'].transform('mean')

df.groupby('Sales Rep').filter(lambda x: x['Sale'].mean() > .3)

输出:

Order Id	Company Id	Company Name	Date	Val	Sale	Sales Rep	Sales Rep Id	cr
3897	4MWBSVADRWSNLBA0	4D9PJORE7YYNDV2E	Qualitative Asimov'S	2014-03-17	2637	0	Teddy Cook	36I1D97CG4V8ATKV	0.315789
3898	8C13U50FF5ZKU1TJ	4D9PJORE7YYNDV2E	Qualitative Asimov'S	2015-10-26	9495	0	Teddy Cook	36I1D97CG4V8ATKV	0.315789
3899	D6Y3HVKNT480ADL1	4D9PJORE7YYNDV2E	Qualitative Asimov'S	2017-12-09	9156	0	Teddy Cook	36I1D97CG4V8ATKV	0.315789
3900	JXO5XMLWEDZKLGCG	4D9PJORE7YYNDV2E	Qualitative Asimov'S	2016-07-05	1219	0	Teddy Cook	36I1D97CG4V8ATKV	0.315789
3901	37PVLZLXMXRCZLNK	4D9PJORE7YYNDV2E	Qualitative Asimov'S	2018-03-07	4374	0	Teddy Cook	36I1D97CG4V8ATKV	0.315789
...	...	...	...	...	...	...	...	...	...
94627	H72B7571AMUFAH2A	JQ7DP9EX0HY1OKRU	Road-Shy Small-Town	2015-08-07	2764	0	Jennifer Peck	UTJ4LM946FZQSCN1	0.304348
94628	SFQVIH3PNXVLR7PM	JQ7DP9EX0HY1OKRU	Road-Shy Small-Town	2014-11-28	1008	0	Jennifer Peck	UTJ4LM946FZQSCN1	0.304348
94629	B4GFG6BPT1HOHJOU	JQ7DP9EX0HY1OKRU	Road-Shy Small-Town	2018-06-27	8999	0	Jennifer Peck	UTJ4LM946FZQSCN1	0.304348
94630	7ZO3XQ1C3U3BOM6T	JQ7DP9EX0HY1OKRU	Road-Shy Small-Town	2015-02-19	2079	0	Jennifer Peck	UTJ4LM946FZQSCN1	0.304348
94631	CN1LKURFMOKKK15D	JQ7DP9EX0HY1OKRU	Road-Shy Small-Town	2018-09-06	1681	0	Jennifer Peck	UTJ4LM946FZQSCN1	0.304348
366 rows × 9 columns
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值