重构Pandas DataFrame:将行转换为参与者分列的指定格式
解决Pandas DataFrame格式转换问题
这是个典型的宽表转长表再转宽表的需求,用Pandas的melt和pivot方法就能完美实现,我给你一步步拆解操作:
步骤1:构造示例数据(如果你的DataFrame已经存在,这步可以跳过)
先把你提供的示例数据转换成Pandas DataFrame:
import pandas as pd data = { 'itemname': ['E1', 'E1', 'E1', 'A1', 'A1', 'A1', 'Foo', 'Foo', 'Foo'], 'participant': [1, 2, 3, 1, 2, 3, 1, 2, 3], 's0': ['no', 'no', 'no', 'no', 'no', 'yes', 'no', 'yes', 'no'], 's1': ['no', 'no', 'no', 'no', 'no', 'no', 'no', 'no', 'yes'], 's2': ['no', 'yes', 'no', 'no', 'no', 'no', 'no', 'no', 'yes'], 's3': ['yes', 'no', 'yes', 'yes', 'yes', 'no', 'yes', 'no', 'yes'] } df = pd.DataFrame(data)
步骤2:执行格式转换
我们可以用链式操作一步完成转换,每一步的作用我都标出来了:
result_df = ( # 第一步:把s0-s3这些宽列转成长格式,保留itemname和participant作为标识列 df.melt(id_vars=['itemname', 'participant'], var_name='s_col', value_name='response') # 第二步:将participant转成列,用itemname+s_col作为行索引 .pivot(index=['itemname', 's_col'], columns='participant', values='response') # 去掉列的索引名称(默认是participant,不需要显示) .rename_axis(columns=None) # 重置索引,把复合索引转成普通列 .reset_index() # 合并itemname和s_col列,生成新的itemname(比如E1_s0) .assign(itemname=lambda x: x['itemname'] + '_' + x['s_col']) # 删掉临时的s_col列 .drop(columns='s_col') # 重命名participant列,改成你想要的participant_1/2/3格式 .rename(columns={1: 'participant_1', 2: 'participant_2', 3: 'participant_3'}) # 按itemname排序,和目标格式顺序一致 .sort_values('itemname') # 重置行索引,去掉排序后的索引混乱 .reset_index(drop=True) )
验证结果
执行完后打印print(result_df),就能得到你想要的格式:
| itemname | participant_1 | participant_2 | participant_3 | |
|---|---|---|---|---|
| 0 | A1_s0 | no | no | yes |
| 1 | A1_s1 | no | no | no |
| 2 | A1_s2 | no | no | no |
| 3 | A1_s3 | yes | yes | no |
| 4 | E1_s0 | no | no | no |
| 5 | E1_s1 | no | no | no |
| 6 | E1_s2 | no | yes | no |
| 7 | E1_s3 | yes | no | yes |
| 8 | Foo_s0 | no | yes | no |
| 9 | Foo_s1 | no | no | yes |
| 10 | Foo_s2 | no | no | yes |
| 11 | Foo_s3 | yes | no | yes |
这个方法的好处是逻辑清晰,不管你有多少个s*列或者多少个participant,都能自动适配,不需要硬编码列名~
内容的提问来源于stack exchange,提问作者user9397006
相关产品推荐
相关产品推荐

