pandas教程:Advanced GroupBy Use 高级GroupBy用法-灵析社区

清晨我上码

12.2 Advanced GroupBy Use(高级GroupBy用法)

我们已经在第十章讨论了groupby的一些用法,这里还有一些技巧可能会用得到。

1 Group Transforms and “Unwrapped” GroupBys(组变换和无包装的GroupBy)

在第十章里,使用apply方法在组上进行转换操作的。还有一个内建的方法叫transform,和apply相同,但是在一些函数的用法上有一些限制:

可以产生一个标量,将数据广播(broadcast)到与组一样的形状(这里的broadcast可以理解为改变数据形状的方法,感兴趣的可以直接搜索 numpy broadcast)

可以产生一个和输入的组一样形状的对象

不能对输入进行改变

举个例子:

import numpy as np
import pandas as pd
df = pd.DataFrame({'key': ['a', 'b', 'c'] * 4,
                   'value': np.arange(12.)})
df

通过key来计算组的平均值:

g = df.groupby('key').value
g.mean()
key
a    4.5
b    5.5
c    6.5
Name: value, dtype: float64

假设我们想要产生一个和df['value']一样大小的Series,不过要用key分组后的平均值来替换。我们可以把函数lambda x: x.mean()给transform:

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

对于内建的聚合函数,我们可以传入一个字符串别名,就像使用groupby agg方法的时候一样:

g.transform('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,transform能用那些返回Series的函数,但是结果的大小和输入的必须一样。例如,我们通过一个lambda函数令每个小组都乘2:

g.transform(lambda x: x * 2)
0      0.0
1      2.0
2      4.0
3      6.0
4      8.0
5     10.0
6     12.0
7     14.0
8     16.0
9     18.0
10    20.0
11    22.0
Name: value, dtype: float64

一个更复杂的例子,我们可以按降序来计算每一个组:

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

考虑一个包含简单聚合的分组转换函数:

def normalize(x):
    return (x - x.mean()) / x.std()

使用transform或apply,都能得到一样的结果:

g.transform(normalize)
0    -1.161895
1    -1.161895
2    -1.161895
3    -0.387298
4    -0.387298
5    -0.387298
6     0.387298
7     0.387298
8     0.387298
9     1.161895
10    1.161895
11    1.161895
Name: value, dtype: float64
g.apply(normalize)
0    -1.161895
1    -1.161895
2    -1.161895
3    -0.387298
4    -0.387298
5    -0.387298
6     0.387298
7     0.387298
8     0.387298
9     1.161895
10    1.161895
11    1.161895
Name: value, dtype: float64

内建的聚合函数,比如mean, sum经常比一般的apply函数要快。而是用transform的话,会更快一些。这就需要我们使用无包装的组操作(upwrapped group operation):

g.transform('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
normalized = (df['value'] - g.transform('mean')) / g.transform('std')
normalized
0    -1.161895
1    -1.161895
2    -1.161895
3    -0.387298
4    -0.387298
5    -0.387298
6     0.387298
7     0.387298
8     0.387298
9     1.161895
10    1.161895
11    1.161895
Name: value, dtype: float64

一个无包装的组操作可能会涉及多个组聚合操作,不过向量化操作会胜过这种操作。

2 Grouped Time Resampling(分组时间重采样)

对于时间序列数据,resample方法是一个基于时间的组操作。这里有一个样本表格:

N = 15
times = pd.date_range('2017-05-20 00:00', freq='1min', periods=N)
df = pd.DataFrame({'time': times, 'value': np.arange(N)})
df

我们用time索引,然后重采样:

df.set_index('time').resample('5min').count()

假设一个DataFrame包含多个时间序列,用多一个key列来表示:

df2 = pd.DataFrame({'time': times.repeat(3),
                    'key': np.tile(['a', 'b', 'c'], N), 
                    'value': np.arange(N * 3.)})
df2[:7]

想要对key列的值做重采样,我们引入pandas.TimeGrouper对象:

time_key = pd.TimeGrouper('5min')

然后设置time为索引,对key和time_key做分组,然后聚合:

resampled = (df2.set_index('time')
             .groupby(['key', time_key])
             .sum())
resampled

resampled.reset_index()

阅读量:1518

点赞量:0

收藏量:0