
本文介绍如何在 Pandas DataFrame 中高效筛选出「part_name 不被 full_name 包含」的行,解决 str.contains() 无法直接传入 Series 的常见报错,并提供可扩展、易理解的向量化与非向量化实现方案。
本文介绍如何在 pandas dataframe 中高效筛选出「part_name 不被 full_name 包含」的行,解决 `str.contains()` 无法直接传入 series 的常见报错,并提供可扩展、易理解的向量化与非向量化实现方案。
在 Pandas 数据处理中,常需基于两列字符串之间的逻辑关系(如“是否包含”)进行行级过滤。但直接使用 df['full_name'].str.contains(df['part_name']) 会触发 TypeError: unhashable type: 'Series' —— 因为 str.contains() 的 pat 参数仅接受标量模式(字符串或正则),不支持逐行动态传入 Series。
✅ 正确做法:使用 apply() 实现逐行判断
最直观且可靠的方案是借助 DataFrame.apply() 沿行(axis=1)执行自定义逻辑:
import pandas as pd
df = pd.DataFrame({
"city_code": ["34", "36", "89", "34"],
"full_name": ["WXYZ(24)", "ZYXW", "YZWX", "WXYZ(24)"],
"part_name": ["WXYZ", "ABCD", "YZWX", "ABCD"],
})
# 保留 part_name 不在 full_name 中的行
mask = df.apply(lambda row: row["part_name"] not in row["full_name"], axis=1)
result = df[mask].reset_index(drop=True)
print(result)输出:
city_code full_name part_name 0 36 ZYXW ABCD 1 34 WXYZ(24) ABCD
该方法语义清晰、逻辑直译问题需求(“part_name 是否不被 full_name 包含”),适用于任意复杂字符串逻辑(如忽略大小写、正则匹配、前后缀校验等),只需在 lambda 中扩展即可。
⚠️ 注意事项与优化建议
- 性能考量:apply(axis=1) 属于 Python 级循环,在大数据集(>10⁵ 行)上可能较慢。若追求极致性能且逻辑简单,可尝试向量化替代方案(见下文);
-
空值处理:若 full_name 或 part_name 含 NaN,x not in y 会返回 True(因 NaN not in [...] 恒为 True)。如需排除空值影响,应提前清洗或显式处理:
mask = df.apply( lambda r: pd.notna(r["full_name"]) and pd.notna(r["part_name"]) and r["part_name"] not in r["full_name"], axis=1 ) -
向量化备选(高级):对于纯子串匹配,可结合 numpy.vectorize 或 pd.Series.str.find 构建向量化掩码(但可读性下降):
# 等价向量化写法(推荐仅用于性能敏感场景) import numpy as np find_pos = np.vectorize(lambda a, b: -1 if pd.isna(a) or pd.isna(b) else a.find(b)) mask_vec = find_pos(df["full_name"], df["part_name"]) == -1 result = df[mask_vec].reset_index(drop=True)
✅ 总结
| 方案 | 适用场景 | 可读性 | 性能 | 推荐度 |
|---|---|---|---|---|
| apply(lambda x: x['part_name'] not in x['full_name'], axis=1) | 通用、逻辑清晰、支持扩展 | ★★★★★ | ★★☆ | ⭐⭐⭐⭐⭐(首选) |
| np.vectorize + str.find | 大数据量、纯子串匹配 | ★★☆ | ★★★★ | ⭐⭐⭐ |
| 错误用法 str.contains(Series) | ❌ 禁止使用 | — | 报错 | × |
始终优先选择语义明确、易于维护的 apply 方案;仅当 profiling 确认其成为瓶颈时,再考虑向量化优化。同时务必验证空值行为,确保业务逻辑一致性。










