如何比对2D数组与1D数组元素并删除符合条件的行(NumPy)
问题描述
现有一个3列、n行的矩阵A,实际使用NumPy数组存储,示例内容如下:
A = [ [1,2,3], [6,2,5], [8,1,7], [2,9,8], [1,9,3], [1,4,3] ]
另有一个普通Python一维列表B = [1,2,5,6,8,9]。
需求为:遍历矩阵A的每一行,若某一行的所有元素都存在于列表B中,则删除该行。以上述示例数据为例,第2行[6,2,5]、第4行[2,9,8]的全部元素都属于B,这两行需要被移除。
已尝试方案的问题
第一版嵌套循环代码
copy=[] for i in A: for j in B: if int(j) in i: for k in B[B.index(j):]: if int(k) in i: for l in B[B.index(k):]: if int(l) in i: copy.append(i)
该版本逻辑存在根本错误:四层循环仅在判断行内是否存在3个按B顺序排列的元素,完全没有校验「行内是否存在不在B中的元素」,只要命中循环条件就会重复追加行,因此会出现大量重复值、误删/误保留行的问题。
第二版列表推导式代码
for i in A: copy=[x for x in i if x not in B] copy=np.array(copy) final.append(copy)
该版本逻辑完全偏离需求:代码实际是把每行中不在B里的零散元素抽出来存入结果,没有做整行保留/删除的判断,最终得到的是拆分后的元素集合,不是过滤后的完整矩阵。
正确实现
首先把B转为集合可以大幅提升成员判断的效率,核心判断逻辑为:仅保留「不是所有元素都在B中」的行。
通用兼容写法
不需要手动做NumPy和普通列表的类型转换,逻辑直观易读:
import numpy as np B_set = set(B) # 过滤符合保留条件的行 res_list = [row for row in A if not all(ele in B_set for ele in row)] # 需要NumPy数组格式直接转换即可 res_arr = np.array(res_list)
用示例数据运行后得到的结果如下,正确移除了目标行,无重复、无误删:
[[1, 2, 3], [8, 1, 7], [1, 9, 3], [1, 4, 3]]
NumPy向量化写法(大数据量推荐)
无显式循环,运行效率更高,NumPy内部自动处理类型匹配,不需要手动做类型转换:
import numpy as np # 逐元素判断是否在B中,再按行判断是否整行都属于B delete_mask = np.isin(A, B).all(axis=1) # 取反保留不需要删除的行 res_arr = A[~delete_mask]
内容的提问来源于stack exchange,提问作者Shiraj Baral
相关产品推荐
相关产品推荐

