pandas 之分组利器groupby使用注意

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zlb872551601/article/details/84800334

pandas 之分组利器groupby使用注意

部分参考
https://blog.csdn.net/weixin_39750084/article/details/81008259
Pandas中groupby+agg+merge及describe实现各类分组统计及一些实用技巧

https://blog.csdn.net/m0_37870649/article/details/80979809
Pandas分组运算(groupby)修炼
以及
https://blog.csdn.net/flyfoxs/article/details/81346885
在Pandas中如何给多层索引降级

数据挖掘中分组做统计是家常便饭,

如果是分组字段是一个,被分组统计字段是多个,可按这个模板来:

get_count = lambda x:x.count(if x>10)
 data=data[col1].groupby(data[col2]).agg({'maxValue':'max','minValue':'min','filterCount':get_count}).reset_index()
 add_suffix(suffix),add_prefix(prefix)添加前缀和后缀

根据代码看目的很容易,
即根据col2进行分组后,col1的组内最大值、最小值以及组内大于10的值的个数,加上col2这一列,共同构成一个新的DataFrame对象。

Pandas中groupby+agg+merge及describe实现各类分组统计及一些实用技巧
中讲到了为什么这么写最好,大致是三点:

  1. 为什么要用agg:
    如果你不用agg,也可以实现同样的功能,因为Pandas自带了max、min、mean这些聚合函数,用法如下:
data = data[col1].groupby(data[col2]).max()
data = data[col1].groupby(data[col2]).mean()
data = data[col1].groupby(data[col2]).min()

但是这样既笨重,又没办法通过自定义的聚合函数来实现自定义统计,而用agg可以传入自定义的聚合函数。

  1. 为什么agg里面要放字典
    agg里面可以不传字典,但是新生成的列是不能直接生成你想要的列名的。如果你想要定义列名,那你得这么做:
#先初始化列为1,再给这一列传入统计后的值
data['max'] = 1
data['max'] = data[col1].groupby(data[col2]).agg('max').reset_index()
print(data)
add_prefix()

用这种方法,如果同时实现最大值、最小值、均值、计数等参数统计的话,需要写八行代码,而在agg中传入字典参数,同时定义列名和所用的聚合函数,只需要一列就能完成了,甚好。

  1. 为什么要写reset_index

这是因为 比如groupby 用户字段,那么 用户字段会默认认定为是index,这并不符合预期,因为往往用户字段应该还原为普通列字段,方便后面和其他含用户字段的表的join或merge

如果是分组字段是多个,被分组统计字段是一个(或多个)时,用上面的模板好像有点问题:
要用到unstack()

比如

	import pandas as pd
	import numpy as np
	df=pd.DataFrame({'uid':[1001,1001,1002,1003,1003,1003],'tran_type':[0,1,0,1,0,1],'amount':[1,2,3,4,np.NaN,5]})
	
	uid	tran_type	amount
	0	1001	0	1.0
	1	1001	1	2.0
	2	1002	0	3.0
	3	1003	1	4.0
	4	1003	0	NaN
	5	1003	1	5.0
	
	df.groupby(['uid','tran_type'])['amount'].mean()
	
	uid   tran_type
	1001  0            1.0
	      1            2.0
	1002  0            3.0
	1003  0            NaN
	      1            4.5
	Name: amount, dtype: float64
	
	df.groupby(['uid','tran_type'])['amount'].mean().unstack()
	tran_type	0	1
	uid		
	1001	1.0	    2.0
	1002	3.0	    NaN
	1003	NaN    4.5
	df=df.groupby(['uid','tran_type'])['amount'].mean().unstack()
	df.columns=['tran_type_0','tran_type_1']
	df.reset_index()
	
		uid	tran_type_0	tran_type_1
	0	1001	1.0	2.0
	1	1002	3.0	NaN
	2	1003	NaN	4.5

这样的数据差不多是我们想要的了
但是总感觉有点麻烦,
能不能用agg的方法,试了一下

df=pd.DataFrame({'uid':[1001,1001,1002,1003,1003,1003],'tran_type':[0,1,0,1,0,1],'amount':[1,2,3,4,np.NaN,5]})
   uid	tran_type	amount
0	1001	0		1.0
1	1001	1		2.0
2	1002	0		3.0
3	1003	1		4.0
4	1003	0		NaN
5	1003	1		5.0
df.groupby(['uid','tran_type'])['amount'].agg({'mean'}).unstack()
			mean
