根本原因是默认比较所有列,而实际需依据关键列去重;应显式指定subset、处理nan、清洗字符串、控制索引,并注意大数据量时的性能优化。

为什么 drop_duplicates() 没删掉你认为该删的行
根本原因通常是默认只比较所有列,而你真正想依据的是某几列(比如 'id' 或 'email')。如果没显式指定 subset,哪怕两行在关键字段上完全一样,只要其他列(如时间戳、日志ID)不同,就会被当作不同行保留。
实操建议:
- 明确用
subset=['col1', 'col2']锁定去重依据列,避免“看起来重复却没删”的错觉 - 注意
keep='first'(默认)和keep='last'的行为差异:前者保留首次出现的行,后者保留最后一次——这对时序数据很关键 - 如果列含
NaN,drop_duplicates()默认把所有NaN视为相等,这有时不符合业务逻辑(比如空邮箱不该算作同一用户),可先用fillna()处理或改用布尔索引
遇到字符串空格/大小写不一致,drop_duplicates() 为啥无效
因为它是严格值匹配,'Alice ' 和 'alice' 在 Python 层面就是两个不同字符串。Pandas 不会自动做清洗,得你提前处理。
实操建议:
- 对目标列链式调用:
df['name'].str.strip().str.lower(),再传给subset - 别直接改原列除非必要;更安全的做法是新建临时列用于去重:
df.assign(name_clean=df['name'].str.strip().str.lower()).drop_duplicates(subset=['name_clean']) - 中文全角/半角空格、不可见字符(如
\u200b)也会导致失效,可用.str.replace(r'\s+', ' ', regex=True).str.strip()统一清理
大数据量下 drop_duplicates() 卡住或内存爆掉
它底层依赖哈希表,当数据超千万行或列数多、字符串长时,内存占用会陡增,且无法流式处理。
实操建议:
- 优先用
subset缩小参与哈希的列范围,避免把整行都塞进哈希 - 考虑分块读取 + 全局去重:用
pd.read_csv(..., chunksize=50000)逐块处理,维护一个已见set记录关键字段组合(需确保字段可哈希,如转成tuple) - 如果只是查重不删,用
duplicated()配合any()或sum()更轻量,比如df.duplicated(subset=['id']).sum()快速统计重复数
去重后索引乱了,怎么保持原始顺序或还原索引
drop_duplicates() 不会重置索引,删掉中间行后会出现跳号(比如原索引 0,1,2,3 → 去重后剩 0,2,3),后续用 .iloc 或绘图可能出问题。
实操建议:
- 加
ignore_index=True直接重建连续整数索引,最常用也最省心 - 如果必须保留原始索引(比如要回溯日志),就别动它;但要注意之后用
.loc查找时索引还在,而.iloc行号已变 - 去重前用
df.reset_index(drop=False)把原索引转成列,去重后再设回来,适合需要审计原始位置的场景
真正麻烦的是混合了缺失值、嵌套结构、自定义对象的列——drop_duplicates() 会直接报错或行为异常,这种时候别硬刚,先用 apply() 转成可哈希类型,或者换用 groupby().first() 这类更可控的方式。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











