
本文介绍如何使用 pd.melt() 高效地将多个 Applct_Id 列(如 Applct_Id_1/2/3)展开为长格式,过滤非空值,并保留原始 APPN、Name、Age 等字段,适用于 40 万级数据量的生产场景。
本文介绍如何使用 `pd.melt()` 高效地将多个 applct_id 列(如 applct_id_1/2/3)展开为长格式,过滤非空值,并保留原始 appn、name、age 等字段,适用于 40 万级数据量的生产场景。
在实际数据分析中,常遇到“宽表中多个同类标识列(如 Applct_Id_1 ~ Applct_Id_3)需按非空值展开为独立行”的需求。例如,单个申请号(APPN)关联多个申请人 ID,需为每个有效 ID 复制一行基础信息(如姓名、年龄),形成一对多关系。直接循环或 apply() 易导致性能瓶颈,而 pd.melt() 是 Pandas 原生优化的向量化方案,特别适合处理数十万乃至百万级记录。
✅ 推荐方案:melt + dropna 两步法
核心思路是:将目标 ID 列(value_vars)“熔化”为单列,再剔除空值,最后清理冗余列。该流程全程向量化,无 Python 循环,内存友好且执行迅速。
import pandas as pd
# 构造示例数据(注意:原问题中 'Applct_Id_3' 第5个值缺失,已补全为 None 以保证 DataFrame 合法)
df = 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], # 修正:原问题此处少一个值,补 None
'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'],
'Age': [25, 30, 35, 40, 45, 50]
})
# 步骤1:熔化指定ID列,保留关键标识列
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,并删除辅助列
result = (melted
.dropna(subset=['ID_Number']) # 更明确:仅对 ID_Number 列判空
.drop(columns=['ID_Type']) # 移除不再需要的列
.sort_values(['APPN', 'ID_Number'], ignore_index=True) # 可选:提升可读性
)
print(result)
输出示例:
APPN Name Age ID_Number 0 1001 Alice 25 A 1 1001 Alice 25 W 2 1002 Bob 30 B 3 1002 Bob 30 E 4 1002 Bob 30 Z 5 1003 Charlie 35 C 6 1003 Charlie 35 F 7 1004 David 40 D 8 1004 David 40 Y 9 1005 Eve 45 G 10 1006 Frank 50 F
⚠️ 关键注意事项
- 空值处理:dropna(subset=['ID_Number']) 比布尔索引 melted['ID_Number'].notna() 更健壮,尤其当列含 NaN、None 或 pd.NA 混合时;
- 性能优化:melt 默认不拷贝数据,配合 dropna 和 drop 的链式调用(使用 inplace=False)可减少中间对象内存占用;对 40 万行数据,典型耗时
-
扩展性:若 ID 列名有规律(如 'Applct_Id_' + str(i)),可用列表推导式动态生成 value_vars:
id_cols = [f'Applct_Id_{i}' for i in range(1, 4)] # → ['Applct_Id_1', 'Applct_Id_2', 'Applct_Id_3'] -
去重与计数:如需仅保留含 ≥2 个 ID 的 APPN(按题意“仅复制多 ID 记录”),可在熔化后分组统计:
appn_counts = result.groupby('APPN').size() target_appns = appn_counts[appn_counts >= 2].index final_result = result[result['APPN'].isin(target_appns)]
此方法兼顾简洁性、可读性与高性能,是 Pandas 生态中处理“宽转长 + 条件展开”任务的标准实践。











