keep='first'保留首次录入记录,适用于注册信息等需原始证据场景;keep='last'保留最新记录,适用于订单状态等需最终态场景;默认keep='first'易致数据回退,须按业务显式指定。

keep='first' 和 keep='last' 的业务含义完全不同
默认 keep='first' 是保留最早录入的那条,适合「以首次登记为准」的场景,比如用户注册信息、合同签署时间戳;keep='last' 则保留最新更新的那条,适合「以最新状态为准」的场景,比如订单状态变更、设备传感器最新读数。
常见错误现象:df.drop_duplicates() 后发现关键字段(如 updated_at)被回退到旧值——其实是用了默认 keep='first',把后面更正过的记录删掉了。
- 若数据来自多批次追加写入(如每日增量同步),
keep='last'才能拿到最终态 - 若要做审计溯源,
keep='first'可保留原始录入证据 -
keep=False不是“保留”,而是“全删”,适合清理测试脏数据,但生产环境慎用
subset 参数不配 keep 就容易漏掉逻辑重复
只传 subset=['user_id', 'email'] 却不指定 keep,行为仍按默认 keep='first' 执行——但这时“第一次出现”是按整表顺序算的,和业务时间无关。比如两条记录 user_id 相同但 email 不同,你本意是按 user_id 去重并留最新的一条,结果却留了最早的那条,且没报错。
使用场景:清洗用户主数据时,常需按业务主键(如 ['customer_id', 'source_system'])去重,而非全字段。
- 务必显式写
keep='last'或keep='first',别依赖默认 -
subset里不能有未清洗的字符串列——' john@ex.com '和'john@ex.com'会被判为不同 - 含
datetime64列时,微秒级差异会导致去重失效,建议先用.dt.floor('s')统一精度
duplicated(keep=False) 是查重不是去重,别和 drop_duplicates 混用
duplicated(keep=False) 返回的是一个布尔序列,True 表示该行属于某组重复数据中的任意一条(包括首尾),它本身不修改原数据。而 drop_duplicates() 是直接返回去重后的新 DataFrame。
常见错误现象:写成 df[duplicated(keep=False)] 报 NameError——忘了加 df. 前缀;或误以为 df.duplicated(keep=False).drop_duplicates() 能“二次去重”,实际是布尔序列调用不了 drop_duplicates。
- 要提取全部重复行:用
df[df.duplicated(keep=False)] - 要提取唯一代表行(每组只取一条):用
df.drop_duplicates(subset=..., keep='first') - 要统计每组重复几次:用
df.groupby(list(df.columns)).size(),不是靠duplicated数 True 个数
NaN 处理不当会让 keep 行为失效
pandas 默认把多个 NaN 视为相等,但 NaN == NaN 实际为 False;duplicated() 和 drop_duplicates() 内部用的是特殊等价判断,所以全列为 NaN 的行会被当作重复——但只要其中一列是 NaN、其余列不同,就可能漏判。
性能影响:含大量 NaN 的列参与 subset 时,哈希计算会变慢,且结果不稳定(取决于 pandas 版本对 NaN 的归一化策略)。
- 建议提前用
fillna()统一空值(如''、-1、pd.NaT),再做去重 - 若必须保留 NaN 原始语义,改用
df[~df.duplicated(subset=..., keep='first')]替代drop_duplicates,可绕过部分 NaN 比较陷阱 - 用
df.duplicated().sum()快速验证是否有重复,比肉眼扫更可靠
真正麻烦的不是参数记不住,而是业务规则没对齐:同一张表里,有的字段要留最新,有的要留最早,还有的要整组剔除——这时候得拆成多步处理,而不是指望一个 keep 值解决所有问题。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











