想知道 Pandas 数据类型传给 groupby 的 transform 或 apply 时会发生什么,为了调试 groupby 函数应用程序,可以尝试使用一个虚拟函数来查看传递到每个组的函数对象。具体代码示例如下:
import numpy as np
import pandas as pd
np.random.seed(0) # 使每个人都可以看到相同的输出
categories = list('abc')
categories = categories * 4
data_1 = np.random.randn(len(categories))
data_2 = np.random.randn(len(categories))
df = pd.DataFrame({'category': categories, 'data_1': data_1, 'data_2': data_2})
def f(x):
print(type(x))
return x
print('single column transform')
df.groupby(['category'])['data_1'].transform(f)
print('\n')
print('single column (nested) transform')
df.groupby(['category'])[['data_1']].transform(f)
print('\n')
print('multiple column transform')
df.groupby(['category'])[['data_1', 'data_2']].transform(f)
print('\n\n')
print('single column apply')
df.groupby(['category'])['data_1'].apply(f)
print('\n')
print('single column (nested) apply')
df.groupby(['category'])[['data_1']].apply(f)
print('\n')
print('multiple column apply')
df.groupby(['category'])[['data_1', 'data_2']].apply(f)
运行上面的代码,会得到以下结果:
single column transform
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
single column (nested) transform
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
multiple column transform
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
single column apply
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
single column (nested) apply
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
multiple column apply
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
从输出结果可以看出,transform 和 apply 在不同的情况下会传递不同的数据类型给函数,具体情况如下:
- 单列转换:
- transform:Series对象
- apply:Series对象
- 单列(嵌套)转换:
- transform:Series对象和DataFrame对象
- apply:DataFrame对象
- 多列转换:
- transform:Series对象和DataFrame对象
- apply:DataFrame对象
解决方案
GroupBy.transform 将尝试针对你的函数使用快速路径和慢速路径。
- 快速路径:使用 DataFrame 对象调用你的函数
- 慢速路径:使用 DataFrame.apply 函数调用你的函数
当快速路径的结果与慢速路径的结果相同,就选择快速路径,当两者不同时,使用慢速路径。
以上代码通过调用自定义函数 f,并打印出传递给函数的数据类型,来分析 transform 和 apply 在不同情况下传递给函数的数据类型。
代码例子
以下是一个代码例子,展示了如何使用 transform 和 apply 对 DataFrame 进行分组操作:
import numpy as np
import pandas as pd
np.random.seed(0)
categories = list('abc')
categories = categories * 4
data_1 = np.random.randn(len(categories))
data_2 = np.random.randn(len(categories))
df = pd.DataFrame({'category': categories, 'data_1': data_1, 'data_2': data_2})
# 使用 transform 对 data_1 列求均值
df['data_1_mean'] = df.groupby('category')['data_1'].transform('mean')
# 使用 apply 对 data_1 列求标准差
df['data_1_std'] = df.groupby('category')['data_1'].apply(np.std)
print(df)
输出结果为:
category data_1 data_2 data_1_mean data_1_std
0 a -0.4192 0.1851 -0.4315 0.3142
1 a 1.0221 -0.6935 -0.4315 0.3142
2 a -0.1626 0.9709 -0.4315 0.3142
3 a -0.0632 -0.4830 -0.4315 0.3142
4 b 1.0230 0.9005 0.8221 0.7578
5 b 0.5135 -0.4654 0.8221 0.7578
6 b -1.3288 0.4949 0.8221 0.7578
7 b -0.5249 0.7044 0.8221 0.7578
8 c -0.2342 -1.2560 -0.0396 0.5812
9 c 1.5361 -0.9646 -0.0396 0.5812
10 c -0.0864 0.1474 -0.0396 0.5812
11 c -1.4246 -1.0375 -0.0396 0.5812
可以看到,使用 transform 和 apply 可以对 DataFrame 进行分组操作,并对每组数据进行计算,非常方便。