一、分组 (groupby)
(一) groupby 对象
1、分组运算过程:split->apply->combine
拆分:根据提供的一个或多个键拆分成多组
应用:每个分组运行的计算规则
合并:把每个分组的计算结果合并起来
2、分组操作:
groupby()进行分组,GroupBy对象没有进行实际运算,只是包含分组的中间数据
数据如下:
- 按列分组 obj.groupby(‘label’)
此时label为分组后数据的索引
grouped =book_data.groupby('original_publication_year')
# 此时的grouped 是一个groupby对象,实际上还没进行任何计算,只是含有一些关于分组键的中间数据
grouped
out:
<pandas.core.groupby.groupby.DataFrameGroupBy object at 0x000001D92551A400>
- 按列多重分组 obj.groupby([‘label1’,‘label2’])
此时label1、label2为分组后数据的多层索引
grouped =book_data.groupby(['original_publication_year','authors'])
- 指定要进行分组数据 obj[‘columns’].groupby(‘label’)
不一定每列数据都是需要的,可以选出满足分组需求的列数据
name = ['original_publication_year','language_code','books_count','ratings_count']
# 分组的列一定要包含在name当中
grouped =book_data[name].groupby(['original_publication_year'])
2、分组运算:
对GroupBy对象进行分组运算/多重分组运算
- 计算分组平均值(调用groupby的mean方法)
按单列分组
grouped =book_data.groupby('original_publication_year')
# 计算分组平均值,并查看前五行数据
grouped.mean().head()
out:
可以看出结果中并没有authors列,因为它不是数值类型的数据。
按多列分组:
grouped =book_data.groupby(['original_publication_year','authors'])
# 查看分组后各数值类型列的均值,并查看后20条数据
grouped.mean().tail(20)
可以看出先按original_publication_year分组,再按authors分组,且这两个分组字段为分组后数据的索引。
- 计算每个分组的最大数(调用groupby的max方法)
grouped.max().head()
- 计算每个分组的元素个数(调用groupby的size方法)
grouped.size().head()
(二) 对分组进行迭代
groupby对象支持迭代,可产生一组二元数组(由分组名和数据块组成)
- 单键的情况下
name = ['original_publication_year','language_code','books_count','ratings_count']
grouped =book_data[name].groupby(['original_publication_year'])
# 对分组数据进行遍历
for name,group in book_data.groupby('original_publication_year'):
print(name)
print(group)
out:
如图:1962、1963为分组名,对应的下面的数据为数据块
- 多重键的情况下
元组的第一个元素将会是由键值组成的元组
name = ['original_publication_year','language_code','books_count','ratings_count']
grouped =book_data[name].groupby(['original_publication_year','language_code'])
for (name1,name2),group in grouped:
print(name1,name2)
print(group)
out:
(三)GroupBy对象可以转换成列表或字典
1、GroupBy对象转换list
print(list(grouped))
列表的每个元素为一个分组数据,分组数据以元组形式存储
2、GroupBy对象转换dict
print(dict(list(grouped)))
(四)按数据类型分组
显示DataFrame各列的数据类型
book_data1.dtypes
根据数据类型进行分组
grouped1 = book_data1.groupby(book_data1.dtypes,axis = 1)
grouped1.describe()
(五)通过字典或Series进行分组
1、通过Series分组
# 通过Series分组
data = np.random.randint(0,20,(5,4))
data = pd.DataFrame(data,index=['a','b','c','d','e'],columns=[1,2,3,4])
data
2、通过字典分组
# 通过字典分组(知道每一列对应的分组关系)
mapping={1:'red',2:'blue',3:'red',4:'blue'}
grouped2 = data.groupby(mapping,axis = 1)
grouped2.describe()
grouped2.sum()
(六)通过函数进行分组
任何被当作分组键的函数都会在各索引值上被调用一次,其返回值被用作分组的名称
数据:
# 根据作者名字的长度进行分组
book_data1.groupby(len).sum().head()
(七)通过索引级别进行分组
层次化索引数据集最方便的地方就在于她能根据索引级别进行聚合。要实现该目的,通过level关键字传入接比如编号或名称即可
传入索引编号
# 此处为行索引,如果是列索引,axis=1
book_data1.groupby(level = 1).count()
传入索引名称
book_data1.groupby(level = 'language_code').count()
以上两种写法作用相同,结果如下:
二、聚合 (Aggregation)
数组产生标量值的数据转换过程,如mean()、count()等
常用于对分组后的数据进行计算
1、内置的聚合函数
sum(), mean(), max(), min(), count(), size(), describe()
book_data1.groupby('language_code')['books_count'].min()
2、grouped.agg(func)
func的参数为groupby索引对应的记录
可自定义函数,传入agg方法中
# 自定义函数
def diff(df):
"""
极差
"""
return df.max() - df.min()
# agg传入自定义函数
grouped1.agg(diff)
- 多函数应用
# 使用二元元组作为返回后的数据列名
grouped1.agg([('极差',diff),('最大值','max'),('最小值','min')])
- 对不同的列分别作用不同的聚合函数(使用字典)
mapping = {'books_count':['mean','median'],'ratings_count':'max'}
grouped1.agg(mapping)
三、数据的分组级运算和转换
聚合只是分组运算的其中一种,它是数据转换的一个特例。
数据转换接受将一维数组简化为标量。
transform和apply方法能够执行更多其他的分组运算。
transform的计算结果和原始数据的形状保持一致(返回与数据同样长度的行)
grouped2 =book_data2[['language_code','average_rating','ratings_count']].groupby('language_code').transform(max)
返回的行数据长度与元数据长度一致
func函数也可以在各分组上分别调用,最后结果通过pd.concat组装到一起(数据合并)
可以按照行、列进行聚合
1. 产生层级索引:外层索引是分组名,内层索引是df_obj的行索引
def top_n(df, n=1,column ='average_rating' ):
"""
返回每个分组按 column 的 top n 数据
"""
return df.sort_values(by=column, ascending=False)[:n]
book_data3.groupby('language_code').apply(top_n)
外层language_code是分组名
2、 禁止层级索引, group_keys=False
# 禁止层级索引, group_keys=False
grouped3 = book_data3.groupby('language_code' ,group_keys=False).apply(top_n, n=2, column='ratings_count')
grouped3.head()
按列计算:
book_data3[['average_rating','ratings_count']].apply(np.sum,axis = 1)