groupby()是pandas库中DataFrame结构的函数,最近在看用Movielens数据集进行关联分析的教程时,发现用到了groupby()函数,觉得该函数功能很强大,经常用在for循环结构中用于提取数据,故对该函数一些常用的方法进行一些记录。
先创建一个DataFrame对象df
import pandas as pd
df=pd.DataFrame({'name':['a','b','c','d','e'],'age':[10,15,20,15,20],'sex':[True,True,False,True,False]})
df
>>> name age sex
0 a 10 True
1 b 15 True
2 c 20 False
3 d 15 True
4 e 20 False
1.数据分组
依据某个columns对整个DataFrame对象分组
df_1=df.groupby(df['sex'])
list(df_1)
>>> [(False, name age sex
2 c 20 False
4 e 23 False),
(True, name age sex
0 a 10 True
1 b 15 True
3 d 17 True)]
依据某个columns对另一个columns数据分组
df_1=df['age'].groupby(df['sex'])
list(df_1)
>>> [(False,
2 20
4 23
Name: age, dtype: int64),
(True, 0 10
1 15
3 17
Name: age, dtype: int64)]
这个过程还有另外一种语法
df_1=df.groupby(df['sex'])['age']
list(df_1)
>>> [(False, 2 20
4 23
Name: age, dtype: int64),
(True, 0 10
1 15
3 17
Name: age, dtype: int64)]
当然,也可以同时对多个columns数据进行分组,以第一种语法方式为例,此时要注意多个columns的书写方式
df_1=df[['age','name']].groupby(df['sex'])
list(df_1)
>>> [(False, age name
2 20 c
4 23 e),
(True, age name
0 10 a
1 15 b
3 17 d)]
也可以依据多个columns对某个columns数据分组,注意这里groupby函数内columns的写法,不能再像上面那样了
df_1=df['name'].groupby([df['sex'],df['age']])
list(df_1)
>>> [((False, 20), 2 c
Name: name, dtype: object),
((False, 23), 4 e
Name: name, dtype: object),
((True, 10), 0 a
Name: name, dtype: object),
((True, 15), 1 b
Name: name, dtype: object),
((True, 17), 3 d
Name: name, dtype: object)]
除了依据DataFrame结构中已有的columns对数据进行分组,还可以通过外部设定的columns对DataFrame数据进行分组
import numpy as np
education=np.array(['mid school','high school','university','high school','university'])
df_1=df.groupby([education])
list(df_1)
>>> [('high school', name age sex
1 b 15 True
3 d 17 True),
('mid school', name age sex
0 a 10 True),
('university', name age sex
2 c 20 False
4 e 23 False)]
通过groupby函数来分组时,还有一些别具创意的分组方式,任何被当做分组键的函数都会在各个索引值上被调用一次,其返回值就会被用作分组名称。例如对于所用的df,给它加上索引值index(国籍),然后依据国家名称英文字符的个数来分组
df.index=['China','Russia','USA','English','Japan']
df.groupby(len).sum()
>>> age sex
3 20 False
5 30 True
6 15 True
7 15 True
可以看到, ‘China’和'Japan'字母长度均为5,故在计算‘age’和'sex'时将其对应的值求和了,'age'不具有求和性质,未参与计算。
2.对分组进行迭代,生成字典
for index,group in df.groupby(df['sex'])['age']:
print(index)
print(group)
>>> False
2 20
4 20
Name: age, dtype: int64
True
0 10
1 15
3 15
Name: age, dtype: int64
在上面的程序中,index的输出为 ['False' , 'True'],group的输出结果为 [ ['20','20'] , ['10','15','15'] ]。一种常见的情况为用index、group的值生成字典。
dic=dict((index,frozenset(group.values))for index,group in df.groupby(df['sex'])['age'])
dic
>>> {False: frozenset({20}), True: frozenset({10, 15})}
在生成字典时,也会有多重键的情况,可以用以下方式
dic=dict(((index_1,index_2),frozenset(group.values))for (index_1,index_2),group in df['age'].groupby([df['sex'],df['age']]))
dic
>>> {(False, 20): frozenset({20}),
(True, 10): frozenset({10}),
(True, 15): frozenset({15})}
也可以用这种更为简洁的方式
dic=dict((index,frozenset(group.values))for index,group in df['age'].groupby([df['sex'],df['age']]))
dic
>>> {(False, 20): frozenset({20}),
(True, 10): frozenset({10}),
(True, 15): frozenset({15})}
还有另一种方式来生成字典
dic=dict( list(df.groupby('sex')))
dic
>>> {False: name age sex
2 c 20 False
4 e 20 False,
True: name age sex
0 a 10 True
1 b 15 True
3 d 15 True}
dic[False]['name']
>>> 2 c
4 e
Name: name, dtype: object
这种对整个df生成字典的方式,字典每个键对应的值仍然为一个DataFrame结构。按照这种方式当然也可以用df中某个columns 生成字典。
3.求和、平均计算
数据处理时经常在groupby之后用到求和、平均计算,所以这里也顺带提一下。
计算平均的过程为
df.groupby('sex')['age'].mean()
>>> sex
False 20.000000
True 13.333333
Name: age, dtype: float64
求和的过程为
df.groupby('sex')['age'].sum()
>>> sex
False 40
True 40
Name: age, dtype: int64
还有一种就是对DataFrame整个结构中各行或各列计算平均或求和,这里先引入pandas中轴(axis)的定义,在DataFrame中有axis=0和axis=1两种情况,axis=0表示遍历所有的行,不能理解为axis=0表示对列的操作,同样的,axis=1表示遍历所有的列。另外,在numpy库中也有关键字axis,且用法与pandas中一致。那么通过使用axis,求和、计算平均的过程可以为
df.sum(axis=1)
>>> 0 11.0
1 16.0
2 20.0
3 16.0
4 20.0
dtype: float64
df.sum(axis=0)
>>> name abcde
age 80
sex 3
dtype: object
df.mean(axis=0)
>>> age 16.0
sex 0.6
dtype: float64