高阶GroupBy应用
本文中可能使用的数据集来自:《利用python进行数据分析》数据集。
之前我们已经讲过通过使用groupby方法来进行数据的分组和聚合。这里介绍一些可能会在数据分析过程中用到的额外用法。
分组转换和“展开”GroupBy
我们在之前分组和聚合的学习中知道,apply方法可以用于执行转换操作。transform方法与apply方法类似,但是会对你使用的函数进行更多的限制:
- transform可以产生一个标量值,并广播到各分组的尺寸数据中
- transform可以产生一个与输入分组尺寸相同的对象
- transform不可以改变它的输入
为了更加直观的说明,首先考虑下面这个DataFrame:
df = pd.DataFrame({"key":list("abc") * 4,
"value":np.arange(12.)})
print(df)
# key value
# 0 a 0.0
# 1 b 1.0
# 2 c 2.0
# 3 a 3.0
# 4 b 4.0
# 5 c 5.0
# 6 a 6.0
# 7 b 7.0
# 8 c 8.0
# 9 a 9.0
# 10 b 10.0
# 11 c 11.0
现在我们想要计算key相同的数据的value的平均值,从之前数据聚合的知识可以知道,可以使用下面的方法:
g = df.groupby("key").value
print(g.mean())
# key
# a 4.5
# b 5.5
# c 6.5
# Name: value, dtype: float64
现在假设我们想要保持计算完平均值后返回的Series大小与原Series大小一样,每个位置上填充的是计算出的平均值,那么我们就可以使用transform方法:
print(g.transform(lambda x:x.mean()))
# 0 4.5
# 1 5.5
# 2 6.5
# 3 4.5
# 4 5.5
# 5 6.5
# 6 4.5
# 7 5.5
# 8 6.5
# 9 4.5
# 10 5.5
# 11 6.5
# Name: value, dtype: float64
当然,就像apply方法一样,还可以这样:
print(g.transform(np.mean))
print(g.transform('mean'))
再比如说,我们想进行一个组内的排序(序号a的数据一同排序,序号为b的一同排序……):
print(g.transform(lambda x:x.rank(ascending=False)))
# 0 4.0
# 1 4.0
# 2 4.0
# 3 3.0
# 4 3.0
# 5 3.0
# 6 2.0
# 7 2.0
# 8 2.0
# 9 1.0
# 10 1.0
# 11 1.0
# Name: value, dtype: float64
这里需要注意的是,使用内建的聚合函数如’mean’或者’sum’,通常会比apply函数更快。将这些函数传入transform方法可以进行一个分组展开的操作(正如之前看到的,将‘mean’传入transform)。
分组的时间重新采样
resample方法可以看做是在时间上的分组操作(resample的用法)。下面是一个小示例:
N = 15
times = pd.date_range("2017-5-20 00:00",freq="min",periods=N)
df = pd.DataFrame({"time":times,"value":np.arange(N)})
print(df.head())
# time value
# 0 2017-05-20 00:00:00 0
# 1 2017-05-20 00:01:00 1
# 2 2017-05-20 00:02:00 2
# 3 2017-05-20 00:03:00 3
# 4 2017-05-20 00:04:00 4
之后我们可以按“time”进行索引,重新采样:
res = df.set_index("time").resample("5min").count()
print(res)
# value
# time
# 2017-05-20 00:00:00 5
# 2017-05-20 00:05:00 5
# 2017-05-20 00:10:00 5
现在考虑下面这个DataFrame对象,它包含着重复的时间项:
N = 15
times = pd.date_range("2017-5-20 00:00",freq="min",periods=N)
df2 = pd.DataFrame({"time":times.repeat(3),
"key":np.tile(list('abc'),N),
"value":np.arange(N * 3)})
print(df2.head(5))
# time key value
# 0 2017-05-20 00:00:00 a 0
# 1 2017-05-20 00:00:00 b 1
# 2 2017-05-20 00:00:00 c 2
# 3 2017-05-20 00:01:00 a 3
# 4 2017-05-20 00:01:00 b 4
如果我们想按照key和time同时进行分组,那么我们就不能直接使用resample方法了,但是我们可以仍可以使用groupby方法:
time_key = pd.Grouper(freq = "5min")
#使用groupby方法按时间频率进行聚合的时候,需要传入Grouper对象(原书中为TimeGrouper对象)
resampled = df2.set_index("time")\
.groupby(["key",time_key])\
.sum()
#使用key和time_key进行分组,之后用sum方法进行聚合
print(resampled)
# value
# key time
# a 2017-05-20 00:00:00 30
# 2017-05-20 00:05:00 105
# 2017-05-20 00:10:00 180
# b 2017-05-20 00:00:00 35
# 2017-05-20 00:05:00 110
# 2017-05-20 00:10:00 185
# c 2017-05-20 00:00:00 40
# 2017-05-20 00:05:00 115
# 2017-05-20 00:10:00 190
print(resampled.reset_index())
# key time value
# 0 a 2017-05-20 00:00:00 30
# 1 a 2017-05-20 00:05:00 105
# 2 a 2017-05-20 00:10:00 180
# 3 b 2017-05-20 00:00:00 35
# 4 b 2017-05-20 00:05:00 110
# 5 b 2017-05-20 00:10:00 185
# 6 c 2017-05-20 00:00:00 40
# 7 c 2017-05-20 00:05:00 115
# 8 c 2017-05-20 00:10:00 190