Python pandas匹配客户SKU折扣时如何避免KeyError返回None
解决方案
核心问题分析
你遇到的报错本质是两个原因导致的:
- 销售记录中的
Purple GrapesSKU没有在df_sku_prices定价表中存在,用loc强制取值就会抛出KeyError - 如果后续有客户+SKU组合没有在折扣表中存在,也会触发同样的报错
最优实现方案(推荐用于生产环境)
不要用逐行apply操作,pandas原生的左连接(left merge)是更高效、更符合需求的实现,匹配不到的字段自动填充缺失值,不会抛出报错,且处理大数据量的性能比apply高几十倍,代码可读性也更强:
import pandas as pd # 先重置两个索引表的索引,方便后续合并 df_sku_prices_reset = df_sku_prices.reset_index() df_customer_discounts_reset = df_customer_discounts.reset_index() # 第一步:匹配SKU定价,保留所有销售记录,匹配不到的定价自动填NaN df_monthly_sales_report = df_sales_volume.merge( df_sku_prices_reset, on="SKU", how="left" ).rename(columns={ "List Price": "SKU List Price", "Markedup Price": "SKU Markedup Price" }) # 第二步:匹配客户SKU折扣,保留所有销售记录,匹配不到的折扣自动填NaN df_monthly_sales_report = df_monthly_sales_report.merge( df_customer_discounts_reset, on=["SKU", "Customer"], how="left" ).rename(columns={ "Discount": "Customer Discount" })
原有apply写法的修改方案(如果需要兼容旧逻辑)
如果坚持要用原来的逐行取值写法,可以在loc取值前先判断索引是否存在,不存在就返回None:
# 匹配SKU定价的修改版 df_monthly_sales_report["SKU List Price"] = df_monthly_sales_report.apply( lambda row: df_sku_prices.loc[row["SKU"], "List Price"] if row["SKU"] in df_sku_prices.index else None, axis=1, ) df_monthly_sales_report["SKU Markedup Price"] = df_monthly_sales_report.apply( lambda row: df_sku_prices.loc[row["SKU"], "Markedup Price"] if row["SKU"] in df_sku_prices.index else None, axis=1, ) # 匹配折扣的修改版 df_monthly_sales_report["Customer Discount"] = df_monthly_sales_report.apply( lambda row: df_customer_discounts.loc[(row['SKU'], row['Customer']), "Discount"] if (row['SKU'], row['Customer']) in df_customer_discounts.index else None, axis=1, )
方案说明
- 最终输出的DataFrame完全符合你要求的字段,匹配不到的定价/折扣默认填充NaN(pandas标准缺失值格式,和None逻辑完全一致)
- 左连接方案支持生产环境百万级以上数据量运行,性能远优于逐行apply
- 代码逻辑清晰,方便同事后续维护修改
内容的提问来源于stack exchange,提问作者good_vibes
相关产品推荐
相关产品推荐