tran_type	0     	1
uid		
1001	   1.0      2.0
1002	   3.0     NaN
1003	  NaN	4.5
牵扯到了多级索引了

如何转化为大致 
   	uid	tran_type_0	tran_type_1
   0	1001	1.0	        2.0
   1	1002	3.0	        NaN
   2	1003	NaN	4.5
   的样子呢

https://blog.csdn.net/flyfoxs/article/details/81346885
在Pandas中如何给多层索引降级 给出了骚操作的写法:

df=df[['uid','amount']].groupby(['uid']).agg({'mean','min'})
		amount
	mean	min
uid		
1001	1.5	1.0
1002	3.0	3.0
1003	4.5	4.0
可读性还好,但是这没办法和后面的含有uid的表join或merge吧
因为是多级索引,要是能降级就好了,
df.columns
MultiIndex(levels=[['amount'], ['mean', 'min']],
           labels=[[0, 0], [0, 1]])
一种想法是直接去掉一级就好了
#直接去掉一层索引,df.columns = df.columns.droplevel(0),这是鸵鸟策略吧
#df.columns=['uid','amount_mean','amount_min']
#第二种想法手动去写列名,是不是显得不够专业啊,下面大神给出的# 把2层合并到一层的 骚写法,
df.columns = ["_".join(x) for x in df.columns.ravel()]
df.reset_index()
uid	amount_mean	amount_min
0	1001	1.5	1.0
1	1002	3.0	3.0
2	1003	4.5	4.0
这样就是我们想要的数据了

再次回到我们开始提出的问题,能不能用agg的方法对groupby多个字段,
同样用到上面的对多级索引降级的方式就可以很好解决 问题了

df=df.groupby(['uid','tran_type'])['amount'].agg({'mean'}).add_prefix('amount_').unstack()
		amount_mean
tran_type	0	1
uid		
1001	 1.0	     2.0
1002	 3.0	     NaN
1003	 NaN     4.5
使用层次索引合并降级
df.columns = [x[0]+"_"+str(x[1]) for x in df.columns.ravel()]
#这里因为0是数值型,直接和字符串amount_mean不能用"_".join(x) 方式连接
df.columns
df.reset_index()
	uid	amount_mean_0	amount_mean_1
0	1001	1.0	                 2.0
1	1002	3.0	                NaN
2	1003	NaN	          4.5

这正是我们想要的

和pandas.groupby常一起用的还有transform函数和describe函数,cut函数,
以及计数的size()函数(计np.NaN)和count()函数(不计np.NaN)

describe函数比较简单易懂,常见统计量的summary
transform函数则在于,在原df的索引index不变下方便的在原df中增加groupby之后的聚合结果

前面进行聚合运算的时候,得到的结果是一个以分组名为 index 的结果对象。如果我们想使用原数组的 index 的话,就需要进行 merge 转换。transform(func, args, *kwargs) 方法简化了这个过程,它会把 func 参数应用到所有分组,然后把结果放置到原数组的 index 上(如果结果是一个标量,就进行广播):即transform隐式地帮我们完成了一次merge操作,

 df['count_B']=df.groupby(['group1', 'group2'])['B'].transform('count')

上面运算的结果分析: {‘group1’:’A’, ‘group2’:’C’}的组合共出现3次,即index为0,1,2。对应”B”列的值分别是”one”,”NaN”,”NaN”,由于count()计数时不包括Nan值,因此{‘group1’:’A’, ‘group2’:’C’}的count计数值为1。
transform()方法会将该计数值在dataframe中所有涉及的rows都显示出来(我理解应该就进行广播)

对连续数值变化的列做分组,会用到cut函数,cut函数中需自定义bins的范围

聚合方法size()和count()
size跟count的区别: size计数时包含NaN值,而count不包含NaN值

浅红色文字:浅红色文字:

深红色文字:深红色文字

浅绿色文字:浅绿色文字

深绿色文字:深绿色文字

浅蓝色文字:浅蓝色文字

深蓝色文字:深蓝色文字

浅黄色文字:浅黄色文字

深黄色文字:深黄色文字

浅青色文字:浅青色文字

深青色文字:深青色文字

浅紫色文字:浅紫色文字

深紫色文字:深紫色文字

猜你喜欢

转载自blog.csdn.net/zlb872551601/article/details/84800334
今日推荐