isin() 是查询某列是否包含指定值的最安全方法,支持多值匹配、明确处理 NaN 和空列表,且性能优于误用 == 或循环调用 isin()。

isin 方法查某列是否含指定值,比 == 更安全
直接用 df[col] == value 只能查完全相等,而实际中常要查“是否在某个集合里”——比如找所有城市是北京、上海或深圳的订单。这时 isin() 是唯一合理选择,它天然支持多个候选值,且对 NaN 和空列表行为明确。
-
isin()返回布尔 Series,可直接用于切片:df[df['city'].isin(['北京', '上海', '深圳'])] - 传入空列表
[]会返回全False,不会报错,但结果为空 DataFrame —— 这点容易被忽略,上线后查不到数据却没报错 - 如果列里有
NaN,isin()默认不匹配(即NaN in ['a', 'b']是False),符合直觉;但若误用==比较NaN,结果全是False,更难排查
传入 list / set / tuple 都行,但 set 不保证顺序,不影响结果
isin() 内部把输入转成哈希结构查,所以传 set 理论上略快,尤其候选值多时。但输出行序只由原 DataFrame 决定,和输入容器顺序无关。
- 日常用
list最稳妥,写法直观:df['id'].isin([101, 205, 307]) - 如果候选值来自另一 DataFrame 的某列,别直接传
other_df['tag'].values—— 它可能是numpy.ndarray,没问题;但若带NaN,得先dropna(),否则isin()会把NaN当作一个合法值去匹配(而通常你并不想匹配NaN) - 避免传
pd.Series,除非你明确需要它的 index 对齐逻辑;多数情况用.tolist()或.unique()转一下更可控
性能差?先看是不是在重复调用 or 小数据硬扛大集合
单次 isin() 很快,瓶颈往往出在误用场景:比如在循环里反复调用 df[col].isin([x]) 查单个值,或者拿 10 万行 DataFrame 去匹配 5 万个候选 ID。
- 查单个值,用
==更合适:df[df['uid'] == target_id],比isin([target_id])少一次容器构建开销 - 候选集超 1 万,确认是否真需要全量匹配 —— 有时加个
df['col'].notna() & df['col'].isin(large_list)能提前过滤掉大量NaN,提速明显 - 如果频繁按同一列 + 不同集合查询,考虑把该列设为索引再用
.loc,或者用pd.Categorical编码后再isin(),能省下不少哈希计算
字符串模糊匹配?isin 不干这事,别硬凑
isin() 只做精确成员判断,不支持通配符、正则或子串包含。常见错误是以为 df['name'].isin(['张']) 能找出“张三”“张伟”,其实不能。
- 要查“姓张”,用
str.startswith('张');要查“含‘明’字”,用str.contains('明') - 如果真想混合用(比如“精确匹配 A/B,同时模糊匹配 C 类”),得拆成两步布尔运算:
mask1 = df['type'].isin(['A', 'B']); mask2 = df['name'].str.contains('C'); df[mask1 | mask2] - 嵌套
isin()也没意义,比如df['tags'].isin([['a','b'], ['c']])—— 因为tags列元素是字符串,不是列表,永远不匹配
None 或 np.nan,导致部分本该命中的行被跳过。检查方法很简单:打印 len(your_list) 和 len([x for x in your_list if pd.notna(x)]),差值就是隐患数。

















