如何将带有特殊命名规则的多时段问卷数据宽格式DataFrame转换为长格式?
我懂你的困扰——这种变量命名不统一的宽表转长确实有点绕,不过我们可以用两种方法搞定,一种灵活通用,一种直观好懂,看看哪个更适合你:
方案一:用正则匹配+melt()+pivot()(通用高效)
这种方法适合变量较多的情况,通过正则表达式自动识别每个字段对应的测量时段和问卷指标:
首先先复现你的示例数据:
import pandas as pd df = pd.DataFrame({ 'code': ['CAPQ', 'BANI'], 'PANAS_1': [4, 2], 'PANAS_2': [3, 3], 'PANAS1_1': [1, 4], 'PANAS1_2': [5, 4], 'PANAS2_1': [2, 3], 'PANAS2_2': [4, 2] })
然后执行转换步骤:
# 第一步:把所有问卷变量转成长格式,临时存储变量名和对应值 df_melted = df.melt(id_vars='code', var_name='temp_var', value_name='value') # 第二步:从临时变量名里识别测量时段 # 匹配三种命名模式:PANAS_*对应时段1,PANAS1_*对应时段2,PANAS2_*对应时段3 df_melted['timeslot'] = df_melted['temp_var'].replace( {r'PANAS_.*': 1, r'PANAS1_.*': 2, r'PANAS2_.*': 3}, regex=True ) # 第三步:提取问卷的指标后缀(比如_1、_2) df_melted['indicator'] = df_melted['temp_var'].str.extract(r'_(.*)$') # 第四步:把指标转回宽格式,得到最终结构 df_final = df_melted.pivot( index=['code', 'timeslot'], columns='indicator', values='value' ).reset_index() # 重命名列名,恢复成你想要的PANAS_1、PANAS_2 df_final.columns = ['code', 'timeslot', 'PANAS_1', 'PANAS_2'] print(df_final)
执行后就能得到你想要的长格式结果了。
方案二:分时段提取后合并(直观易理解)
如果你的变量不多,直接拆分每个时段的数据再合并会更清晰:
# 提取第一个时段的数据,添加timeslot标识 df_slot1 = df[['code', 'PANAS_1', 'PANAS_2']].assign(timeslot=1) # 提取第二个时段的数据,重命名列名统一格式后添加timeslot df_slot2 = df[['code', 'PANAS1_1', 'PANAS1_2']].rename( columns={'PANAS1_1': 'PANAS_1', 'PANAS1_2': 'PANAS_2'} ).assign(timeslot=2) # 提取第三个时段的数据,同样重命名列名并添加timeslot df_slot3 = df[['code', 'PANAS2_1', 'PANAS2_2']].rename( columns={'PANAS2_1': 'PANAS_1', 'PANAS2_2': 'PANAS_2'} ).assign(timeslot=3) # 合并三个时段的数据,按code和timeslot排序 df_final = pd.concat([df_slot1, df_slot2, df_slot3], ignore_index=True)\ .sort_values(by=['code', 'timeslot'])\ .reset_index(drop=True) print(df_final)
这个方法逻辑简单,新手也能快速上手,要是以后加其他问卷变量,只要复制对应时段的提取代码,调整列名就行。
内容的提问来源于stack exchange,提问作者Chiara
相关产品推荐
相关产品推荐

