Pandas 累计和分组

对大数据进行分析的时候,⼀项基本工作就是数据累计(summarization),通常包括:

  • sum: 求和
  • mean:平均数
  • median:中位数
  • min:最小值
  • max:最大值
  • count:计数
  • first/last: 第⼀项和最后⼀项
  • std: 标准差
  • var:方差
  • mad:均值绝对方差
  • prod:所有项乘积
# 准备数据
# 我们这次准备数据时候⽤seaborn提供的⾏星数据,包括天⽂学家观测到的围绕恒星运⾏的⾏星数据
# 下载地址:
# https://github.com/mwaskom/seaborn-data
import seaborn as sns
planets = sns.load_dataset('planets')
print(planets.shape)
# 显示数据头部
print(planets.head())
(1035, 6)
 method number orbital_period mass distance year
0 Radial Velocity 1 269.300 7.10 77.40 2006
1 Radial Velocity 1 874.774 2.21 56.95 2008
2 Radial Velocity 1 763.000 2.60 19.84 2011
3 Radial Velocity 1 326.030 19.40 110.62 2007
4 Radial Velocity 1 516.220 10.50 119.47 2009

describe函数

describe函数计算每⼀列的常⽤统计值,给出⼀个比较笼统的数值。
通过下⾯describe计算的数据,我们可以对数据总体做出⼀个大概的判断,比如各个列的中级,最大值,均值等等。
在统计之前,我们先删除掉缺失值。

d = planets.dropna().describe()
print(d)
      number orbital_period mass distance year
count 498.00000 498.000000 498.000000 498.000000 498.000000
mean 1.73494 835.778671 2.509320 52.068213 2007.377510
std 1.17572 1469.128259 3.636274 46.596041 4.167284
min 1.00000 1.328300 0.003600 1.350000 1989.000000
25% 1.00000 38.272250 0.212500 24.497500 2005.000000
50% 1.00000 357.000000 1.245000 39.940000 2009.000000
75% 2.00000 999.600000 2.867500 59.332500 2011.000000
max 6.00000 17337.500000 25.000000 354.000000 2014.000000

GroupBy

GroupBy借用的是SQL的命令, 其核心思想是:

  • split:分割
  • applay:应⽤
  • combine:组合

通过运用GroupBy命令和不同的累计函数进行组合使用,对某些标签或索引进行累计分析。
下面来看个⼩案例

import pandas as pd
df = pd.DataFrame({"name":list("ABCABC"), "data":range(100,106)}, columns=["name",
"data"])
print("df = \n", df)
# 按name列进⾏分组,然后求魅族的平均数
a = df.groupby("name").mean()
print("\n a = \n", a)
df =
 name data
0 A 100
1 B 101
2 C 102
3 A 103
4 B 104
5 C 105
 a =
 data
name
A 101.5
B 102.5
C 103.5

GroupBy对象

GroupBy返回的结果是⼀个抽象类型,可以看组是⼀个DataFrame的集合。

按列取值返回的结果

# 按method列进⾏组合
gb = planets.groupby("method")
# gb是⼀个抽象数据
print(gb)
# 对GroupBy结果还可以再次抽取数
print(gb["orbital_period"])
<pandas.core.groupby.groupby.DataFrameGroupBy object at 0x7f755623f5f8>
<pandas.core.groupby.groupby.SeriesGroupBy object at 0x7f755623fa90>

下⾯句子相当于按找method进行组合,然后选取orbital_period列,选取后求每个组的中位数

a = planets.groupby("method")['orbital_period'].median()
print("组合后统计结果: \n", a)
组合后统计结果:
 method
Astrometry 631.180000
Eclipse Timing Variations 4343.500000
Imaging 27500.000000
Microlensing 3300.000000
Orbital Brightness Modulation 0.342887
Pulsar Timing 66.541900
Pulsation Timing Variations 1170.000000
Radial Velocity 360.200000
Transit 5.714932
Transit Timing Variations 57.011000
Name: orbital_period, dtype: float64

按组迭代

GroupBy对象⽀持进行迭代,返回每⼀组都是Series或者DataFrame数据。

