05_Pandas分组聚合
分组
df.groupby()方法可以先按指定字段对DataFrame进行分组,生成一个分组器对象,然后把这个对象的各个字段按一定的聚合方法输出。
groupby()方法最终输出的是一个分组对象,DataFrameGroupBy和SeriesGroupBy(分别是DataFrame和Series应用groupby方法产生的)。分组对象是聚合统计操作的基础。
df.groupby('team')
df.Q1.groupby(df.team)
## 按标签分组
最简单的分组方法是指定DataFrame中的一列,按照这列的去重数据分组。也可以指定多列,按这几个列的排列组合去重进行分组。
grouped = df.groupby('col') #单列
grouped = df.groupby('col',axis='columns') # 按行
grouped = df.groupby(['col1','col2']) # 多列
grouped = df.groupby('team') # 分组
grouped.get_group('D') # 查看D组
## 表达式
通过行和列的表达式,生成—个布尔数据的序列,从而将数据分为True和False两组。
# 索引值是否为偶数,分成两组
df.groupby(lambda x:x%2==0).sum()
df.groupby(df.index%2==0).sum() #同上
# 列名包含Q的分成一组
df.groupby(lambda x:'Q' in x,axis=1).sum()
df.groupby(df.index%2==0) # 按索引奇偶分为True和False两组
df.groupby(df.team.isin(['A','B'])) # 按照A、B、其他团队分组
df.groupby([df.time.date,df.time.hour]) #按照日期和小时分组
函数分组
by参数可以调用一个函数,通过计算返回一个分组依据。
df.groupby(df.time.apply(lambda x:x.year)).count() # 从时间列time中提取年份来分组
# 按姓名首字母为元音、辅音分组
def get_letter_type(letter):
if letter[0].lower() in 'aeiou':
return '元音'
else:
return '辅音'
# 使用函数
df.set_index('name').groupby(get_letter_type).sum()
多种方式混合
分组可以按多个依据,在同一次分组中可以混合使用不同的分组方法
# 按team、姓名首字母是否是元音分组
df.groupby(['team',df.name.apply(get_letter_type)]).sum()
分组器Grouper
Pandas提供了一个分组器pd.Grouper(),它能完成分组工作,还可以服用分组。
# 分组器语法
pandas.Grouper(key=None,level=None,freq=None,axis=0,sort=False)
# 示例
team_grouper = df.groupby(pd.Grouper('team'))
team_grouper.sum()
# 如果是时间,可以60秒分一组
df.groupby(pd.Grouper(key='date',freq='60s'))
# 轴方向
df.groupby(pd.Grouper(key='date',freq='60s',axis=1))
# 按索引
df.groupby(pd.Grouper(level=1)).sum()
# 多列
df.groupby([pd.Grouper(freq='1M',key='date'),'Buyer']).sum()
索引
groupby操作后分组字段会成为索引,如果不想成为索引,可以使用as_index=False进行设置
df.groupby('team',as_index=False).sum()
排序
groupby操作后分组字段会成为索引,数据会对索引排序,如果不想排序,可以指定sort=False。
df.groupby('team',sort=False).sum()
分组对象操作
选择分组
分组对象的groups是一个字典(是Pandas定义的PrettyDict),这个字典包含分组的名称和分组的内容索引列表。可以使用字典的keys()方法取出分组名称
grouped = df.groupby('team')
grouped.groups # 输出一个字典结构
grouped.keys() # dict_keys(['A', 'B', 'C', 'D', 'E'])
多层索引
grouped2 = df.groupby(['team',df.name.str[0]])
# 选择B组、姓名以A开头的数据
grouped2.get_group(('B','A')) # 注意参数个数:元组
grouped.insices 返回一个字典,其键位组名,值为本组索引的array格式,可以实现对单分组数据的选取
grouped.indices # 输出字典结构
grouped.indices['A'] #选择A组
迭代分组
# 迭代
for g in grouped:
print(g) # 迭代元素是一个元组,是由分组名和分组内容组成
for name,grp in grouped:
print(name) # 分组名
print(grp) # 分组数据 dataframe结构
应用函数apply()
分组对象使用apply()调用一个函数,传入的是DataFrame(分组后的数据),返回一个经过函数计算后的DataFrame、Series或者标量,然后再把数据组合。
# 将数据中的所有元素乘以2
df.groupby('team').apply(lambda x:x*2)
# 按分组将一列输出为列表
df.groupby('team').apply(lambda x: x['name'].tolist())
# 查看某个分组
df.groupby('team').apply(lambda x: x['name'].tolist()).A
# 调用函数,实现每组Q1成绩最高的前三个
def first_3(df_,c):
return df_[c].sort_values(asscending=False).head(3)
df.set_index('name').groupby('team').apply(first_3,'Q1')
传入一个Series,映射系列不同的聚合统计算法
df.groupby('team').apply(lambda x:pd.Series(
{
'Q1_sum' : x['Q1'].sum(),
'Q2_max' : x['Q2'].max(),
'Q2_mean' : x['Q2'].mean(),
'Q4_prodsum': (x['Q4']*x['Q4']).sum()
}
))
管道方法pipe()
类似于DataFrame的管道方法,分组对象的管道方法是接收之前的分组对象,将同组的所有数据应用在方法中,最后返回的是经过函数处理过的返回数据格式
# 每组最大值与最小值之和
df.groupby('team').pipe(lambda x:x.max()+x.min())
使用函数,通过计算,最终返回的是一个Series
# 定义了A组合B组平均值的差值
def mean_diff(x):
return x.get_group('A').mean() - x.get_group('B').mean()
# 使用函数
df.groupby('team').pipe(mean_diff)
## 转换方法transform()
transform类似于agg(),与agg不同的是它返回一个与原始数据相同形状的DataFrame,将每个数据原来的值一一替换成统计后的值。
df.groupby('team').transform(np.mean)
使用函数时,分别传入每个分组的子DataFrame的每一个列,经过计算后每列返回一个结果,然后再将每组的这个列所有值都替换为此计算结果,最后以原DataFrame形式显示所有数据。
df.groupby('team').transform(max) # 最大值
df.groupby('team').transform(np.std) # 标准差
# 使用函数,和上一个学生的差值
df.groupby('team').transform(lambda x:x.shift(-1))
也可以用它来进行按组筛选
# Q1成绩大于60的组所有成员
df[df.groupby('team').transform('mean').Q1>60]
## 筛选方法filter()
使用filter()对组作为整体进行筛选,如果满足条件,则整个组会被显示。传入它调用函数中的默认变量为每个分组的DataFrame,经过计算,最终返回一个bool值(不是bool序列),为真的DataFrame会全部显示。
#筛选出所在组总平均分大于51的成员
df.groupby('team').filter(lambda x:x.mean(1).mean()>51)
# Q1成绩至少有大于97的组
df.groupby('team').filter(lambda x:(x['Q1'] > 97).any())
# 所有成员平均成绩大于50的组
df.groupby('team').filter(lambda x:(x.select_dtypes(include='number').mean() >= 50).all())
# Q1所有成员成绩之和超过1060的组
df.groupby('team').filter(lambda g:g.Q1.sum() > 1060)
聚合统计
分组对象如同df.describe(),也支持describe(),用来对总体进行描述
# 描述统计
# df.groupby('team').describe()
# 由于列过多,可以进行转置T
df.groupby('team').describe().T
统计函数
对分组对象直接使用统计函数,对分组内的所有数据进行此计算,最终以DataFrame的形式显示数据
# 计算各组平均数
grouped = df.groupby('team')
grouped.mean()
# 还支持一下常用的统计方法
grouped.describe() # 描述性统计
grouped.sum() # 求和
grouped.count() # 每组数量,不包含缺失值
grouped.max() #求最大值
grouped.min() # 求最小值
grouped.size() # 分组数量
grouped.mean() # 平均值
grouped.median() # 中位数
grouped.std() # 标准差
grouped.var() # 方差
grouped.corr() # 相关系数
grouped.sem() # 标准误差
grouped.prod() # 乘积
grouped.cummax() # 每组的累积最大值
grouped.cumsum() # 累加
grouped.cumsum() # 累加
grouped.mad() #平均绝对偏差
聚合方法agg()
分组对象的方法.aggregate()简写为.agg()。它的作用是将分组后的对象给定统计方法,也支持按字段分别给定不同的统计方法。
# 所有列使用一个计算方法
df.groupby('team').aggregate(sum)
df.groupby('team').agg(sum)
grouped.aggregate(np.size)
grouped['Q1'].agg(np.mean)
一个字段多个统计方法
grouped[['Q1','Q3']].agg([np.mean,np.std])
不同列使用不同计算方法,且一个列使用多个计算方法:
grouped.agg({'Q1':['min','max'],'Q2':['sum']})
统计方法可以使用函数
# 聚合结果使用函数
# lambda/函数,所有方法都可以用
def max_min(x):
return x.max()-x.min()
grouped.Q1.agg(Mean='mean',
Sum='sum',
Diff=lambda x:x.max()-x.min(),
Max_min=max_min)
# 全局应用
grouped.agg(max_min)
其他
### 组内头尾值
grouped.first() # 每组第一个
grouped.last() # 每组最后一个
组内分位数
中位数是分位数的一种特殊情形,为二分位。如果需要看其他指定分位的数据,可以使用.quantile()来实现。
df.groupby('team').median() # 中位数
df.groupby('team').quantile() # 同上
df.groupby('team').quantile(0.5) # 同上
组内差值
和DataFrame的diff()一样,分组对象的diff()方法会在组内进行前后数据的差值计算,并以原DataFrame形状返回数据
df.select_dtypes(include='number').groupby(df.team).diff() # 注意字符串
数据分箱
- pandas.cut:根据指定分界点对连续数据进行分箱处理
- pandas.qcut:根据指定区间数量对连续数据进行等宽分箱处理。所谓等宽,指的是每个区间中的数据量是相同的
定界分箱pd.cut()
pud.cut()可以指定区间将数字进行划分
# 将Q1成绩按60分及以上,60分以下进行分类
pd.cut(df.Q1,bins=[0,60,100])
将分箱结果应用到groupby分组中:
# Series使用
df.Q1.groupby(pd.cut(df.Q1,bins=[0,60,100])).count()
# DataFrame使用
df.groupby(pd.cut(df.Q1,bins=[0,60,100])).count()
其它参数
pd.cut(df.Q1,bins=[0,60,100],labels=False) # 不显示区间,使用数据作为每个箱子的标签(0,1,2,n)
pd.cut(df.Q1,bins=[0,60,100],labels=['及格','不及格']) # 指定签名
pd.cut(df.Q1,bins=[0,60,100],include_lowest=True) # 包含最低部分
pd.cut(df.Q1,bins=[0,89,100],right=False) # 是否是右闭区间[89,100)
等宽分箱pd.qcut()
pd.qcut()可以指定所分区间的数量,Pandas会自动进行分箱
#按Q1成绩分为两组
pd.qcut(df.Q1,q=2)
#应用到分组
df.Q1.groupby(pd.qcut(df.Q1,q=2)).count()
df.groupby(pd.qcut(df.Q1,q=2)).max()
其他参数
pd.qcut(range(5),4)
pd.qcut(range(5),4,labels=False)
# 指定标签名
pd.qcut(range(5),4,labels=['good','medium','bad'])
# 返回箱子标签
pd.qcut(df.Q1,q=2,retbins=True)
# 分箱位小数
pd.qcut(df.Q1,q=2,precision=3)
# 排名分3个层次
pd.qcut(df.Q1.rank(method='first'),3)
原文地址:https://blog.csdn.net/qq_27953479/article/details/143843249
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!