发布于2026-07-19 阅读(0)
扫一扫,手机访问
处理Pandas数据清洗时,按关键词筛选或删除行是高频操作。很多人第一反应是用循环,其实用`str.contains()`配合取反运算符就能高效完成。不过这里有几个容易踩的坑,值得先说说。
核心逻辑很简单:先筛选出包含关键词的行,再用取反符号`~`把它们过滤掉。`str.contains()`返回的是一个布尔型Series,`~`对它取反后,就得到了“不包含”的掩码。
实际操作中,最常见的错误是没加`na=False`。当列中存在`NaN`值时,`str.contains()`默认会返回`NaN`,而`~NaN`会直接报错,提示`TypeError: bad operand type for unary ~: 'float'`。所以,必须显式传入`na=False`,让缺失值被统一视为`False`,取反后才能保留为`True`——也就是保留那些包含NaN的行。
另外还有几个细节需要注意:
举个例子:要删除text列中包含“error”(不区分大小写)的行,可以这样写:
df = df[~df['text'].str.contains('error', na=False, case=False)]
`query()`的写法确实更简洁,但它对字符串方法的支持有限。它只允许`.str.startswith()`、`.str.endswith()`和`.str.fullmatch()`这类确定性匹配,没有`str.contains()`的等价写法。如果硬写`query("text.str.contains('x')")`,会直接报错——`query()`无法解析这种嵌套属性调用。
所以,遇到需要模糊匹配的场景,老老实实用布尔索引是最稳妥的方案。
有些人看到“删除含某几个词的行”,会下意识想到`isin()`。但`isin()`只判断单元格是否完全等于某个值,不是找子串。比如`df[~df['text'].isin(['error', 'fail'])]`,只会删掉整个值正好是`'error'`或`'fail'`的行,而像`'system error occurred'`这样的内容会被忽略。
如果需要删除包含任意一个关键词的行,可以用`|`把多个`contains()`条件拼接起来,或者直接写一个正则表达式,比如`pattern = 'error|fail'`。
如果要删除同时包含多个关键词的行,就得链式调用,或者用`apply()`配合`all()`,但性能会差一些,非必要不建议这样用。
`~df['col'].str.contains(...)`每次都会重新计算一遍。如果后续还要基于同样的条件做其他操作(比如统计剩余行数、再按另一列分组),最好先把掩码存成变量:
mask = ~df['text'].str.contains('temp', na=False)
df_clean = df[mask].copy()
print(f"删了 {len(df) - mask.sum()} 行")
当`contains()`带有复杂正则或`case=False`时,计算开销会明显增加。另外,用`copy()`能避免`SettingWithCopyWarning`,虽然不是必须的,但顺手加上更稳妥。
其实,很多人真正容易忽略的是`na`参数的默认行为。调了半天,发现删少了或者报错了,才回头查文档——这个坑,才是最常踩的。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8