迭代回来的数据⼤概是每组以method作为名称,几行六列的⼀个DataFrame

for (method, group) in planets.groupby("method"):
print(method, group.shape)
Astrometry (2, 6)
Eclipse Timing Variations (9, 6)
Imaging (38, 6)
Microlensing (23, 6)
Orbital Brightness Modulation (3, 6)
Pulsar Timing (5, 6)
Pulsation Timing Variations (1, 6)
Radial Velocity (553, 6)
Transit (397, 6)
Transit Timing Variations (4, 6)

调用方法

借助于Python强大的类方法(@classmethod), 可以直接对GroupBy的每⼀组对象添加功能,无论是DataFrame或者Series都可以使用。

a = planets.groupby("method")['year'].describe().unstack()
print(a)
	   method
count Astrometry 					2.000000
	  Eclipse Timing Variations 	9.000000
	  Imaging 						38.000000
	  Microlensing 					23.000000
	  Orbital Brightness Modulation 3.000000
	  Pulsar Timing 				5.000000
	  Pulsation Timing Variations 	1.000000
	  Radial Velocity 				553.000000
	  Transit 						397.000000
	  Transit Timing Variations 	4.000000
mean  Astrometry 					2011.500000
	  Eclipse Timing Variations 	2010.000000
	  Imaging 						2009.131579
	  Microlensing 					2009.782609
	  Orbital Brightness Modulation 2011.666667
	  Pulsar Timing 				1998.400000
	  Pulsation Timing Variations 	2007.000000
	  Radial Velocity 				2007.518987
   	  Transit 						2011.236776
	  Transit Timing Variations 	2012.500000
std   Astrometry 					2.121320
	  Eclipse Timing Variations 	1.414214
 	  Imaging 						2.781901
	  Microlensing 					2.859697
	  Orbital Brightness Modulation 1.154701
	  Pulsar Timing 				8.384510
	  Pulsation Timing Variations 	NaN
	  Radial Velocity 				4.249052
	  Transit 						2.077867
	  Transit Timing Variations 	1.290994
								 	...
50%   Astrometry 					2011.500000
	  Eclipse Timing Variations 	2010.000000
	  Imaging 						2009.000000
	  Microlensing 					2010.000000
	  Orbital Brightness Modulation 2011.000000
	  Pulsar Timing 				1994.000000
	  Pulsation Timing Variations 	2007.000000
	  Radial Velocity 				2009.000000
	  Transit 						2012.000000
	  Transit Timing Variations 	2012.500000
75%   Astrometry 					2012.250000
	  Eclipse Timing Variations 	2011.000000
	  Imaging 						2011.000000
	  Microlensing 					2012.000000
	  Orbital Brightness Modulation 2012.000000
	  Pulsar Timing 				2003.000000
	  Pulsation Timing Variations 	2007.000000
	  Radial Velocity 				2011.000000
	  Transit 						2013.000000
	  Transit Timing Variations 	2013.250000
max   Astrometry 					2013.000000
	  Eclipse Timing Variations 	2012.000000
	  Imaging 						2013.000000
	  Microlensing 					2013.000000
	  Orbital Brightness Modulation 2013.000000
	  Pulsar Timing 				2011.000000
	  Pulsation Timing Variations 	2007.000000
	  Radial Velocity 				2014.000000
	  Transit 						2014.000000
	  Transit Timing Variations 	2014.000000
Length: 80, dtype: float64

累计,过滤和转换

GroupBy基本功能是分组,但分组之后相应的操作,也为数据分析提供了很多⾼效的方法。
此类方法大概分为:

  • aggregate:累计
  • filter:过滤
  • transform:变换
  • apply:应用
# 数据准备
import numpy as np
import pandas as pd
rng = np.random.RandomState(0)
df = pd.DataFrame({'key':list("ABCABC"),
 'data_1':range(100,106),
 'data_2': rng.randint(0,10, 6)},
 columns=['key', 'data_1', 'data_2'])
print("df = \n", df)
df =
 key data_1 data_2
0 A 100 5
1 B 101 0
2 C 102 3
3 A 103 3
4 B 104 7
5 C 105 9

累计

