Python数据聚合和分组运算(1)-GroupByMechanics
前⾔
Python的pandas包提供的数据聚合与分组运算功能很强⼤,也很灵活。这本书第9章详细的介绍了这⽅⾯的⽤法,但是有些细节不常⽤就容易忘记,遂打算把书中这部分内容总结在博客⾥,以便复习查看。根据书中的章节,这部分知识包括以下四部分:
1.GroupBy Mechanics(groupby技术)
2.Data Aggregation(数据聚合)
3.Group-wise Operation and Transformation(分组级运算和转换)
4.Pivot Tables and Cross-Tabulation(透视表和交叉表)
本⽂是第⼀部分,介绍groupby技术。
⼀、分组原理
核⼼:
1.不论分组键是数组、列表、字典、Series、函数,只要其与待分组变量的轴长度⼀致都可以传⼊groupby进⾏分组。
2.默认axis=0按⾏分组,可指定axis=1对列分组。
对数据进⾏分组操作的过程可以概括为:split-apply-combine三步:
1.按照键值(key)或者分组变量将数据分组。
2.对于每组应⽤我们的函数,这⼀步⾮常灵活,可以是python⾃带函数,可以是我们⾃⼰编写的函数。
3.将函数计算后的结果聚合。
图1:分组聚合原理(图⽚来⾃《Python for Data Analysis》page 252)
import pandas as pd
import numpy as np
df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two', 'one'],
'data1' : np.random.randn(5),
'data2' : np.random.randn(5)})
我们将key1当做我们的分组键值,对data1进⾏分组,再求每组的均值:
grouped = df['data1'].groupby(df['key1'])
语法很简单,但是这⾥需要注意grouped的数据类型,它不在是⼀个数据框,⽽是⼀个GroupBy对象。
grouped
实际上,在这⼀步,我们并没有进⾏任何计算仅仅是创建⽤key1分组后创建了⼀个GroupBy对象,我们后⾯函数的任何操作都是基于这个对象的。
求均值:
刚刚我们只是⽤了key1进⾏了分组,我们也可以使⽤两个分组变量,并且通过unstack⽅法进⾏结果重塑:
means = df['data1'].groupby([df['key1'], df['key2']]).mean()
means
means.unstack
以上我们的分组变量都是df内部的Series,实际上只要是和key1等长的数组也可以:
states = np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
years = np.array([2005, 2005, 2006, 2005, 2006])
df['data1'].groupby([states, years]).mean()
⼆、对分组进⾏迭代
groupby是什么函数GroupBy对象⽀持迭代操作,会产⽣⼀个由分组变量名和数据块组成的⼆元元组:
for name, group upby('key1'):
print name
print group
如果分组变量有两个:
for (k1,k2), group upby(['key1','key2']):
print k1,k2
print group
我们可以将上⾯的结果转化为list或者dict,来看看结果是什么样的:
upby(['key1','key2']))
看不太清楚,我们来看看这个列表的第⼀个元素:
upby(['key1','key2']))[0]
同样,我们也可以将结果转化为dict(字典):
dict(upby(['key1','key2'])))
dict(upby(['key1','key2'])))[('a','one')]
以上都是基于⾏进⾏分组,因为默认情况下groupby是在axis=0⽅向(⾏⽅向)进⾏分组,我们可以指定axis=1⽅向(列⽅向)进⾏分组:upby(df.dtypes,axis=1)
list(grouped)[0]
dict(list(grouped))
注意,
'''下⾯两段语句功能⼀样'''
upby(df.key1)
三、通过字典进⾏分组
people = pd.DataFrame(np.random.randn(5, 5),
columns=['a', 'b', 'c', 'd', 'e'],
index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'])
people.ix[2:3, ['b', 'c']] = np.nan # 添加缺失值
people
假如,我们想按列进⾏聚合,该怎么操作呢?
我们根据实际情况,对列名建⽴字典,然后将此字典传⼊groupby,切记指定axis=1,因为我们是对列进⾏分组聚合:
mapping = {'a': 'red', 'b': 'red', 'c': 'blue',
'd': 'blue', 'e': 'red', 'f' : 'orange'}
by_upby(mapping,axis=1)
an()
既然我们可以通过传⼊字典来对列进⾏分组,那么肯定也可以通过传⼊Series来对列进⾏分组了(Series中的index就相当字典中的key 嘛):
map_series = pd.Series(mapping)
四、通过函数进⾏分组
刚刚我们分组时利⽤了dict和series建⽴映射,对于⼀些复杂的需求,我们可以直接对groupby函数传递函数名来进⾏分组,以刚才的people 数据为例,如果我们想按⾏分组,分组的key是每个⼈名的字母长度,该怎么做呢?⽐较直接的想法是相对每个名字求长度,建⽴⼀个数组,然后将这个数组传⼊groupby,我们来试验⼀下:
l=[len(x) for x in people.index]
⽅案可⾏,那么有没有更快捷更优美的⽅法呢?当然有啦,我们只需将len这个函数名传给groupby即可:
除了传递函数,我们也可以将函数和dict,series,array⼀起使⽤,毕竟最后都会统统转化为数组:
key_list = ['one', 'one', 'one', 'two', 'two']
五、根据索引级别分组
刚刚我们的数据索引只有⼀级,当数据有多级索引时,可以通过level指定我们想要分组的索引,注意要使⽤axis=1表⽰按列:
columns = pd.MultiIndex.from_arrays([['Asian', 'Asian', 'Asian', 'America', 'America'],
['China','Japan','Singapore','United States','Canada']], names=['continent', 'country'])
hier_df = pd.DataFrame(np.random.randn(4, 5), columns=columns)
hier_df
我们按洲进⾏分组求和:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论