Pandas分组聚合 - 基础
数据分析阶段:
数据规整(清洗)阶段后,下一阶段就是 分组聚合
对数据集分组并对各组应用一个函数是数据分析中的重要环节
一般将数据准备好后,首先就是计算分组统计
sql能够方便的连接、过滤、转换和聚合数据,但sql能执行的分组运算种类有限,Pandas则强大灵活的多
In [1]:
import numpy as np
import pandas as pd
某班若干为同学的 三次、语文、数学、英语 考试成绩
In [2]:
df = pd.DataFrame({
'name': ['张三','李四','王五','李四','王五','王五','赵六'],
'chinese': [18, 53, 67, 63, 39, 70, 94],
'math': [82, 63, 41, 59, 46, 39, 58],
'english': [68, 52, 90, 86, 60, 98, 64],
'test': ['一','一','一','二','二','三','一']
})
df
Out[2]:
name | chinese | math | english | test | |
---|---|---|---|---|---|
0 | 张三 | 18 | 82 | 68 | 一 |
1 | 李四 | 53 | 63 | 52 | 一 |
2 | 王五 | 67 | 41 | 90 | 一 |
3 | 李四 | 63 | 59 | 86 | 二 |
4 | 王五 | 39 | 46 | 60 | 二 |
5 | 王五 | 70 | 39 | 98 | 三 |
6 | 赵六 | 94 | 58 | 64 | 一 |
In [3]:
df.index
Out[3]:
RangeIndex(start=0, stop=7, step=1)
In [4]:
df.columns
Out[4]:
Index(['name', 'chinese', 'math', 'english', 'test'], dtype='object')
数据聚合
一般指应用某些方法(自定义的聚合函数或系统自带Pandas的统计方法等)给数据降维
In [5]:
df
Out[5]:
name | chinese | math | english | test | |
---|---|---|---|---|---|
0 | 张三 | 18 | 82 | 68 | 一 |
1 | 李四 | 53 | 63 | 52 | 一 |
2 | 王五 | 67 | 41 | 90 | 一 |
3 | 李四 | 63 | 59 | 86 | 二 |
4 | 王五 | 39 | 46 | 60 | 二 |
5 | 王五 | 70 | 39 | 98 | 三 |
6 | 赵六 | 94 | 58 | 64 | 一 |
In [6]:
df.mean() # 平均值
Out[6]:
chinese 57.714286
math 55.428571
english 74.000000
dtype: float64
In [7]:
type(df.mean())
Out[7]:
pandas.core.series.Series
In [8]:
df.sum() # 求和,聚合,降维
Out[8]:
name 张三李四王五李四王五王五赵六
chinese 404
math 388
english 518
test 一一一二二三一
dtype: object
In [9]:
df.sum(axis=1)
Out[9]:
0 168
1 168
2 198
3 208
4 145
5 207
6 216
dtype: int64
In [13]:
18 + 82 + 68
Out[13]:
168
In [14]:
df.count()
df.count(axis=1)
# 计数最常用的方法是.size()
Out[14]:
0 5
1 5
2 5
3 5
4 5
5 5
6 5
dtype: int64
In [15]:
df.describe() # describe,也可以用在这里,但它并非聚合运算(但经常当成聚合运算使用)
Out[15]:
chinese | math | english | |
---|---|---|---|
count | 7.000000 | 7.000000 | 7.000000 |
mean | 57.714286 | 55.428571 | 74.000000 |
std | 24.260491 | 14.998413 | 17.281975 |
min | 18.000000 | 39.000000 | 52.000000 |
25% | 46.000000 | 43.500000 | 62.000000 |
50% | 63.000000 | 58.000000 | 68.000000 |
75% | 68.500000 | 61.000000 | 88.000000 |
max | 94.000000 | 82.000000 | 98.000000 |
数据分组
分组聚合:groupby(),一般指以下一个或多个操作步骤的集合
Splitting 分组
Applying 每个分组应用函数
Combining 合并
In [16]:
df
Out[16]:
name | chinese | math | english | test | |
---|---|---|---|---|---|
0 | 张三 | 18 | 82 | 68 | 一 |
1 | 李四 | 53 | 63 | 52 | 一 |
2 | 王五 | 67 | 41 | 90 | 一 |
3 | 李四 | 63 | 59 | 86 | 二 |
4 | 王五 | 39 | 46 | 60 | 二 |
5 | 王五 | 70 | 39 | 98 | 三 |
6 | 赵六 | 94 | 58 | 64 | 一 |
In [18]:
# 一般统计指标,聚合运算不能体现表格的进一步的信息
df.mean()
Out[18]:
chinese 57.714286
math 55.428571
english 74.000000
dtype: float64
In [19]:
# 分组
df.groupby('name')
Out[19]:
基础,重要
In [20]:
df
Out[20]:
name | chinese | math | english | test | |
---|---|---|---|---|---|
0 | 张三 | 18 | 82 | 68 | 一 |
1 | 李四 | 53 | 63 | 52 | 一 |
2 | 王五 | 67 | 41 | 90 | 一 |
3 | 李四 | 63 | 59 | 86 | 二 |
4 | 王五 | 39 | 46 | 60 | 二 |
5 | 王五 | 70 | 39 | 98 | 三 |
6 | 赵六 | 94 | 58 | 64 | 一 |
最常用的聚合函数:
- 平均值:.mean() (透视表)
- 个数:.size() (交叉表)
求每位同学、每科成绩的平均分
In [25]:
# 先分组,再聚合
x = df.groupby('name').mean() # 平均值
x
Out[25]:
chinese | math | english | |
---|---|---|---|
name | |||
张三 | 18.000000 | 82.0 | 68.000000 |
李四 | 58.000000 | 61.0 | 69.000000 |
王五 | 58.666667 | 42.0 | 82.666667 |
赵六 | 94.000000 | 58.0 | 64.000000 |
In [22]:
# 王五的语文成绩
(67+39+70)/3
Out[22]:
58.666666666666664
In [26]:
type(x)
Out[26]:
pandas.core.frame.DataFrame
In [28]:
x.loc[['张三', '王五'], 'chinese']
Out[28]:
name
张三 18.000000
王五 58.666667
Name: chinese, dtype: float64
求每位同学的考试次数
In [23]:
df.groupby('name').size() # 分组数据出现的行数
Out[23]:
name
张三 1
李四 2
王五 3
赵六 1
dtype: int64
In [29]:
# 分组数据在每一列出现的行数,因为重复所以不常用
df.groupby('name').count()
Out[29]:
chinese | math | english | test | |
---|---|---|---|---|
name | ||||
张三 | 1 | 1 | 1 | 1 |
李四 | 2 | 2 | 2 | 2 |
王五 | 3 | 3 | 3 | 3 |
赵六 | 1 | 1 | 1 | 1 |
将分组传给变量
In [30]:
classGroup = df.groupby('name')
classGroup
Out[30]:
In [34]:
classGroup.mean() # 最常用
classGroup.size() # 最常用
classGroup.sum()
Out[34]:
chinese | math | english | |
---|---|---|---|
name | |||
张三 | 18 | 82 | 68 |
李四 | 116 | 122 | 138 |
王五 | 176 | 126 | 248 |
赵六 | 94 | 58 | 64 |
如果不想使用分组列作为索引,设置参数as_index=False
In [35]:
df.groupby('name', as_index=False).mean()
Out[35]:
name | chinese | math | english | |
---|---|---|---|---|
0 | 张三 | 18.000000 | 82.0 | 68.000000 |
1 | 李四 | 58.000000 | 61.0 | 69.000000 |
2 | 王五 | 58.666667 | 42.0 | 82.666667 |
3 | 赵六 | 94.000000 | 58.0 | 64.000000 |
上面是以单列为基准分组,聚合单列
下面是:
- 多列分组
- 多列聚合
同时以多列为基准分组
多列分组
In [37]:
df
Out[37]:
name | chinese | math | english | test | |
---|---|---|---|---|---|
0 | 张三 | 18 | 82 | 68 | 一 |
1 | 李四 | 53 | 63 | 52 | 一 |
2 | 王五 | 67 | 41 | 90 | 一 |
3 | 李四 | 63 | 59 | 86 | 二 |
4 | 王五 | 39 | 46 | 60 | 二 |
5 | 王五 | 70 | 39 | 98 | 三 |
6 | 赵六 | 94 | 58 | 64 | 一 |
In [36]:
df.groupby('name').mean()
Out[36]:
chinese | math | english | |
---|---|---|---|
name | |||
张三 | 18.000000 | 82.0 | 68.000000 |
李四 | 58.000000 | 61.0 | 69.000000 |
王五 | 58.666667 | 42.0 | 82.666667 |
赵六 | 94.000000 | 58.0 | 64.000000 |
In [40]:
x2 = df.groupby(['name', 'test']).mean()
x2
Out[40]:
In [43]:
x2.columns
x2.index
Out[43]:
MultiIndex(levels=[['张三', '李四', '王五', '赵六'], ['一', '三', '二']],
labels=[[0, 1, 1, 2, 2, 2, 3], [0, 0, 2, 0, 1, 2, 0]],
names=['name', 'test'])
In [39]:
# 给多列做分组,不将分组列作为索引
df.groupby(['test', 'name'], as_index=False).mean()
Out[39]:
test | name | chinese | math | english | |
---|---|---|---|---|---|
0 | 一 | 张三 | 18 | 82 | 68 |
1 | 一 | 李四 | 53 | 63 | 52 |
2 | 一 | 王五 | 67 | 41 | 90 |
3 | 一 | 赵六 | 94 | 58 | 64 |
4 | 三 | 王五 | 70 | 39 | 98 |
5 | 二 | 李四 | 63 | 59 | 86 |
6 | 二 | 王五 | 39 | 46 | 60 |
多列聚合
对于大数据集,很可能只需要对部分列进行聚合
下列三种写法结果一样
- 分组聚合参数,传入标量形式的单个列名,返回Series
- 分组聚合参数,传入列表或数组,返回DataFrame(默认传入所有列)
In [44]:
df
Out[44]:
name | chinese | math | english | test | |
---|---|---|---|---|---|
0 | 张三 | 18 | 82 | 68 | 一 |
1 | 李四 | 53 | 63 | 52 | 一 |
2 | 王五 | 67 | 41 | 90 | 一 |
3 | 李四 | 63 | 59 | 86 | 二 |
4 | 王五 | 39 | 46 | 60 | 二 |
5 | 王五 | 70 | 39 | 98 | 三 |
6 | 赵六 | 94 | 58 | 64 | 一 |
对除分组基准列以外的所有列进行聚合
In [45]:
df.groupby('name').sum()
Out[45]:
chinese | math | english | |
---|---|---|---|
name | |||
张三 | 18 | 82 | 68 |
李四 | 116 | 122 | 138 |
王五 | 176 | 126 | 248 |
赵六 | 94 | 58 | 64 |
分组后,只对 chinese
列进行聚合
In [47]:
# 方法1:对所有列进行聚合后,抽取需要的列
# 效率低(会运算所有列),不推荐
df.groupby('name').sum()['chinese']
Out[47]:
name
张三 18
李四 116
王五 176
赵六 94
Name: chinese, dtype: int64
In [50]:
# 方法2:抽出聚合列,和分组基准列,单独运算
# 效率高,但写着麻烦
df['name']
df['chinese']
# 传入标量或列名,返回Series
df['chinese'].groupby(df['name']).sum()
Out[50]:
name
张三 18
李四 116
王五 176
赵六 94
Name: chinese, dtype: int64
In [52]:
# 方法3:分组后指定某列进行聚合,书写简单,效率高,推荐**********************
# 是上面写法的简写(语法糖)
df.groupby('name')['chinese'].sum()
Out[52]:
name
张三 18
李四 116
王五 176
赵六 94
Name: chinese, dtype: int64
多列聚合
In [54]:
df.groupby('name')['chinese', 'math'].sum()
Out[54]:
chinese | math | |
---|---|---|
name | ||
张三 | 18 | 82 |
李四 | 116 | 122 |
王五 | 176 | 126 |
赵六 | 94 | 58 |
聚合列,传入参数不是单值,而是列表或数组,返回DataFrame
In [58]:
df.groupby('name')[['chinese']].mean()
df[['chinese']].groupby(df['name']).mean()
df.groupby('name').mean()[['chinese']]
Out[58]:
chinese | |
---|---|
name | |
张三 | 18.000000 |
李四 | 58.000000 |
王五 | 58.666667 |
赵六 | 94.000000 |