使用Pandas按Class对表格进行部分逆透视的技术实现请求
使用Pandas实现部分逆透视(Partially Unpivot)操作
先明确下需求:我们需要把原始表格中按Class字段拆分的年份数据(2017、2018),合并到同一ID的行中,生成带Class后缀的年份列(比如2017A、2018B),同时保留ID、Class和Type字段。
原始数据表格
| ID | Class | Type | 2017 | 2018 |
|---|---|---|---|---|
| 12A | A | Net | 1 | 7 |
| 12B | A | Gross | NaN | 8 |
| 12A | B | Net | 3 | 9 |
| 12B | B | Gross | 4 | 10 |
| 13A | A | Net | 5 | 11 |
| 13C | B | Net | 6 | 5 |
期望结果表格
| ID | Class | Type | 2017A | 2018A | 2017B | 2018B |
|---|---|---|---|---|---|---|
| 12A | A | Net | 1 | 7 | 3 | 9 |
| 12B | A | Gross | NaN | 8 | 4 | 10 |
| 13A | A | Net | 5 | 11 | NaN | NaN |
| 13C | B | Net | NaN | NaN | 6 | 5 |
具体实现步骤(Pandas代码)
我把整个过程拆成了几个清晰的步骤,方便理解和调试:
1. 加载原始数据
首先我们把原始数据转换成Pandas的DataFrame:
import pandas as pd import numpy as np # 构造原始数据 raw_data = { 'ID': ['12A', '12B', '12A', '12B', '13A', '13C'], 'Class': ['A', 'A', 'B', 'B', 'A', 'B'], 'Type': ['Net', 'Gross', 'Net', 'Gross', 'Net', 'Net'], '2017': [1, np.nan, 3, 4, 5, 6], '2018': [7, 8, 9, 10, 11, 5] } df = pd.DataFrame(raw_data)
2. 转换成长格式(Melt)
我们先把固定的年份列(2017、2018)转成长格式,这样方便后续和Class字段组合:
# 将年份列转为长格式,保留ID和Class作为标识 melted_df = df.melt( id_vars=['ID', 'Class'], value_vars=['2017', '2018'], var_name='Year', value_name='Value' )
3. 生成新的年份- Class列名
把年份和Class拼接成目标中的新列名(比如2017A、2018B):
# 组合年份和Class,生成新的列名前缀 melted_df['Year_Class'] = melted_df['Year'] + melted_df['Class']
4. 透视回宽格式(Pivot)
现在把长格式的数据透视回宽格式,每个ID对应一行,新的年份- Class作为列:
# 透视成宽格式,ID作为唯一标识 pivoted_df = melted_df.pivot( index='ID', columns='Year_Class', values='Value' ).reset_index()
5. 合并元数据(Class、Type)
因为同一个ID的Type是唯一的,Class我们取该ID首次出现的值(和目标表格一致),把这些元数据合并到透视后的结果中:
# 获取每个ID对应的Class和Type(保留第一条记录的值) id_metadata = df.drop_duplicates(subset='ID')[['ID', 'Class', 'Type']] # 合并元数据和透视后的年份数据 final_df = pd.merge(id_metadata, pivoted_df, on='ID', how='left')
6. 调整列顺序
最后调整列的顺序,和期望结果完全匹配:
# 按目标表格的列顺序重新排列 final_df = final_df[['ID', 'Class', 'Type', '2017A', '2018A', '2017B', '2018B']] # 查看结果 print(final_df)
运行这段代码后,你就能得到和期望完全一致的表格了。
内容的提问来源于stack exchange,提问作者S.Gu
相关产品推荐
相关产品推荐

