本文介绍如何在 Pandas 中高效地从含字典的列中,根据另一列的键名快速提取对应值,重点推荐零开销的列表推导式方案,并对比 json_normalize 和 groupby.transform 等向量化替代方法,显著提升百万级数据处理性能。
本文介绍如何在 pandas 中高效地从含字典的列中,根据另一列的键名快速提取对应值,重点推荐零开销的列表推导式方案,并对比 `json_normalize` 和 `groupby.transform` 等向量化替代方法,显著提升百万级数据处理性能。
在实际数据分析中,常遇到一类“嵌套映射”场景:一个 DataFrame 包含一列关键词(如 words),另一列存储以该关键词为键的字典(如 dict1),需按行提取 dict1[words] 构建新列。传统写法 df.apply(lambda row: row['dict1'][row['words']], axis=1) 虽逻辑清晰,但在大数据集上性能极差——因其本质是 Python 级别逐行循环,且每次调用 apply 都需构造 Series 对象,带来巨大开销。
✅ 推荐首选:列表推导式 + dict.get()(最快、最简洁)
利用 Python 原生 zip 并行遍历两列,结合字典安全取值 .get(),天然支持 NaN 和缺失键(返回 None,Pandas 自动转为 NaN):
df['value'] = [d.get(w) for w, d in zip(df['words'], df['dict1'])]
该方案无 Pandas 开销,纯 Python 迭代,实测在 40 万行数据上仅需 127ms(比 apply 快 20 倍),代码可读性强,是兼顾性能与可维护性的最优解。
? 备选方案:json_normalize + 高级索引(适合复杂嵌套)
若字典结构统一且需复用解析结果,可先将字典列展开为 DataFrame,再通过位置索引批量提取:
import numpy as np
idx, cols = pd.factorize(df['words']) # 将 words 映射为整数索引
df['value'] = (
pd.json_normalize(df['dict1']) # 展开为宽表(列=字典键)
.reindex(cols, axis=1) # 按 words 唯一值重排列顺序
.to_numpy()[np.arange(len(df)), idx] # 行列双索引定位
)此方法在 40 万行下耗时约 811ms,优势在于可扩展至多层嵌套字典解析,但内存占用略高。
⚡ 进阶技巧:groupby.transform(语义清晰,中等性能)
利用 transform 的广播特性,在分组内对每组字典执行键查找:
df['value'] = (
df.groupby('words', as_index=False)['dict1']
.apply(lambda g: g.str[g.name]) # g.str[key] 等价于对每行 dict 取 key
.droplevel(0)
)耗时约 237ms,语法贴近自然语言(“按 words 分组,对每组 dict 列取当前组名对应的值”),适合强调业务逻辑可读性的场景。
⚠️ 注意事项与最佳实践
- 始终优先使用 [d.get(w) for w, d in zip(...)] 替代 axis=1 的 apply;
- dict.get(key) 比 dict[key] 更健壮,自动处理键不存在或字典为 NaN 的情况;
- 若字典列含 None 或非字典类型,建议预处理:df['dict1'] = df['dict1'].apply(lambda x: x if isinstance(x, dict) else {});
- 避免 np.vectorize:它仅为语法糖,不真正向量化,且对 NaN 处理不稳定;
- 对超大规模数据(千万行+),可考虑 polars 或 modin.pandas 加速,但本例中纯列表推导已逼近 Python 层极限性能。
综上,列表推导式是解决该问题的黄金标准——它直击痛点、零依赖、高性能、易调试,应作为 Pandas 字典列映射操作的默认选择。

















