Python Pandas 将堆叠格式列转换为长表格式实现方法
复合表头CSV转长表实现方案
核心问题出在原始文件是三层堆叠表头,直接用melt/pivot/transpose硬转没有先规整表头信息,自然拿不到正确结果。按以下步骤处理即可:
处理逻辑
- 先拆分三层表头:最上层年份是读入DF默认的列名(空值列被pandas自动命名为Unnamed),中间层是月份、最下层是出口指标,两层都存在跨列空值,用向前填充补全每一列对应的年份、月份、指标三元组。
- 剔除前3行无效的表头、空行,提取真实业务数据,前两列固定为编码、国家。
- 先把宽表转成长表,拆分出年份、月份、指标字段,再把两个出口指标透视成独立列,最后做字段清理即可。
可直接运行的代码
import pandas as pd import numpy as np # 原始DF构造代码(读本地CSV时替换这部分为pd.read_csv即可) df = pd.DataFrame([{'Unnamed: 0': np.nan, 'Unnamed: 1': np.nan, '2017': 'Enero', 'Unnamed: 3': np.nan, 'Unnamed: 4': 'Febrero', 'Unnamed: 5': np.nan}, {'Unnamed: 0': np.nan, 'Unnamed: 1': np.nan, '2017': 'Valor export', 'Unnamed: 3': 'Volumen export', 'Unnamed: 4': 'Valor export', 'Unnamed: 5': 'Volumen export'}, {'Unnamed: 0': np.nan, 'Unnamed: 1': np.nan, '2017': np.nan, 'Unnamed: 3': np.nan, 'Unnamed: 4': np.nan, 'Unnamed: 5': np.nan}, {'Unnamed: 0': '080390110000 SA-2017', 'Unnamed: 1': 'USA', '2017': '29200.10725', 'Unnamed: 3': '67198.189', 'Unnamed: 4': '38631.16383', 'Unnamed: 5': '87962.196'}, {'Unnamed: 0': '090390110000 SA-2017', 'Unnamed: 1': 'Mexico', '2017': '9283.79255', 'Unnamed: 3': '21638.126', 'Unnamed: 4': '9785.40009', 'Unnamed: 5': '22863.867'}, {'Unnamed: 0': '010390110000 SA-2017 ', 'Unnamed: 1': 'Canada', '2017': '8017.55675', 'Unnamed: 3': '19352.178', 'Unnamed: 4': '11137.27057', 'Unnamed: 5': '27020.428'}, {'Unnamed: 0': '070390110000 SA-2017', 'Unnamed: 1': 'Brazil', '2017': '3786.44363', 'Unnamed: 3': '8704.871', 'Unnamed: 4': '4553.70795', 'Unnamed: 5': '10583.833'}, {'Unnamed: 0': '060390110000 SA-2017', 'Unnamed: 1': 'Italy', '2017': '4809.76636', 'Unnamed: 3': '12411.691', 'Unnamed: 4': '4304.02052', 'Unnamed: 5': '11198.063'}, {'Unnamed: 0': '000390110000 SA-2017 ', 'Unnamed: 1': 'Spain', '2017': '2290.65793', 'Unnamed: 3': '6227.269', 'Unnamed: 4': '3269.41957', 'Unnamed: 5': '9118.595'}, {'Unnamed: 0': '0990390110000 SA-2017 ', 'Unnamed: 1': 'Costa Rica', '2017': '1855.70035', 'Unnamed: 3': '4687.714', 'Unnamed: 4': '2668.57892', 'Unnamed: 5': '6425.365'}, {'Unnamed: 0': '0040390110000 SA-2017 ', 'Unnamed: 1': 'Honduras', '2017': '1823.358', 'Unnamed: 3': '4223.521', 'Unnamed: 4': '250.2036', 'Unnamed: 5': '603.392'}]) # 1. 提取三层表头,向前填充补全跨列空值 header_year = pd.Series(df.columns).ffill() header_month = df.iloc[0].ffill().reset_index(drop=True) header_metric = df.iloc[1].reset_index(drop=True) # 2. 提取真实数据行,重命名列 data = df.iloc[3:].reset_index(drop=True) new_cols = ['编码', '国家'] for col_idx in range(2, len(header_year)): new_cols.append(f"{header_year[col_idx]}_{header_month[col_idx]}_{header_metric[col_idx]}") data.columns = new_cols # 3. 宽表转长表,拆分字段后透视指标 long_df = data.melt(id_vars=['编码', '国家'], var_name='col_meta', value_name='value') long_df[['年份', '月份', '指标']] = long_df['col_meta'].str.split('_', expand=True) long_df = long_df.pivot( index=['编码', '国家', '年份', '月份'], columns='指标', values='value' ).reset_index() # 4. 字段清理:去除编码前后空格、数值转浮点 long_df['编码'] = long_df['编码'].str.strip() long_df[['Valor export', 'Volumen export']] = long_df[['Valor export', 'Volumen export']].astype(float)
说明
- 最终输出的
long_df就是要求的长表格式,每行对应唯一的国家、编码、年份、月份组合,Valor export和Volumen export各为独立列,列顺序可按需调整。 - 如果原始CSV包含更多年份、月份,只要表头结构和样例一致(年份、月份各跨2列,第三层表头为两个出口指标),代码无需修改可直接运行,向前填充逻辑会自动补全所有列的属性。
内容的提问来源于stack exchange,提问作者JoshPickel
相关产品推荐
相关产品推荐

