Pandas2.2 GroupBy
Function application
| 方法 | 描述 |
|---|---|
| SeriesGroupBy.apply(func, *args, **kwargs) | 用于对每个分组应用指定的函数 |
| DataFrameGroupBy.apply(func, *args[, …]) | 用于对每个分组应用指定的函数 |
| SeriesGroupBy.agg([func, engine, engine_kwargs]) | 用于在滚动窗口上应用聚合函数的方法 |
| DataFrameGroupBy.agg([func, engine, …]) | 用于对分组数据应用一个或多个聚合函数 |
| SeriesGroupBy.aggregate([func, engine, …]) | 用于对分组数据应用聚合函数 |
| DataFrameGroupBy.aggregate([func, engine, …]) | 用于对分组数据应用聚合函数 |
| SeriesGroupBy.transform(func, *args[, …]) | 用于对每个分组应用指定的函数 |
pandas.SeriesGroupBy.transform()
方法描述
pandas.SeriesGroupBy.transform(func, *args, engine=None, engine_kwargs=None, **kwargs) 是 SeriesGroupBy 对象的一个方法,用于对每个分组应用指定的函数,并返回一个与原始 Series 具有相同索引的 Series。与 apply() 和 agg() 不同,transform() 的关键特点是保持原始数据的形状,它将聚合结果广播回原始数据的每个元素。
参数说明
func: function, str, list or dict- 要应用于每个分组的函数,可以是字符串(如 ‘mean’, ‘sum’)、函数对象或它们的组合
*args: 传递给函数的位置参数- [engine]: str, default None
- 计算引擎,可选 ‘cython’ 或 ‘numba’
- None 表示使用默认引擎
engine_kwargs: dict, default None- 传递给计算引擎的额外参数
**kwargs: 传递给函数的关键字参数
返回值
返回一个 Series,其索引与原始 Series 相同,每个元素都被替换为对应分组的转换结果。
使用示例
import pandas as pd
import numpy as np
# 示例1: 基本用法 - 标准化数据
print("=== 示例1: 基本用法 - 标准化数据 ===")
data = pd.Series([10, 20, 30, 40, 50, 60],
index=['A', 'A', 'B', 'B', 'C', 'C'])
print("原始数据:")
print(data)
print()
grouped = data.groupby(level=0)
print("对每个分组应用 mean 函数进行标准化:")
result_mean = grouped.transform('mean')
print(result_mean)
print()
print("减去分组均值实现组内标准化:")
result_standardized = data - grouped.transform('mean')
print(result_standardized)
print()
# 示例2: 使用自定义函数
print("=== 示例2: 使用自定义函数 ===")
def custom_transform(series):
"""自定义转换函数:将每个元素转换为占组总和的比例"""
return series / series.sum()
print("将每个元素转换为占组总和的比例:")
result_custom = grouped.transform(custom_transform)
print(result_custom)
print()
# 示例3: 百分位数排名
print("=== 示例3: 百分位数排名 ===")
values = pd.Series([1, 5, 2, 8, 3, 9, 4, 7],
index=['X', 'X', 'Y', 'Y', 'X', 'X', 'Y', 'Y'])
print("值序列:")
print(values)
print()
grouped_values = values.groupby(level=0)
print("计算每组内的百分位数排名:")
result_percentile = grouped_values.transform(lambda x: x.rank(pct=True))
print(result_percentile)
print()
# 示例4: 填充缺失值
print("=== 示例4: 填充缺失值 ===")
data_with_nan = pd.Series([1, np.nan, 3, np.nan, 5, 6],
index=['A', 'A', 'B', 'B', 'C', 'C'])
print("包含缺失值的数据:")
print(data_with_nan)
print()
grouped_nan = data_with_nan.groupby(level=0)
print("使用每组的均值填充缺失值:")
result_filled = grouped_nan.transform(lambda x: x.fillna(x.mean()))
print(result_filled)
print()
# 示例5: 数据去趋势
print("=== 示例5: 数据去趋势 ===")
time_series = pd.Series([10, 15, 20, 25, 30, 35],
index=['Group1', 'Group1', 'Group1', 'Group2', 'Group2', 'Group2'])
print("时间序列数据:")
print(time_series)
print()
grouped_ts = time_series.groupby(level=0)
print("去除每组线性趋势:")
def detrend(series):
x = np.arange(len(series))
slope, intercept = np.polyfit(x, series, 1)
trend = slope * x + intercept
return series - trend
result_detrend = grouped_ts.transform(detrend)
print(result_detrend)
print()
# 示例6: 复杂金融数据示例
print("=== 示例6: 复杂金融数据示例 ===")
returns = pd.Series([0.02, -0.01, 0.03, -0.02, 0.04, 0.01,
-0.03, 0.02, 0.01, -0.01, 0.03, 0.02],
index=['Tech', 'Tech', 'Finance', 'Finance', 'Tech', 'Finance',
'Tech', 'Finance', 'Tech', 'Finance', 'Tech', 'Finance'])
print("月度收益率数据:")
for i in range(len(returns)):
print(f"{returns.index[i]}: {returns.iloc[i]:.2%}")
print()
grouped_returns = returns.groupby(level=0)
print("将收益率标准化为每行业的Z分数:")
industry_mean = grouped_returns.transform('mean')
industry_std = grouped_returns.transform('std')
z_scores = (returns - industry_mean) / industry_std
print(z_scores.round(4))
print()
# 示例7: 分组排序
print("=== 示例7: 分组排序 ===")
scores = pd.Series([85, 92, 78, 95, 88, 90],
index=['Class_A', 'Class_A', 'Class_B', 'Class_B', 'Class_A', 'Class_B'])
print("学生分数:")
print(scores)
print()
grouped_scores = scores.groupby(level=0)
print("每班内学生的相对排名:")
relative_rank = grouped_scores.transform(lambda x: x.rank(method='average', ascending=False))
print(relative_rank)
print()
# 示例8: 移动窗口变换
print("=== 示例8: 移动窗口变换 ===")
data_window = pd.Series([1, 2, 3, 4, 5, 6, 7, 8],
index=['Group1', 'Group1', 'Group1', 'Group1',
'Group2', 'Group2', 'Group2', 'Group2'])
print("数据序列:")
print(data_window)
print()
grouped_window = data_window.groupby(level=0)
print("计算每组内的累积和:")
cumsum_result = grouped_window.transform('cumsum')
print(cumsum_result)
print()
# 示例9: 条件变换
print("=== 示例9: 条件变换 ===")
sales = pd.Series([100, 150, 200, 120, 180, 160],
index=['North', 'North', 'South', 'South', 'East', 'East'])
print("销售数据:")
print(sales)
print()
grouped_sales = sales.groupby(level=0)
print("高于组均值的标记为1,否则为0:")
mean_sales = grouped_sales.transform('mean')
above_average = (sales > mean_sales).astype(int)
print(above_average)
print()
# 示例10: 多级索引变换
print("=== 示例10: 多级索引变换 ===")
multi_index = pd.MultiIndex.from_tuples([
('A', 1), ('A', 2), ('B', 1), ('B', 2), ('C', 1), ('C', 2)
])
data_multi = pd.Series([10, 20, 30, 40, 50, 60], index=multi_index)
print("多级索引数据:")
print(data_multi)
print()
# 按第一级分组
grouped_level0 = data_multi.groupby(level=0)
print("按第一级索引分组并标准化:")
normalized_result = grouped_level0.transform(lambda x: (x - x.mean()) / x.std())
print(normalized_result)
执行结果:
=== 示例1: 基本用法 - 标准化数据 ===
原始数据:
A 10
A 20
B 30
B 40
C 50
C 60
dtype: int64
对每个分组应用 mean 函数进行标准化:
A 15.0
A 15.0
B 35.0
B 35.0
C 55.0
C 55.0
dtype: float64
减去分组均值实现组内标准化:
A -5.0
A 5.0
B -5.0
B 5.0
C -5.0
C 5.0
dtype: float64
=== 示例2: 使用自定义函数 ===
将每个元素转换为占组总和的比例:
A 0.333333
A 0.666667
B 0.428571
B 0.571429
C 0.454545
C 0.545455
dtype: float64
=== 示例3: 百分位数排名 ===
值序列:
X 1
X 5
Y 2
Y 8
X 3
X 9
Y 4
Y 7
dtype: int64
计算每组内的百分位数排名:
X 0.25
X 0.75
Y 0.25
Y 1.00
X 0.50
X 1.00
Y 0.50
Y 0.75
dtype: float64
=== 示例4: 填充缺失值 ===
包含缺失值的数据:
A 1.0
A NaN
B 3.0
B NaN
C 5.0
C 6.0
dtype: float64
使用每组的均值填充缺失值:
A 1.0
A 1.0
B 3.0
B 3.0
C 5.0
C 6.0
dtype: float64
=== 示例5: 数据去趋势 ===
时间序列数据:
Group1 10
Group1 15
Group1 20
Group2 25
Group2 30
Group2 35
dtype: int64
去除每组线性趋势:
Group1 -5.0
Group1 0.0
Group1 5.0
Group2 -5.0
Group2 0.0
Group2 5.0
dtype: float64
=== 示例6: 复杂金融数据示例 ===
月度收益率数据:
Tech: 2.00%
Tech: -1.00%
Finance: 3.00%
Finance: -2.00%
Tech: 4.00%
Finance: 1.00%
Tech: -3.00%
Finance: 2.00%
Tech: 1.00%
Finance: -1.00%
Tech: 3.00%
Finance: 2.00%
将收益率标准化为每行业的Z分数:
Tech -0.2673
Tech -1.3363
Finance 0.8909
Finance -1.3363
Tech 0.2673
Finance -0.4454
Tech -1.8704
Finance 0.4454
Tech -0.8018
Finance -0.8909
Tech 0.8018
Finance 0.0000
dtype: float64
=== 示例7: 分组排序 ===
学生分数:
Class_A 85
Class_A 92
Class_B 78
Class_B 95
Class_A 88
Class_B 90
dtype: int64
每班内学生的相对排名:
Class_A 3.0
Class_A 1.0
Class_B 3.0
Class_B 1.0
Class_A 2.0
Class_B 2.0
dtype: float64
=== 示例8: 移动窗口变换 ===
数据序列:
Group1 1
Group1 2
Group1 3
Group1 4
Group2 5
Group2 6
Group2 7
Group2 8
dtype: int64
计算每组内的累积和:
Group1 1
Group1 3
Group1 6
Group1 10
Group2 5
Group2 11
Group2 18
Group2 26
dtype: int64
=== 示例9: 条件变换 ===
销售数据:
North 100
North 150
South 200
South 120
East 180
East 160
dtype: int64
高于组均值的标记为1,否则为0:
North 0
North 1
South 1
South 0
East 1
East 0
dtype: int64
=== 示例10: 多级索引变换 ===
多级索引数据:
A 1 10
2 20
B 1 30
2 40
C 1 50
2 60
dtype: int64
按第一级索引分组并标准化:
A 1 -0.707107
2 0.707107
B 1 -0.707107
2 0.707107
C 1 -0.707107
2 0.707107
dtype: float64
关键要点
transform()方法保持原始数据的形状,返回与输入 Series 索引相同的 Series- 与
apply()和agg()不同,transform()将聚合结果广播回原始数据的每个元素 - 常用于数据标准化、缺失值填充、去趋势等操作
- 支持字符串形式的函数名、自定义函数和 lambda 表达式
- 在金融数据分析中广泛用于行业中性化、标准化等预处理步骤
- 可以实现复杂的条件变换和分组操作
- 与原始数据保持严格的对齐关系,便于后续分析
- 支持多级索引分组变换
- 在数据清洗和特征工程中非常有用
- 性能通常优于手动循环实现的等效操作
988

被折叠的 条评论
为什么被折叠?



