如何将带Min/Max/Unit行的网格状Pandas DataFrame转换为标准化扁平表
Pandas 宽表转标准长表高效实现方案
以下方案完全基于Pandas内置的矢量化操作,避免了嵌套循环的性能损耗,数据量越大性能优势越明显:
import pandas as pd # 你提供的原始df构造代码 df_raw = pd.DataFrame({ 'Name':['FIELD_A', 'FIELD_B', 'FIELD_C', 'FIELD_D'], 'Min':[None, 100, -1.0, 0], 'Max':[None, 500, 0.75, 500], 'Unit':[None, 'ms', '%', 'cm'], '1':['2020/01/21',150,0.8,200], '2':['2020/01/22',160,0.7,210], '3':['2020/01/23',170,0.6,220], '4':['2020/01/24',180,0.5,230], '5':['2020/01/25',190,0.4,240] }).transpose() # ---------------- 转换逻辑开始 ---------------- # 1. 修正列名,把第一行的字段名设为列名 df_raw.columns = df_raw.iloc[0] df_raw = df_raw[1:].reset_index(names='row_type') # 2. 拆分元数据(Min/Max/Unit)和业务数据,分别转长表 ## 处理元数据:得到每个FIELD对应的Min/Max/Unit映射 meta_df = df_raw[df_raw['row_type'].isin(['Min', 'Max', 'Unit'])]\ .melt(id_vars='row_type', var_name='FIELD', value_name='meta_val')\ .pivot(index='FIELD', columns='row_type', values='meta_val')\ .reset_index() meta_df['FIELD'] = meta_df['FIELD'].str.split('_').str[-1] ## 处理业务数据:得到每个No.每个FIELD对应的VALUE data_df = df_raw[~df_raw['row_type'].isin(['Min', 'Max', 'Unit'])]\ .melt(id_vars='row_type', var_name='FIELD', value_name='VALUE')\ .rename(columns={'row_type':'No.'}) data_df['FIELD'] = data_df['FIELD'].str.split('_').str[-1] # 3. 关联元数据和业务数据,得到最终结果 result = pd.merge(data_df, meta_df, on='FIELD', how='left')\ [['No.', 'FIELD', 'VALUE', 'Min', 'Max', 'Unit']] # 可选:如果需要把空值替换为字符串NONE,可执行以下代码 # result = result.fillna('NONE') # ---------------- 转换逻辑结束 ----------------
核心逻辑说明
- 先修正原始错位的列名,拆分出元数据和业务数据两部分
- 用
melt函数把宽表转长表,替代内层循环的逐行取值操作 - 用
pivot把元数据转成字段-属性的映射表,替代外层循环的逐字段取元数据操作 - 最后用
merge一次性关联所有字段的元数据,完成转换
内容的提问来源于stack exchange,提问作者Hsins
相关产品推荐
相关产品推荐

