GroupBy#
cuDF 支持 Pandas groupby API 的一小部分(但很重要)子集。
支持的操作摘要#
分组#
通过按一列或多列对 Series
或 DataFrame
的值进行分组来创建 GroupBy 对象
>>> import cudf
>>> df = cudf.DataFrame({'a': [1, 1, 1, 2, 2], 'b': [1, 1, 2, 2, 3], 'c': [1, 2, 3, 4, 5]})
>>> df
a b c
0 1 1 1
1 1 1 2
2 1 2 3
3 2 2 4
4 2 3 5
>>> gb1 = df.groupby('a') # grouping by a single column
>>> gb2 = df.groupby(['a', 'b']) # grouping by multiple columns
>>> gb3 = df.groupby(cudf.Series(['a', 'a', 'b', 'b', 'b'])) # grouping by an external column
警告
与 Pandas 不同,cuDF 默认使用 sort=False
以获得更好的性能,这不保证结果中组的特定顺序。
例如
>>> df = cudf.DataFrame({'a' : [2, 2, 1], 'b' : [42, 21, 11]})
>>> df.groupby('a').sum()
b
a
2 63
1 11
>>> df.to_pandas().groupby('a').sum()
b
a
1 11
2 63
设置 sort=True
将产生类似 Pandas 的输出,但会牺牲一些性能
>>> df.groupby('a', sort=True).sum()
b
a
1 11
2 63
按索引级别分组#
您还可以按 MultiIndex 的一个或多个级别进行分组
>>> df = cudf.DataFrame(
... {'a': [1, 1, 1, 2, 2], 'b': [1, 1, 2, 2, 3], 'c': [1, 2, 3, 4, 5]}
... ).set_index(['a', 'b'])
...
>>> df.groupby(level='a')
The Grouper
对象#
当列和级别同名时,可以使用 Grouper
来区分它们
>>> df
b c
b
1 1 1
1 1 2
1 2 3
2 2 4
2 3 5
>>> df.groupby('b', level='b') # ValueError: Cannot specify both by and level
>>> df.groupby([cudf.Grouper(key='b'), cudf.Grouper(level='b')]) # OK
聚合#
组上的聚合通过 agg
方法支持
>>> df
a b c
0 1 1 1
1 1 1 2
2 1 2 3
3 2 2 4
4 2 3 5
>>> df.groupby('a').agg('sum')
b c
a
1 4 6
2 5 9
>>> df.groupby('a').agg({'b': ['sum', 'min'], 'c': 'mean'})
b c
sum min mean
a
1 4 1 2.0
2 5 2 4.5
>>> df.groupby("a").corr(method="pearson")
b c
a
1 b 1.000000 0.866025
c 0.866025 1.000000
2 b 1.000000 1.000000
c 1.000000 1.000000
下表总结了可用的聚合以及支持它们的类型
聚合 / 数据类型 |
数值 |
日期时间 |
字符串 |
分类 |
列表 |
Struct |
区间 |
十进制 |
---|---|---|---|---|---|---|---|---|
count |
✅ |
✅ |
✅ |
✅ |
✅ |
|||
size |
✅ |
✅ |
✅ |
✅ |
✅ |
|||
sum |
✅ |
✅ |
✅ |
|||||
idxmin |
✅ |
✅ |
✅ |
|||||
idxmax |
✅ |
✅ |
✅ |
|||||
min |
✅ |
✅ |
✅ |
✅ |
||||
max |
✅ |
✅ |
✅ |
✅ |
||||
mean |
✅ |
✅ |
||||||
var |
✅ |
✅ |
||||||
std |
✅ |
✅ |
||||||
quantile |
✅ |
✅ |
||||||
median |
✅ |
✅ |
||||||
nunique |
✅ |
✅ |
✅ |
✅ |
✅ |
|||
nth |
✅ |
✅ |
✅ |
✅ |
||||
collect |
✅ |
✅ |
✅ |
✅ |
✅ |
|||
unique |
✅ |
✅ |
✅ |
✅ |
||||
corr |
✅ |
✅ |
||||||
cov |
✅ |
✅ |
GroupBy apply#
要对每个组应用函数,请使用 GroupBy.apply()
方法
>>> df
a b c
0 1 1 1
1 1 1 2
2 1 2 3
3 2 2 4
4 2 3 5
>>> df.groupby('a').apply(lambda x: x.max() - x.min())
a b c
a
0 0 1 2
1 0 1 1
限制#
apply
的工作方式是将提供的函数依次应用于每个组,然后将结果连接在一起。这可能非常慢,特别是对于大量小分组。对于少量大分组,它可以提供可接受的性能。结果可能并非总是与 Pandas 完全匹配。例如,cuDF 可能会返回包含单列的
DataFrame
,而 Pandas 返回Series
。可能需要进行一些后处理才能匹配 Pandas 的行为。cuDF 不支持 Pandas 使用
apply
支持的一些特殊情况,例如在可调用对象中调用 describe。
Transform#
.transform()
方法按组进行聚合,并将结果广播到组的大小,从而生成一个与输入 Series/DataFrame 大小相同的 Series/DataFrame。
>>> import cudf
>>> df = cudf.DataFrame({'a': [2, 1, 1, 2, 2], 'b': [1, 2, 3, 4, 5]})
>>> df.groupby('a').transform('max')
b
0 5
1 3
2 3
3 5
4 5
滚动窗口计算#
使用 GroupBy.rolling()
方法对每个组执行滚动窗口计算
>>> df
a b c
0 1 1 1
1 1 1 2
2 1 2 3
3 2 2 4
4 2 3 5
对每个组执行窗口大小为 2 的滚动窗口求和
>>> df.groupby('a').rolling(2).sum()
a b c
a
1 0 <NA> <NA> <NA>
1 2 2 3
2 2 3 5
2 3 <NA> <NA> <NA>
4 4 5 9