numpy.intersect1d返回去重排序后的交集,因其按集合语义设计;需保留重复时应改用Counter或np.isin配合计数,多维需视图转换后处理。

intersect1d 为什么只返回去重后的交集?
numpy.intersect1d 默认会对输入数组自动去重并排序,再求交集。这不是 bug,而是设计行为——它本质是“集合交集”,不是“元素级交集”。如果你传入 [1, 2, 2, 3] 和 [2, 2, 4],结果只会是 [2],重复的 2 不会保留。
需要保留重复元素(比如按出现频次取最小交集)?得手动用 np.isin + 计数,或者改用 collections.Counter。例如:
import numpy as np from collections import Counter a, b = np.array([1, 2, 2, 3]), np.array([2, 2, 2, 4]) c = list((Counter(a) & Counter(b)).elements()) # → [2, 2]
- 参数
assume_unique=True可跳过去重步骤,但要求你确保输入已无重复,否则结果错误 - 参数
return_indices=True能返回交集中各元素在原数组中的首次索引,适合做数据对齐 - 不支持多维数组直接调用,必须先
ravel()展平
union1d 并不存在于 NumPy 主干中
别在官方文档里找 numpy.union1d ——它根本不是 NumPy 内置函数。常见混淆来源是旧版 SciPy(0.18 之前)曾导出过该名,或某些博客误写。当前标准做法是用 np.unique(np.concatenate([a, b])) 模拟并集语义。
注意这个“并集”仍是集合语义:去重 + 排序。例如:
立即学习“Python免费学习笔记(深入)”;
a, b = np.array([1, 2, 2]), np.array([2, 3, 3]) np.unique(np.concatenate([a, b])) # → array([1, 2, 3])
- 若需保留原始顺序(不去重也不排序),就只能用
np.concatenate后手动去重,比如借助np.unique(..., return_index=True)提取首次出现位置 - 多维场景下,
concatenate需指定axis;想按行/列算并集,得先转成一维元组视图,如a.view([('', a.dtype)] * a.shape[1]) - 大数据量时,
np.unique是瓶颈,可考虑用set(map(tuple, a.tolist()))(仅限小数组,且丢失 dtype)
如何对多维数组按行/列求交集?
intersect1d 不接受 axis 参数,所以不能直接按行算交集。常见需求是:“找出两个二维数组中完全相同的行”。正确做法是把行转为可哈希结构再比较。
最稳方案(兼容任意 dtype):
a = np.array([[1,2], [3,4], [5,6]])
b = np.array([[3,4], [7,8]])
av = a.view([('', a.dtype)] * a.shape[1]).ravel()
bv = b.view([('', b.dtype)] * b.shape[1]).ravel()
common = np.intersect1d(av, bv).view(a.dtype).reshape(-1, a.shape[1])
# → array([[3, 4]])
- 视图转换依赖 dtype 对齐,若 a/b 的 dtype 不同(如 int32 vs int64),需先统一
- 浮点数组慎用,因
np.intersect1d对 NaN 处理严格(NaN != NaN),会导致本应匹配的行被丢弃 - 更轻量的替代:用
np.array_equal配合广播,但时间复杂度 O(m×n),大数据慢
性能陷阱:小数组别硬套 intersect1d
当数组长度小于几百时,Python 原生 set 操作往往比 intersect1d 快 2–5 倍,尤其输入已是 Python list 或无需排序时。
- 纯整数小数组:直接
list(set(a) & set(b)),再转回np.array - 需要保持 dtype 和顺序:用
np.isin(a, b)得布尔掩码,再索引,比intersect1d少一次排序开销 -
intersect1d底层调用np.sort,而np.sort在小数组上不如 Timsort(Python 的sorted)高效
真正体现 intersect1d 优势的场景是:大数组(>10⁴ 元素)、已排序、或需返回索引时。


















