drop_duplicates()没删干净,因默认全列严格比对,nan≠nan、空格/大小写/类型差异(如'1'与1)均导致误判;需先清洗(strip/lower/类型转换)、再指定subset去重。

用 drop_duplicates() 去重时为什么没删干净?
默认只对所有列完全一致的行去重,只要有一列值不同,就被视为不同行。常见陷阱是:含 NaN 的行不会被当作重复(Pandas 认为 NaN != NaN),还有字符串前后空格、大小写不一致、数据类型混杂(比如 '1' 和 1)也会逃过检测。
实操建议:
- 先统一清洗关键列:
df['col'] = df['col'].str.strip().str.lower() - 对数值列强制转类型:
df['id'] = pd.to_numeric(df['id'], errors='coerce') - 去重时显式指定列:
df.drop_duplicates(subset=['name', 'email'], keep='first') - 若想把
NaN当作相同值处理,加参数keep=False并配合na_position='first'预排序(但更稳妥的是先用fillna()占位)
识别并删除典型脏数据:空值、全空行、异常长度文本
脏数据往往不是“错”,而是“不合理”——比如邮箱字段为空、手机号只有 3 位、地址字段全是空格或占位符('N/A'、'NULL'、'--')。
实操建议:
- 删全空行:
df.dropna(how='all') - 删某列为空的行:
df.dropna(subset=['email']) - 删异常文本(如邮箱不含
@):df = df[df['email'].str.contains('@', na=False)] - 删超长/超短字段:
df = df[df['phone'].str.len().between(10, 15, inclusive='both')] - 替换并删除占位符:
df.replace({'N/A': pd.NA, 'NULL': pd.NA, '--': pd.NA}, inplace=True),再接dropna()
inplace=True 真的省内存吗?别乱用
它只是避免赋值语句,不改变底层数据拷贝行为。Pandas 在执行 drop_duplicates() 或 dropna() 时,内部仍会创建视图或副本,尤其当 DataFrame 有混合 dtype 或使用了 categoricals 时,inplace=True 可能触发隐式拷贝,反而更慢。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
实操建议:
- 优先写成
df = df.drop_duplicates(...),语义清晰,调试方便 - 真要控内存,改用
subset缩小操作范围,或分块处理:pd.read_csv(..., chunksize=10000) -
inplace=True在链式调用中会失效(比如df.dropna().drop_duplicates(inplace=True)不生效),直接报错或静默忽略
去重 + 脏数据清理,推荐一个最小安全流程
没有银弹,但有一个低风险启动顺序:先做无损清洗(不删行),再按需裁剪,最后验证。跳过这步,常导致“删着删着发现关键数据没了”。
实操建议:
- 备份索引:
df_orig = df.copy()(不是.copy(deep=False)) - 统一缺失值:
df = df.replace({'': pd.NA, ' ': pd.NA}) - 清洗关键列(如 email、phone)并标准化格式
- 执行
df = df.dropna(subset=['email']).drop_duplicates(subset=['email']) - 用
df_orig.shape[0] - df.shape[0]核对删了多少行,再抽样检查删掉的是否合理
最易被忽略的是:清洗逻辑本身可能引入新问题,比如 str.lower() 对含中文或特殊符号的字段无害,但对某些带编码含义的 ID 字段可能是灾难性的——动手前,先看三行原始数据。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










