
本文介绍如何基于分组,将 dataframe 中指定列的每组元素两两组合,生成对应的新列(如 b_m → b_m1/b_m2),并自动剔除单元素组,高效实现类似 itertools.combinations 的展开逻辑。
本文介绍如何基于分组,将 dataframe 中指定列的每组元素两两组合,生成对应的新列(如 b_m → b_m1/b_m2),并自动剔除单元素组,高效实现类似 itertools.combinations 的展开逻辑。
在数据分析中,常需将同一分组内的多个观测值两两配对,用于计算相似性、构建边关系或生成交互特征。例如,给定按 Group 分组的数据,希望对每组内 B_m 和 B_n 列的所有元素进行无序不重复两两组合(即 C(n,2)),并将结果分别展开为 B_m1/B_m2 和 B_n1/B_n2 四列,同时保留原始分组键和其他非目标列。
核心思路是:以非目标列为分组依据,对每个目标列独立执行两两组合,再横向拼接结果。Pandas 的 groupby.apply 配合 itertools.combinations 是最简洁高效的实现方式。
以下是完整可运行代码:
import pandas as pd
from itertools import combinations
# 构建示例数据
df = pd.DataFrame(
data=[
[0, 4, 7, -1, 0.9],
[0, 4, 7, 0, 0.3],
[0, 4, 7, 1, 0.2],
[1, 3, 3, 1, 0.5],
[1, 3, 3, 0, 0.2],
[2, 1, 8, 0, 0.6],
],
columns=['Group', 'A_x', 'A_y', 'B_m', 'B_n'],
)
# 定义目标列(需展开为 pair 的列)与分组列
cols_to_pair = ['B_m', 'B_n']
group_cols = list(df.columns.difference(cols_to_pair, sort=False)) # ['Group', 'A_x', 'A_y']
# 分组后对每列独立展开两两组合,并重命名新列
g = df.groupby(group_cols, sort=False)
result = pd.concat([
g[c].apply(lambda x: pd.DataFrame(list(combinations(x, r=2))))
.rename(columns=lambda i: f'{c}{i+1}')
for c in cols_to_pair
], axis=1).reset_index(drop=False)
# 按分组列排序并重置索引(可选,提升可读性)
result = result.sort_values(group_cols).reset_index(drop=True)
print(result)
输出结果:
Group A_x A_y B_m1 B_m2 B_n1 B_n2 0 0 4 7 -1.0 0.0 0.9 0.3 1 0 4 7 -1.0 1.0 0.9 0.2 2 0 4 7 0.0 1.0 0.3 0.2 3 1 3 3 1.0 0.0 0.5 0.2
✅ 关键说明与注意事项:
- 自动过滤单元素组:combinations(x, 2) 对长度
- 列名自动映射:rename(columns=lambda i: f'{c}{i+1}') 将组合元组的第 0、1 位转为 B_m1/B_m2 等;
- 性能提示:该方法避免显式循环和逐行构造,充分利用 Pandas 向量化分组操作,适用于万级分组规模;
- 扩展性强:若需三元组,仅需将 r=2 改为 r=3,列名逻辑同步调整即可;
- 注意 sort=False 参数:防止 groupby 默认重排序打乱原始顺序(尤其当分组列含重复但顺序敏感时)。
此方案兼具可读性、健壮性与扩展性,是处理“分组内成对展开”类任务的标准实践。











