如何用Python的Pandas包将时间序列数据从宽格式转长格式?
宽格式时间序列转长格式并生成Time变量
我有一组宽格式的时间序列数据,需要转换为长格式来做数据分析和数据集合并。数据中A_0代表指标A在时间0的取值,A_15代表时间15的取值,以此类推。
原始数据代码:
import pandas as pd df_wide = pd.DataFrame({'Subject': ['AA', 'BB', 'CC', 'DD'], 'A_0': [1, 2, 3, 4], 'A_15': [2, 3, 4, 5], 'A_30': [3, 4, 5, 6], 'B_0': [1, 2, 3, 4], 'B_15': [2, 3, 4, 5], 'B_30': [3, 4, 5, 6], 'C_0': [1, 2, 3, 4], 'C_15': [2, 3, 4, 5], 'C_30': [3, 4, 5, 6] } )
原始数据展示:
Subject A_0 A_15 A_30 B_0 B_15 B_30 C_0 C_15 C_30 0 AA 1 2 3 1 2 3 1 2 3 1 BB 2 3 4 2 3 4 2 3 4 2 CC 3 4 5 3 4 5 3 4 5 3 DD 4 5 6 4 5 6 4 5 6
期望转换后的长格式(带Time变量):
目标数据代码:
df_long = pd.DataFrame({'Subject': ['AA', 'AA', 'AA', 'BB', 'BB', 'BB', 'CC', 'CC', 'CC', 'DD', 'DD', 'DD'], 'Time': [0, 15, 30, 0, 15, 30, 0, 15, 30, 0, 15, 30], 'A': [1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6], 'B': [1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6], 'C': [1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6], })
目标数据展示:
Subject Time A B C 0 AA 0 1 1 1 1 AA 15 2 2 2 2 AA 30 3 3 3 3 BB 0 2 2 2 4 BB 15 3 3 3 5 BB 30 4 4 4 6 CC 0 3 3 3 7 CC 15 4 4 4 8 CC 30 5 5 5 9 DD 0 4 4 4 10 DD 15 5 5 5 11 DD 30 6 6 6
我试过pivot和melt但没搞明白怎么生成Time变量,求帮助。
解决方案
可以通过**melt+列拆分+pivot**三步完成转换,逻辑清晰易理解:
步骤1:用melt将宽格式转为中间长格式
先把所有指标列(A_0、B_15这类)转为行,保留Subject作为标识列:
# melt转换,id_vars是保留的列,value_vars是要转成行的列 df_melt = df_wide.melt(id_vars='Subject', var_name='Metric_Time', value_name='Value')
转换后df_melt的结构:
Subject Metric_Time Value 0 AA A_0 1 1 BB A_0 2 2 CC A_0 3 3 DD A_0 4 4 AA A_15 2 ...
步骤2:拆分Metric_Time列为Metric和Time
把Metric_Time列按下划线_拆分,得到指标名(A/B/C)和时间值(0/15/30):
# 拆分列,expand=True表示拆成两列 df_melt[['Metric', 'Time']] = df_melt['Metric_Time'].str.split('_', expand=True) # 把Time转为数值类型 df_melt['Time'] = df_melt['Time'].astype(int)
拆分后df_melt新增了Metric和Time列:
Subject Metric_Time Value Metric Time 0 AA A_0 1 A 0 1 BB A_0 2 A 0 2 CC A_0 3 A 0 3 DD A_0 4 A 0 4 AA A_15 2 A 15 ...
步骤3:用pivot转回宽格式(按Subject和Time分组)
现在把Metric列转成列名,Value作为对应值,得到最终的长格式:
df_long = df_melt.pivot(index=['Subject', 'Time'], columns='Metric', values='Value').reset_index() # 去掉列名的索引名称 df_long.columns.name = None
最终输出的df_long就和你期望的格式完全一致了。
一步到位的简化代码
如果想把步骤合并成一行,可以这样写:
df_long = (df_wide.melt(id_vars='Subject', var_name='Metric_Time', value_name='Value') .assign(**{'Metric': lambda x: x['Metric_Time'].str.split('_').str[0], 'Time': lambda x: x['Metric_Time'].str.split('_').str[1].astype(int)}) .pivot(index=['Subject', 'Time'], columns='Metric', values='Value') .reset_index() .rename_axis(None, axis=1))
内容的提问来源于stack exchange,提问作者CB_datarookie
相关产品推荐
相关产品推荐

