drop_duplicates() 默认只删除所有列完全相同的行;若需按指定列去重,须用subset参数;避免inplace=true,应显式赋值;含nan时默认视其相等;大数据量时可优化列处理或改用数据库去重。

为什么 drop_duplicates() 默认不删你认为的“重复行”
常见现象是调用 df.drop_duplicates() 后 DataFrame 行数没变,甚至 df.duplicated().sum() 返回 0。根本原因在于:默认只检查**所有列完全一致**的行。如果你只关心某几列(比如只看 'user_id' 和 'timestamp' 是否重复),但其他列(如日志ID、自增序号)不同,那整行就不会被识别为重复。
解决方法是显式指定 subset 参数:
df_clean = df.drop_duplicates(subset=['user_id', 'timestamp'])
另外注意:keep 参数决定保留哪一行 —— 'first'(默认)、'last' 或 False(全删)。若想保留最新时间戳那行,先按时间排序再设 keep='last',或直接用 keep='last' 配合已排序数据。
inplace=True 看似省事,实际容易出错
很多人写 df.drop_duplicates(inplace=True) 图方便,但后果是:一旦误操作无法回退,且在函数链式调用中会破坏表达式返回值(比如 df.drop_duplicates().groupby(...) 会报错)。更严重的是,在某些 pandas 版本或特定内存布局下,inplace=True 可能引发 SettingWithCopyWarning 或静默失败。
推荐始终返回新 DataFrame:
- 明确赋值:
df = df.drop_duplicates(subset=['id']) - 若原变量名必须复用,至少加注释说明这是覆盖操作
- 对大型 DataFrame,可加
copy=False(仅当确认无需原始副本时)来避免额外内存拷贝,但需确保后续无副作用修改
删除重复前,先确认重复逻辑是否真符合业务
技术上删得干净,不代表业务上合理。例如:
- 订单表中
'order_id'相同但'status'不同(如 “created” vs “shipped”),该保留哪条?不能只按 ID 去重 - 用户行为日志里同一
'user_id'+'event_type'在毫秒级时间戳下大量重复,可能是埋点异常,也可能是真实高频操作 —— 此时应先统计分布:df.groupby(['user_id', 'event_type']).size().describe() - 含 NaN 的列参与去重时,
pandas默认把 NaN 视为彼此相等(即两行仅在 NaN 列不同,仍算重复),这和 SQL 或直觉可能冲突;如需严格区分,提前用fillna()或布尔掩码过滤
大数据量时,drop_duplicates() 性能卡在哪
底层依赖哈希表,时间复杂度接近 O(n),但实际瓶颈常出现在:
- 字符串列过长或过多(如 JSON 字段):哈希计算开销大 → 先用
.str.slice()或正则提取关键片段再比较 - 多列组合去重(如 5+ 列):列数越多,哈希碰撞概率上升,缓存局部性下降 → 尝试先
sort_values()再用keep='first',有时比哈希更快 - 使用
subset但未对对应列建索引:虽不影响正确性,但 pandas 不会自动利用索引加速 → 若该列查询频繁且唯一性高,考虑设为df.set_index('col', drop=False)后再操作
真正上百万行以上,别只盯着 drop_duplicates() 优化;先确认是否真的需要全量内存处理 —— 有时流式 dedupe 或数据库层去重(GROUP BY + ROW_NUMBER())更稳。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











