5.数据分组与聚合
数据分组
1.groupby方法:DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False)
参数名称 | 参数说明 |
---|---|
by | 可以传入函数、字典、Series等,用于分组的依据条件 |
axis | 0或者1,表示操作的轴方向默认按列操作,取1按行操作 |
level | 接收int或者索引名,代表标签所在的级别,默认None |
as_index | 接收boolean,表示聚合后的聚合标签是否以DataFrame的索引输出,默认True |
sort | 接收boolean,对分组依据和分组标签排序,默认True |
group_keys | 接收boolean,表示是否显示分组标签的名称,默认True |
squeeze | 接收Boolean,表示是否在允许情况下对数据进行降维操作,默认False |
参数by,如果传入函数,则对索引进行计算并分组;如果传入字典或者Series,则字典或者Series的值作为分组依据;如果传入Numpy数组,则数据元素作为分组依据;如果传入字符串或者字符串列表,则用这些字符串所代表的字段作为分组依据。
数据分组之后返回的是一个groupby对象,可以调用该对象的方法如size返回一个含有分组大小的Series。
#取df['data1']这一列数据并按df['key1']这一列的数据来分组 分完之后a:3 ,b:2
import numpy as np
import pandas as pd
##groupby()
df = pd.DataFrame({
'key1':['a','a','b','b','a'],
'key2':[1,0,1,1,0],
'data1':np.random.randn(5),
'data2':np.random.randn(5)
})
print(df)
grouped = df['data1'].groupby(df['key1'])
print(grouped.size())
print(grouped.mean())
key1 key2 data1 data2
0 a 1 0.410518 0.204681
1 a 0 -0.558132 -0.008501
2 b 1 -0.008334 -1.935630
3 b 1 -0.481743 0.775196
4 a 0 0.597605 0.561882
key1
a 3
b 2
Name: data1, dtype: int64
key1
a 0.149997
b -0.245038
Name: data1, dtype: float64
2.按列名分组:DataFrame数据的列索引名可以作为分组键,但是用于分组的对象必须是DataFrame本身。不然会报错找不到索引名称。
#按列索引名称分组
grouped1 = df.groupby('key1').size()
grouped2 = df.groupby('key1').mean()
print(grouped1)
grouped2
key1
a 3
b 2
dtype: int64
key2 data1 data2
key1
a 0.333333 0.149997 0.252688
b 1.000000 -0.245038 -0.580217
3.按列表或元组分组:分组键还可以是和DataFrame行数相等的列表或者元组,相当于把列表或者元组当成DataFrame的一列,然后分组。
##所给的按列表或元组
w = ['w','w','y','w','y']
df.groupby(w).sum()
key2 data1 data2
w 2 -0.629356 0.971377
y 1 0.589272 -1.373748
4.按字典分组:如果原始的DataFrame中分组信息难以确定或不存在,则可以通过字典结构定义一个分组信息。
#定义一个字典来分组 分组信息:不区分大小写来分组
df = pd.DataFrame(np.random.normal(size=(6,5)), index=['a','b','A','B','c','C'])
print(df)
dic = {
"a":'one',
"b":'two',
"c":'three',
"A":'one',
"B":'two',
"C":'three'
}
x = df.groupby(dic)
print(x.sum())
0 1 2 3 4
a -0.422562 1.962075 -0.489384 -1.304302 -1.109478
b 1.134703 -0.358548 -1.373025 0.851012 -0.302279
A -0.196233 -0.192463 0.286070 0.872550 -0.835654
B -0.038677 -0.130829 -0.599642 -0.201865 -1.849057
c -0.033203 -0.512046 -0.414564 0.516591 1.191699
C -1.145768 0.176744 -0.160164 1.435075 -0.124890
0 1 2 3 4
one -0.618795 1.769613 -0.203314 -0.431753 -1.945131
three -1.178971 -0.335301 -0.574728 1.951666 1.066808
two 1.096026 -0.489377 -1.972667 0.649148 -2.151336
5.按函数分组:类似于字典,通过映射关系来进行分组
#函数
def judge(x):
if x>=0:
return 'a'
else:
return 'b'
df = pd.DataFrame(np.random.randn(4,4))
print(df)
print(df[3].groupby(df[3].map(judge)).sum())
0 1 2 3
0 0.714710 -1.180971 0.177371 1.257526
1 -0.465390 0.822470 1.767948 0.740839
2 0.194928 0.658354 -0.053870 -0.657892
3 1.001120 -1.195080 1.122340 -1.813876
a 1.998365
b -2.471768
Name: 3, dtype: float64
数据聚合:对分组后的数据进行计算,产生标量值的数据转换过程。
1.聚合函数:在聚合运算中,空值不参加计算。
函数 | 使用说明 |
---|---|
count | 计数 |
sum | 求和 |
mean | 平均值 |
median | 中位数 |
std、var | 无偏标准差和方差 |
min、max | 最小、最大值 |
prod | 求积 |
first、last | 第一个和最后一个值 |
2.agg方法实现聚合数据:支持对每个分组应用某个函数。能直接对DataFrame进行函数应用操作。
#agg
## 使用agg求出当前数据对应的统计量
data = pd.read_excel('D:\python\数据分析与可视化\第四章:pandas统计分析基础\data\\testdata.xls')
print(data.head())
print('求当前数据的各项统计量:\n',data[['淋巴细胞计数','白细胞计数']].agg([np.sum, np.mean]))
## 使用agg函数分别求各字段不同的统计量
print('求个字段的不同统计量:\n',data.agg({'淋巴细胞计数':np.mean, '白细胞计数':np.std}))
## 计算不同字段不同数目的统计量
print('计算不同字段不同数目的统计量:\n',data.agg({'淋巴细胞计数':np.mean, '白细胞计数':[np.std, np.mean]}))
## 统计不同性别人群的血小板计数的平均值
print('统计不同性别人群的血小板计数:\n',data.groupby('性别')['血小板计数'].agg(np.mean))
## 返回的数据不希望以分组键为索引 as_index=False实现
print('统计不同性别人群的血小板计数:\n',data.groupby('性别',as_index=False)['血小板计数'].agg(np.mean))
序号 性别 身份证号 是否吸烟 是否饮酒 开始从事某工作年份 体检年份 淋巴细胞计数 白细胞计数 细胞其它值 \
0 1 女 ****1982080000 否 否 2009年 2017 2.4 8.5 NaN
1 2 女 ****1984110000 否 否 2015年 2017 1.8 5.8 NaN
2 3 男 ****1983060000 否 否 2013年 2017 2.0 5.6 NaN
3 4 男 ****1985040000 否 否 2014年 2017 2.5 6.6 NaN
4 5 男 ****1986040000 否 否 2014年 2017 1.3 5.2 NaN
血小板计数
0 248.0
1 300.0
2 195.0
3 252.0
4 169.0
求当前数据的各项统计量:
淋巴细胞计数 白细胞计数
sum 4280.270000 6868.008100
mean 3.849164 6.176266
求个字段的不同统计量:
淋巴细胞计数 3.849164
白细胞计数 12.043418
dtype: float64
计算不同字段不同数目的统计量:
淋巴细胞计数 白细胞计数
mean 3.849164 6.176266
std NaN 12.043418
统计不同性别人群的血小板计数:
性别
女 212.687636
男 194.727417
Name: 血小板计数, dtype: float64
统计不同性别人群的血小板计数:
性别 血小板计数
0 女 212.687636
1 男 194.727417
分组运算:包含聚合运算,聚合运算是数据转换的特例。
1.transform方法:将运算分不到每一行
# 分组运算
## transform 运算分布到每一行
data.groupby('性别')['血小板计数'].transform('mean').sample(5)
915 194.727417
1039 194.727417
1062 194.727417
95 194.727417
416 212.687636
Name: 血小板计数, dtype: float64
2.apply方法:类似于agg方法,可以将函数应用于每一列
## apply 函数应用到每列 axis=1 应用到每行
data.groupby(['性别','是否吸烟'])['血小板计数'].apply(np.mean)
性别 是否吸烟
女 否 212.133188
是 297.333333
男 否 194.236749
是 195.210175
重要技巧:
groupby
之后直接.reset_index()
可以得到一个没有多级索引的DataFram,之后可以通过df.rename({‘old_col1’:‘new_col1’,‘old_col2’:‘new_col2’,…})
重命名
df1= df.groupby([‘date’])[‘price’].agg({‘sum’,‘count’}).reset_index()