本文介绍如何使用 pd.melt() 高效地将多个 Applct_Id 列(如 Applct_Id_1/2/3)展开为长格式,过滤非空值并保留原始关键字段,适用于 40 万级数据量的生产场景。
本文介绍如何使用 `pd.melt()` 高效地将多个 applct_id 列(如 applct_id_1/2/3)展开为长格式,过滤非空值并保留原始关键字段,适用于 40 万级数据量的生产场景。
在实际数据分析中,常遇到宽表结构:同一主键(如 APPN)下存在多个同质但编号不同的字段(如 Applct_Id_1, Applct_Id_2, Applct_Id_3),而业务要求将每个非空 ID 视为一条独立记录,并复用其关联属性(如 Name, Age)。直接循环或 apply() 逐行处理在 40 万数据量下性能极差;正确解法是利用 Pandas 的向量化熔解(melting)操作——它底层基于 NumPy,内存友好且执行迅速。
首先定义原始数据(注意:示例中 'Applct_Id_3' 第五行应为 None 以保持列长度一致,已修正):
import pandas as pdimport numpy as npdf = pd.DataFrame({ 'APPN': [1001, 1002, 1003, 1004, 1005, 1006], 'Applct_Id_1': ['A', 'B', 'C', 'D', None, 'F'], 'Applct_Id_2': [None, 'E', 'F', None, 'G', None], 'Applct_Id_3': ['W', 'Z', None, 'Y', None, None], # 修正:补全为6个元素 'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'], 'Age': [25, 30, 35, 40, 45, 50]})
接着执行高效熔解流程:
# 1. 熔解:将 Applct_Id_* 列转为长格式,保留 APPN/Name/Age 作为标识列melted = df.melt( id_vars=['APPN', 'Name', 'Age'], value_vars=['Applct_Id_1', 'Applct_Id_2', 'Applct_Id_3'], var_name='ID_Type', value_name='ID_Number')# 2. 过滤:仅保留 ID_Number 非空的行(自动排除 None/np.nan)melted = melted[melted['ID_Number'].notna()]# 3. 清理:删除冗余的 ID_Type 列(因业务无需区分来源列)melted = melted.drop(columns=['ID_Type'])# 4. (可选)排序:按 APPN 和 ID_Number 提升可读性与后续分组效率melted = melted.sort_values(['APPN', 'ID_Number'], ignore_index=True)print(melted.head(10))
输出结果(节选):
APPN Name Age ID_Number0 1001 Alice 25 A1 1001 Alice 25 W2 1002 Bob 30 B3 1002 Bob 30 E4 1002 Bob 30 Z5 1003 Charlie 35 C6 1003 Charlie 35 F7 1004 David 40 D8 1004 David 40 Y9 1005 Eve 45 G
result = (df.melt(...).query("ID_Number.notna()").drop('ID_Type', axis=1) .sort_values(['APPN', 'ID_Number']).reset_index(drop=True))
# 统计每个 APPN 的 ID 数量,保留 ≥2 的 APPNappn_counts = melted.groupby('APPN').size()valid_appns = appn_counts[appn_counts >= 2].indexfinal_df = melted[melted['APPN'].isin(valid_appns)].copy()
该方案兼顾简洁性、可维护性与工业级性能,是处理此类“一主多从”宽表展开任务的标准实践。