如何在Pandas DataFrame拆堆(unstack)时生成所有值的笛卡尔积组合
解决同一计划p下多键c的v值笛卡尔积转换问题
我来帮你搞定这个需求!核心是要在生成笛卡尔积组合的同时,保留每个值对应的c键名称,这样才能顺利转成你想要的宽表格式。下面给你两种分步实现的方法,都能达到目标:
方法1:手动构建笛卡尔积行(直观易懂)
这种方法先把数据整理成字典结构,再遍历生成所有组合,同时绑定c的名称:
步骤1:导入库并准备示例数据
import pandas as pd from itertools import product x = pd.DataFrame({ 'p':[5, 5, 5, 5, 6, 6], 'c':['alpha', 'alpha', 'beta', 'beta', 'gaga', 'gaga'], 'v':['orange', 'apple', 'football', 'rugby', 'cake', 'pie'] })
步骤2:按p分组,整理成{ c: [v列表] }的字典
这一步把每个p对应的所有c和其v值列表存起来,方便后续生成组合:
# 按p分组,每个p下得到{c: [v1, v2,...]}的嵌套字典 grouped_dict = x.groupby('p').apply( lambda g: g.groupby('c')['v'].apply(list).to_dict() ).to_dict()
此时grouped_dict的结构是:
{ 5: {'alpha': ['orange', 'apple'], 'beta': ['football', 'rugby']}, 6: {'gaga': ['cake', 'pie']} }
步骤3:生成笛卡尔积并构建结果行
遍历每个p,用product生成所有v值的组合,同时把每个组合的元素和对应的c绑定成字典:
result_rows = [] for p, c_v_dict in grouped_dict.items(): # 获取当前p下的所有c名称和对应的v列表 c_names = list(c_v_dict.keys()) v_lists = list(c_v_dict.values()) # 生成所有v值的笛卡尔积 for combo in product(*v_lists): # 拼接成包含p和各c对应值的行字典 row = {'p': p} row.update(zip(c_names, combo)) result_rows.append(row)
步骤4:转成目标DataFrame
final_df = pd.DataFrame(result_rows)
最终输出的final_df就是你想要的格式:
p alpha beta gaga 0 5 orange football NaN 1 5 orange rugby NaN 2 5 apple football NaN 3 5 apple rugby NaN 4 6 NaN NaN cake 5 6 NaN NaN pie
方法2:用Pandas的交叉合并(更贴合Pandas风格)
这种方法利用Pandas的merge(how='cross')来自动生成笛卡尔积,不需要手动遍历:
步骤1:按p和c拆分并重命名列
先把每个(p,c)组的v列重命名为对应的c名称:
# 按p和c分组,将每个组的v列重命名为c的名称 dfs_by_pc = x.groupby(['p', 'c']).apply( lambda g: g[['p', 'v']].rename(columns={'v': g.name[1]}) ).reset_index(drop=True)
步骤2:按p分组做交叉合并
用reduce把每个p下的所有子DataFrame做交叉合并,生成笛卡尔积:
from functools import reduce final_df = dfs_by_pc.groupby('p').apply( lambda g: reduce(lambda left, right: pd.merge(left, right, on='p', how='cross'), g) ).reset_index(drop=True)
这个方法得到的结果和方法1完全一致,而且全程用Pandas原生操作,适合习惯Pandas语法的场景。
两种方法都能完美处理你说的扩展场景:比如p=7时alpha有2个值、beta有3个值、gaga有4个值,会自动生成2×3×4=24条组合记录。
内容的提问来源于stack exchange,提问作者manoelpqueiroz
相关产品推荐
相关产品推荐