相比较于sum和median之类的功能,累计(aggregate)能实现比较复杂的操作,比如字符串,函数或者函数列表,并且能⼀次性计算所有累计值。

同时统计min,median,max

rst = df.groupby('key').aggregate(['min', np.median, np.max])
print(rst)
	 data_1			 data_2
	 min median amax min median amax
key
A 	 100 101.5  103  3   4.0    5
B 	 101 102.5  104  0   3.5    7
C 	 102 103.5  105  3   6.0    9

或者还有其他的方法,对每列时候用不同的统计函数

rst = df.groupby('key').aggregate({'data_1':'min',
 'data_2':'max'})
print(rst)
 data_1 data_2
key
A 100 5
B 101 7
C 102 9

过滤

通过过滤功能,可以保留我们需要的值,把不需要的去掉。

# 过滤函数
def my_filter(x):
 return x['data_2'].std() > 1.5
rst = df.groupby('key').std()
print('df.std = \n', rst)
# 使⽤过滤函数,把不符合要求的过滤掉
rst = df.groupby('key').filter(my_filter)
print("\n rst.filter_func = \n", rst)
df.std =
 data_1 data_2
key
A 2.12132 1.414214
B 2.12132 4.949747
C 2.12132 4.242641

 rst.filter_func =
 key data_1 data_2
1 B 101 0
2 C 102 3
4 B 104 7
5 C 105 9

转换

累计操作把数据集合进行了裁剪和选择,而转换操作是把全量数据进行加工,得到的数据格式与输入数据⼀致,常见的操作是对数据减去均值,实现数据标准化。

# 对数据进⾏标准化
rst = df.groupby('key').transform(lambda x: x - x.mean())
print(rst)
 data_1 data_2
0 -1.5 1.0
1 -1.5 -3.5
2 -1.5 -3.0
3 1.5 -1.0
4 1.5 3.5
5 1.5 3.0

应用

apply可以让人在每个数据上应用任意方法,这个函数让输入⼀个DataFrane,返回的结果可以是pandas对象或者标量。

# 求每⼀项的百分⽐
def norm_data_1(x):
 # 求百分⽐
 x['data_1'] = x['data_1'] / x['data_1'].sum()

 return x
rst = df.groupby('key').apply(norm_data_1)
print(rst)
 key data_1 data_2
0 A 0.492611 5
1 B 0.492683 0
2 C 0.492754 3
3 A 0.507389 3
4 B 0.507317 7
5 C 0.507246 9

设置分割的键

对DataFrame的分割可以根据列来,也还有其他的方法。

将列表,数组,Series或者索引作为分组键

此时分组键可以是与DaytaFrame匹配的任意Series或者列表。

# 普通数组作为分组键
L = [0,1,1,0,2,1]
a = df.groupby(L).sum()
print(a)
  data_1 data_2
0 203 8
1 308 12
2 104 7

直接使用键值也可以

a = df.groupby(df['key']).sum()
print(a)
 data_1 data_2
key
A 203 8
B 205 7
C 207 12

用字典或者Series将索引映射到分组的名称

提供字典,按照字典的键值进行分组,最后结果使用字典键值映射的值。
要求索引必须跟字典的键值匹配。

# 利⽤字典分组
D_mapping = {'A':"One", 'B':"Two", 'C':"Three"}
df = df.set_index('key')
a = df.groupby(D_mapping).sum()
print(a)
 data_1 data_2
One 203 8
Three 207 12
Two 205 7

使用任意Python函数

我们还可以把Python函数传入groupby,与前⾯的内容类似,然后得到新的分组。

# 传⼊任意分组
a = df.groupby(str.lower).mean()
print(a)
 data_1 data_2
a 101.5 4.0
b 102.5 3.5
c 103.5 6.0

多个有效的键组成的列表

有效的键值可以组合起来,从而返回⼀个多级索引的分组结果。

# 利⽤上⾯定义的字典,我们可以组合成多级索引
a = df.groupby([str.lower, D_mapping]).mean()
print(a)
 data_1 data_2
a One 101.5 4.0
b Two 102.5 3.5
c Three 103.5 6.0
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值