import numpy as np
import pandas as pd
分组模式及其对象
1. 分组的一般模式
df.groupby(分组依据)[数据来源].使用操作
2. 分组依据的本质
① 单个维度、多个维度的分组,直接在groupby中传入相应列名构成的列表即可。
df.groupby(['School','Gender'])['Height'].mean()
② 通过一定的复杂逻辑来分组
#先写出分组条件
condition = df.Weight > df.Weight.mean()
df.groupby(condition)['Height'].mean()
练一练
请根据上下四分位数分割,将体重分为high、normal、low三组,统计身高的均值。
def fenzu_height(x):
if x > df['Height'].quantile(0.75):
return "high"
elif x < df['Height'].quantile(0.25):
return "low"
else:
return "normal"
bool = df['Height'].apply(fenzu_height)
df.groupby(bool)['Height'].mean()
首先写一个函数分出三种情况,再对要求的身高那一列的数据apply这个函数【先写好分组条件】
最后产生的结果就是按照条件列表中元素的值来分组,下面用随机传入字母序列来验证这一想法
如果传入多个序列进入 groupby ,那么最后分组的依据就是这两个序列对应行的唯一组合
通过 drop_duplicates 就能知道具体的组类别
df[['School', 'Gender']].drop_duplicates()
3. Groupby对象
gb = df.groupby(['School', 'Grade'])
具体做分组操作时,所调用的方法都来自于 pandas 中的 groupby 对象,这个对象上定义了许多方法,也具有一些方便的属性。
① 通过 ngroups 属性,可以得到分组个数
gb.ngroups
#16
② 通过 groups 属性,可以返回从 组名 映射到 组索引列表 的字典:
res = gb.groups
# 字典的值由于是索引,元素个数过多,此处只展示字典的键
res.keys()
练一练
上一小节介绍了可以通过 drop_duplicates 得到具体的组类别,现请用 groups 属性完成类似的功能。
gb = df.groupby(['School','Grade'])
res = gb.groups
res.keys()
③ 当 size 作为 DataFrame 的属性时,返回的是表长乘以表宽的大小,但在 groupby 对象上表示统计每个组的元素个数
gb.size()
④ 通过 get_group 方法可以直接获取所在组对应的行,此时必须知道组的具体名字
gb.get_group(('Fudan University', 'Freshman'))
二、聚合函数
1.内置聚合函数
在介绍agg之前,首先要了解一些直接定义在groupby对象的聚合函数,因为它的速度基本都会经过内部的优化,使用功能时应当优先考虑。根据返回标量值的原则,包括如下函数:
max/min/mean/median/count/all/any/idxmax/idxmin/mad/nunique/skew/quantile/sum/std/var/sem/size/prod
练一练
请查阅文档,明确 all/any/mad/skew/sem/prod 函数的含义。
- all 和 any 一般用于bool值列。all表示分组后每一组中所有值都为True则返回True , 有一个False就返回False;any 表示bool值列中只要有一个True则返回true , 只有全为False才会返回False非0都是Ture!!!
- mad(mean absolute deviation)平均绝对离差 , 用于统计学中对分组后的每组数据做离散程度分析的指标之一
M
i
=
1
n
∑
k
=
1
n
∣
x
k
−
x
ˉ
∣
M_i=\frac1n\sum_{k=1}^n|x_k-\bar x|
Mi=n1∑k=1n∣xk−xˉ∣
- skew(skewness)偏度 , 用来反映分组后每组数据分布的偏态程度 , 正值为右偏 , 绝对值越大 , 偏度越高
S K i = n n − 1 ∑ k = 1 n ( x k − x ˉ ) 2 ( n − 2 ) ( ∑ k = 1 n ( x k − x ˉ ) 2 ) 3 2 SK_i=\frac{n\sqrt{n-1}\sum_{k=1}^n(x_k-\bar x)^2}{(n-2)(\sum_{k=1}^n(x_k-\bar x)^2)^{\frac32}} SKi=(n−2)(∑k=1n(xk−xˉ)2)23nn−1 ∑k=1n(xk−xˉ)2
- sem(standard error of mean)均值标准误差 , 描述的是多个均值样本的标准差,体现均值抽样分布的离散程度,反映样本均值之间的差异
设样本无偏估计标准差为s , 样本大小为N , 则分组后每组的sem可表示为
S E M i = s N SEM_i=\frac{s}{\sqrt N} SEMi=N s
- prod(product)连乘 , 每组prod表示为
P R O D i = Π k = 1 n x k PROD_i=\Pi_{k=1}^nx_k PRODi=Πk=1nxk
这些聚合函数当传入的数据来源包含多个列时,将按照列进行迭代计算:
2. agg方法
虽然在 groupby 对象上定义了许多方便的函数,但仍然有以下不便之处:
- 无法同时使用多个函数
- 无法对特定的列使用特定的聚合函数
- 无法使用自定义的聚合函数
- 无法直接对结果的列名在聚合前进行自定义命名
下面说明如何通过 agg 函数解决这四类问题:
【a】使用多个函数
当使用多个聚合函数时,需要用列表的形式把内置聚合函数对应的字符串传入,先前提到的所有字符串都是合法的。
此时的列索引为多级索引,第一层为数据源,第二层为使用的聚合方法,分别逐一对列使用聚合,因此结果为6列。
【b】对特定的列使用特定的聚合函数
对于方法和列的特殊对应,可以通过构造字典传入 agg 中实现,其中字典以列名为键,以聚合字符串或字符串列表为值。
练一练
请使用【b】中的传入字典的方法完成【a】中等价的聚合任务。
gb.agg({'Height':['sum','idxmax','skew'],'Weight':['sum','idxmax','skew']})
【c】使用自定义函数
在 agg 中可以使用具体的自定义函数, 需要注意传入函数的参数是之前数据源中的列,逐列进行计算 。下面分组计算身高和体重的极差:
练一练
在 groupby 对象中可以使用 describe 方法进行统计信息汇总,请同时使用多个聚合函数,完成与该方法相同的功能。
gb.describe()
gb.agg(['count','mean','std','min',('25%',lambda x:x.quantile(0.25)),('50%','quantile'),('75%',lambda x:x.quantile(0.75)),'max'])
由于传入的是序列,因此序列上的方法和属性都是可以在函数中使用的,只需保证返回值是标量即可。下面的例子是指,如果组的指标均值,超过该指标的总体均值,返回High,否则返回Low。
【d】聚合结果重命名
如果想要对聚合结果的列名进行重命名,只需要将上述函数的位置改写成元组,元组的第一个元素为新的名字,第二个位置为原来的函数,包括聚合字符串和自定义函数,现举若干例子说明:
另外需要注意,使用对一个或者多个列使用单个聚合的时候,重命名需要加方括号,否则就不知道是新的名字还是手误输错的内置函数字符串
三、变换和过滤
1. 变换函数与transform方法
变换函数的返回值为同长度的序列,最常用的内置变换函数是累计函数: cumcount/cumsum/cumprod/cummax/cummin ,它们的使用方式和聚合函数类似,只不过完成的是组内累计操作。
当用自定义变换时需要使用 transform 方法,被调用的自定义函数, 其传入值为数据源的序列 ,与 agg 的传入类型是一致的,其最后的返回结果是行列索引与数据源一致的 DataFrame 。
2.组索引与过滤
组过滤作为行过滤的推广,指的是如果对一个组的全体所在行进行统计的结果返回 True 则会被保留, False 则该组会被过滤,最后把所有未被过滤的组其对应的所在行拼接起来作为 DataFrame 返回。
在 groupby 对象中,定义了 filter 方法进行组的筛选,其中自定义函数的输入参数为数据源构成的 DataFrame 本身,在之前例子中定义的 groupby 对象中,传入的就是 df[[‘Height’, ‘Weight’]] ,因此所有表方法和属性都可以在自定义函数中相应地使用,同时只需保证自定义函数的返回为布尔值即可。
跨列分组
一般使用apply
参考
https://datawhalechina.github.io/joyful-pandas/build/html/%E7%9B%AE%E5%BD%95/ch4.html