如何用Pandas将无日期值列名的宽格式数据转为长格式?
宽格式转长格式解决方案
问题背景
现有宽格式数据集(日期直接作为列标题,无单独的日期/值列名):
RIC Company 31/12/2021 31/12/2020 31/12/2019 ABC ABC ltd 0.77 0.75 0.66 XYZ XYZ ltd 7846.43 na 6607.29 CDF CDF ltd 191.14 127.74 63.92
需要转换为如下长格式:
RIC Company Date Value ABC ABC ltd 31/12/2021 0.77 ABC ABC ltd 31/12/2020 0.75 ABC ABC ltd 31/12/2019 0.66 XYZ XYZ ltd 31/12/2021 7846.43 XYZ XYZ ltd 31/12/2020 na XYZ XYZ ltd 31/12/2019 6607.29 CDF CDF ltd 31/12/2021 191.14 CDF CDF ltd 31/12/2020 127.74 CDF CDF ltd 31/12/2019 63.92
尝试pd.melt、pd.wide_to_long、pyjanitor的pivot_longer均未成功,其中pyjanitor的尝试代码报错:
(df .pivot_longer( index = ['RIC','Company'], names_to = ('.value', 'Date'), sort_by_appearance=True) )
错误原因
pyjanitor代码中names_to = ('.value', 'Date')的用法不匹配场景:该参数组合适用于列名包含前缀+日期的情况(如Value_31/12/2021),但当前列名直接是日期,无需拆分前缀,因此配置错误导致报错。
解决方法
方法1:使用pd.melt(最直观)
直接指定标识列、日期列名和值列名:
import pandas as pd # 构造示例DataFrame data = { 'RIC': ['ABC', 'XYZ', 'CDF'], 'Company': ['ABC ltd', 'XYZ ltd', 'CDF ltd'], '31/12/2021': [0.77, 7846.43, 191.14], '31/12/2020': [0.75, 'na', 127.74], '31/12/2019': [0.66, 6607.29, 63.92] } df = pd.DataFrame(data) # 转换长格式 long_df = pd.melt( df, id_vars=['RIC', 'Company'], var_name='Date', value_name='Value' ) print(long_df)
输出结果完全符合目标格式。
方法2:使用pd.wide_to_long
先给日期列添加统一前缀,再进行转换:
# 重命名日期列,添加前缀 df_renamed = df.rename(columns={col: f'Value_{col}' for col in df.columns if '/' in col}) # 转换长格式 long_df = pd.wide_to_long( df_renamed, stubnames=['Value'], i=['RIC', 'Company'], j='Date', sep='_' ).reset_index() print(long_df)
方法3:使用pyjanitor的正确pivot_longer用法
无需拆分列名,直接指定日期列和值列的名称:
import janitor long_df = df.pivot_longer( index=['RIC', 'Company'], names_to='Date', values_to='Value', sort_by_appearance=True ) print(long_df)
此方法直接将所有非标识列(日期列)转为Date列,对应的值转为Value列,完美匹配需求。
内容的提问来源于stack exchange,提问作者non_linear
相关产品推荐
相关产品推荐

