1.1 描述统计
分组对象如同df.describe(),也支持.describe(),用来对数据的总体进行描述:
# 描述统计
df.groupby('team').describe()
# 由于列过多,我们进行转置
df.groupby('team').describe().T
1.2 统计函数
对分组对象直接使用统计函数,对分组内的所有数据进行此计算,最终以DataFrame形式显示数据。
# 各组平均数
grouped.mean()
1.3 聚合方法agg()
分组对象的方法.aggregate()简写为.agg()。它的作用是将分组后的对象给定统计方法,也支持按字段分别给定不同的统计方法。
# 所有列使用一个计算方法
df.groupby('team').aggregate(sum)
df.groupby('team').agg(sum)
grouped.agg(np.size)
grouped['Q1'].agg(np.mean)
使用它主要是为了实现一个字段使用多种统计方法,不同字段使用不同方法:
# 每个字段使用多个计算方法
grouped[['Q1','Q3']].agg([np.sum, np.mean, np.std])
不同列使用不同计算方法,且一个列用多个计算方法:
df.groupby('team').agg({'Q1': ['min', 'max'], 'Q2': 'sum'})
类似于我们之前学过的增加新列的方法df.assign(),agg()可以指定新列的名字:
# 指定列名,列表是为原列和方法
df.groupby('team').Q1.agg(Mean='mean', Sum='sum')
df.groupby('team').agg(Mean=('Q1', 'mean'), Sum=('Q2', 'sum'))
df.groupby('team').agg(
Q1_max=pd.NamedAgg(column='Q1', aggfunc='max'),
Q2_min=pd.NamedAgg(column='Q2', aggfunc='min')
)
如果列名不是有效的Python变量格式,则可以用以下方法:
df.groupby('team').agg(**{
'1_max':pd.NamedAgg(column='Q1', aggfunc='max')})
统计方法可以使用函数。在使用函数时,分别传入每个分组后的子DataFrame,会按子DataFrame把这组的所有列组成的序列传到函数里进行计算,最终返回一个固定值。
# 聚合结果使用函数
# lambda/函数,所有方法都可以用
def max_min(x):
return x.max() - x.min()
# 定义函数
df.groupby('team').Q1.agg(Mean='mean',
Sum='sum',
Diff=lambda x: x.max() - x.min(),
Max_min=max_min
)
如果对全列使用同一函数,直接写函数名即可:
# 调用函数
df.groupby('team').agg(max_min)
1.4 时序重采样方法resample()
针对时间序列数据,resample()将分组后的时间索引按周期进行聚合统计。
idx = pd.date_range('1/1/2020', periods=100, freq='T')
df2 = pd.DataFrame(data={'a':[0, 1]*50, 'b':1},
index=idx)
索引为一个时序数据,按下来,我们按a列进行分组,然后按每20分钟(由于1分钟是一个周期T,我们传入20T)对b进行求和计算:
# 每20分钟聚合一次
df2.groupby('a').resample('20T').sum()
# 三个周期一聚合(一分钟一个周期)
df.groupby('a').resample('3T').sum()
# 30秒一分组
df.groupby('a').resample('30S').sum()
# 每月
df.groupby('a').resample('M').sum()
# 以右边时间点为标识
df.groupby('a').resample('3T', closed='right').sum()
1.5 组内头尾值
在一个组内,如果希望取第一个值和最后一个值,可以使用以下方法。当然,定义第一个和最后一个是你需要事先完成的工作。
# 每组第一个
df.groupby('team').first()
# 每组最后一个
df.groupby('team').last()
1.6 组内分位数
我们经常使用中位数,它是分位数的一个特殊情形,为二分位。如果在分组中需要看指定分位数据,可以使用.quantile()来实现。
# 二分位数,即中位数
df.groupby('team').median() # 同下
df.groupby('team').quantile()
df.groupby('team').quantile(0.5)
1.7 组内差值
和DataFrame的diff()一样,分组对象的diff()方法会在组内进行前后数据的差值计算,并以原DataFrame形状返回数据:
# grouped为全数字列,计算在组内的前后差值
grouped.diff()
2 数据分箱
数据分箱(data binning,也称为离散组合或数据分桶)是一种数据预处理技术,它将原始数据分成几个小区间,即bin(小箱子),是一种量子化的形式。数据分箱可以最大限度减小观察误差的影响。落入给定区间的原始数据值被代表该区间的值(通常是中心值)替换。然后将其替换为针对该区间计算的常规值。这具有平滑输入数据的作用,并且在小数据集的情况下还可以减少过拟合。
Pandas主要基于以两个函数实现连续数据的离散化处理。
pandas.cut:根据指定分界点对连续数据进行分箱处理。
pandas.qcut:根据指定区间数量对连续数据进行等宽分箱处理。所谓等宽,指的是每个区间中的数据量是相同的。
2.1 定界分箱pd.cut()
# 将Q1成绩换60分及以上、60分以下进行分类
pd.cut(df.Q1, bins=[0, 60, 100])
将分箱结果应用到groupby分组中:
# Series使用
df.Q1.groupby(pd.cut(df.Q1, bins=[0, 60, 100])).count()
# DataFrame使用
df.groupby(pd.cut(df.Q1, bins=[0, 60, 100])).count()
# 不显示区间,使用数字作为每个箱子的标签,形式如0,1,2,n等
pd.cut(df.Q1, bins=[0, 60, 100],labels=False)
# 指定标签名
pd.cut(df.Q1, bins=[0, 60, 100],labels=['不及格','及格',])
# 包含最低部分
pd.cut(df.Q1, bins=[0, 60, 100], include_lowest=True)
# 是否为右闭区间,下例为[89, 100)
pd.cut(df.Q1, bins=[0, 89, 100], right=False)
2.2 等宽分箱pd.qcut()
pd.qcut()可以指定所分区间的数量,Pandas会自动进行分箱:
# 按Q1成绩分为两组
pd.qcut(df.Q1,q=2)
# 查看分组区间
pd.qcut(df.Q1,q=2).unique()
应用到分组中:
# Series使用
df.Q1.groupby(pd.qcut(df.Q1,q=2)).count()
# DataFrame使用
df.groupby(pd.qcut(df.Q1,q=2)).max()
pd.qcut(range(5), 4)
pd.qcut(range(5), 4,labels=False)
# 指定标签名
pd.qcut(range(5), 3,labels=["good", "medium", "bad"])
# 返回箱子标签
array([1. ,51.5, 98.]))
pd.qcut(df.Q1, q=2, retbins=True)
# 分箱位小数位数
pd.qcut(df.Q1, q=2, precision=3)
排名分3个层次
pd.qcut(df.Q1.rank(method='first'), 3)
2.6 分组可视化
数据分组对象也支持plot(),不过它以分组对象中每个DataFrame或Series为对象,绘制出所有分组的图形。默认情况下,它绘制的是折线图
# 分组,设置索引为name
grouped = df.set_index('name').groupby('team')
# 绘制图形
grouped.plot()
还可以通过plot.x()或者plot(kind='x')的形式调用其他形状的图形,比如:
plot.line:折线图
plot.pie:饼图
plot.bar:柱状图
plot.hist:直方图
plot.box:箱形图
plot.area:面积图
plot.scatter:散点图
plot.hexbin:六边形分箱图
2.2 直方图hist()
组对象的hist()可以绘制出每个分组的直方图矩阵,每个矩阵为一个分组:
# 绘制直方图
grouped.hist()
2.3 箱线图boxplot()
分组的boxplot()方法绘制出每个组的箱线图。箱线图展示了各个字段的最大值、最小值、分位数等信息,为我们展示了数据的大体形象,代码如下。
# 分组箱线图
grouped.boxplot(figsize=(15,12))