本文是对《利用Python进行数据分析》中关于groupby进行分组聚合和运算的一个回顾性总结,整体而言,在过去的一年的工作中,用到groupby的场景还是蛮多的,尤其是利用它与相关函数的结合能解决非常多场景下的数据分析需求,也非常方便,是个重点。
目录
groupby分组解析
groupby分组依据
groupby 分组依据:整体而言,分组键可以有多种形式,且类型不必相同:列表或数组,其长度与待分组的轴一样;表示DataFrame某个列名的值;字典或Series,给出待分组轴上的值与分组名之间的对应关系;函数,用于处理轴索引或索引中的各个标签。下面逐个讲解记录。
按照列名分组
方式1-df直接以key
实例1:
df = DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two', 'one'],
'data1' : np.random.randn(5),
'data2' : np.random.randn(5)})
print(df.groupby('key1')['data1'].mean()) # 这个同下面等价。相当于先key1分组,然后去其中data1列的值来计算均值。
输出
<pandas.core.groupby.SeriesGroupBy object at 0x7fae8aed8350>
key1
a 0.746672
b -0.537585
Name: data1, dtype: float64
方式2 -选serise按照series
实例2:
# 按key1进行分组,并计算data1列的平均值
grouped=df['data1'].groupby(df['key1']) # 访问data1,并根据分组键(key1的所有值)调用groupby 。
print(grouped)
print(grouped.mean())
输出
key1
a 0.746672
b -0.537585
Name: data1, dtype: float64
按照series分组
这是对于选取series来根据另一个或多个series进行分组
实例
#按照Series分组
means = df['data1'].groupby([df['key1'], df['key2']]).mean()
print(means)
# 上面的分组键均为Series。实际上,分组键可以是任何长度适当的数组 实际也可以穿入将列名当做分组键,但注意data1在后面了
# 注意多个分组键在运算后会形成层次化索引
print(df.groupby(['key1','key2'])['data1'].mean())
print(df.groupby(['key1','key2'])['data1'].mean().index)
输出
key1 key2
a one 0.880536
two 0.478943
b one -0.519439
two -0.555730
Name: data1, dtype: float64
key1 key2
a one 0.880536
two 0.478943
b one -0.519439
two -0.555730
Name: data1, dtype: float64
MultiIndex(levels=[[u'a', u'b'], [u'one', u'two']],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
names=[u'key1', u'key2'])
按数组分组
由series来根据依据的数组进行分组, 实例
# 上面的分组键均为Series。实际上,分组键可以是任何长度适当的数组
states=np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
years = np.array([2005, 2005, 2006, 2005, 2006])
df['data1'].groupby([states,years]).mean()
输出
California 2005 0.478943
2006 -0.519439
Ohio 2005 -0.380219
2006 1.965781
Name: data1, dtype: float64
按字典分组
实例: 假设已知列的分组关系,并希望根据分组计算列的和: 注意此,字典中传的key是对应dataframe中的column
people=DataFrame(np.random.randn(5,5),columns=['a','b','c','d','e'],index=['Joe','Steve','Wes','Jim','Travis'])
# 假设已知列的分组关系,并希望根据分组计算列的和: 注意此,字典中传的key是对应dataframe中的column
mapping={'a':'red','b':'red','c':'blue','d':'blue','e':'red','f':'orange'}
# 将这个分组关系字典传给groupby即可
by_column=people.groupby(mapping,axis=1) # 注意此是对列的分组关系,因此要用axis=1
by_column.sum()
输出
blue red
Joe 0.780548 -3.128892
Steve 0.720225 1.705513
Wes -2.956703 -2.197664
Jim 1.413643 0.743556
Travis -1.647382 -0.902466
按函数分组
函数包括python与pandas自带的函数、自定义函数。一次还可传多个函数组成的list。
#实例1,按pandas自带的函数
grouped2=df.groupby(df.dtypes,axis=0)
print(grouped2)
输出
<pandas.core.groupby.DataFrameGroupBy object at 0x7fae31765e50>
#实例2 ,按python的函数如len 。注意 group by 可以传函数,通过函数进行分组。任何被当做分组键的函数都会在各个索引值index 上被调用一次,其返回值就会被用作分组索引名称,此即len的长度值
people=DataFrame(np.random.randn(5,5),columns=['a','b','c','d','e'],index=['Joe','Steve','Wes','Jim','Travis'])
people.groupby(len).sum() # group by 可以传函数,通过函数进行分组。任何被当做分组键的函数都会在各个索引值index 上被调用一次,其返回值就会被用作分组索引名称,此即len的长度值
输出
a b c d e
3 0.591569 -0.993608 0.798764 -0.791374 2.119639
5 0.886429 -2.001637 -0.371843 1.669025 -0.438570
6 -0.713544 -0.831154 -2.370232 -1.860761 -0.860757
按函数、数组、字典等混合使用也可以。本质上都是根据值的对应去分组
实例: #注意: 对于 groupby , 将函数跟数组、列表、字典、Series 混合使用也不是问题,因为任何东西最终都会被转换为数组
key_list=['one','one','one','two','two']
people.groupby([len,key_list]).min()
输出
a b c d e
3 one -0.539741 -1.296221 0.274992 -1.021228 -0.577087
two 0.124121 0.302614 0.523772 0.000940 1.343810
5 one 0.886429 -2.001637 -0.371843 1.669025 -0.438570
6 two -0.713544 -0.831154 -2.370232 -1.860761 -0.860757
根据层次化索引的级别或者编号
首先,数据是含有层次化索引的df,层次化索引数据集最方便的地方就在于它能够根据索引级别进行聚合。要实现该目的,通过level 关键字传入级别编号或名称 即可。
实例
columns=pd.MultiIndex.from_arrays([['US','US','US','JP','JP'],[1,3,5,1,3]],names=['city','tensor'])
hier_df=DataFrame(np.random.randn(4,5),columns=columns)
print(hier_df)
print(hier_df.columns)
# 注意传入的names里的值
print(hier_df.groupby(level='city',axis=1).count())
输出
city US JP
tensor 1 3 5 1 3
0 0.051316 -1.157719 0.816707 0.433610 1.010737
1 1.824875 -0.997518 0.850591 -0.131578 0.912414
2 0.188211 2.169461 -0.114928 2.003697 0.029610
3 0.795253 0.118110 -0.748532 0.584970 0.152677
MultiIndex(levels=[[u'JP', u'US'], [1, 3, 5]],
labels=[[1, 1, 1, 0, 0], [0, 1, 2, 0, 1]],
names=[u'city', u'tensor'])
city JP US
0 2 3
1 2 3
2 2 3
3 2 3
groupby后的分组对象
groupby 对象支持迭代,可以产生一组二元元组(由分组名和数据块组成)
实例1
for name ,group in df.groupby('key1'):
print(name)
print(group)
输出
a
data1 data2 key1 key2
0 -0.204708 1.393406 a one
1 0.478943 0.092908 a two
4 1.965781 1.246435 a one
b
data1 data2 key1 key2
2 -0.519439 0.281746 b one
3 -0.555730 0.769023 b two
实例2: groupby 后套个list 可以直接转换为字典! 得到的字典的key为groupby对象的值
pieces=dict(list(df.groupby('key1'))) # groupby 后套个list 可以直接转换为字典! 得到的字典的key为groupby对象的值
pieces['b']
输出
data1 data2 key1 key2
2 -0.519439 0.281746 b one
3 -0.555730 0.769023 b two
从groupby后的对象中选取一个或一组列
实例 : 注意 此处同下面的对比,此处传入的是['data2'] ,如果传入的是 列表或数组,如此处,得到的返回的是 已分组的 DataFrame .下面传的是单个值 'data2',则得到返回的是 已分组的 Series
s1=df.groupby(['key1','key2'])[['data2','data1']].mean() # 注意 此处同下面的对比,此处传入的是['data2'] ,如果传入的是 列表或数组,如此处,得到的返回的是 已分组的 DataFrame .下面传的是单个值 'data2',则得到返回的是 已分组的 Series
print(type(s1))
print(s1)
输出
<class 'pandas.core.frame.DataFrame'>
data2 data1
key1 key2
a one 1.319920 0.880536
two 0.092908 0.478943
b one 0.281746 -0.519439
two 0.769023 -0.555730
s2=df.groupby(['key1','key2'])['data2'].mean()
print(type(s2))# 此得到则为series
print(s2)
# print(s2.columns)
print(s2.index)
输出
<class 'pandas.core.series.Series'>
key1 key2
a one 1.319920
two 0.092908
b one 0.281746
two 0.769023
Name: data2, dtype: float64
MultiIndex(levels=[[u'a', u'b'], [u'one', u'two']],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
names=[u'key1', u'key2'])
后续小结将继续围绕groupby 从如下方面进行回顾
利用groupby进行数据聚合
分组级运算和转换
透视表
交叉表
案例
鸣谢与参考:
《利用python进行数据分析》