在数组的子数组中查找公共元素

Posted

技术标签:

【中文标题】在数组的子数组中查找公共元素【英文标题】:Find common elements in subarrays of arrays 【发布时间】:2018-11-19 06:34:03 【问题描述】:

我有两个形状为 arr1=(~140000, 3) 和 arr2=(~450000, 10) 的 numpy 数组。对于两个数组,每行的前 3 个元素是坐标 (z,y,x)。我想找到与 arr1 坐标相同的 arr2 行(可以认为是 arr2 的子组)。

例如:

arr1 = [[1,2,3],[1,2,5],[1,7,8],[5,6,7]]

arr2 = [[1,2,3,7,66,4,3,44,8,9],[1,3,9,6,7,8,3,4,5,2],[1,5,8,68,7,8,13,4,53,2],[5,6,7,6,67,8,63,4,5,20], ...]

我想找到共同的坐标(相同的前 3 个元素):

list_arr = [[1,2,3,7,66,4,3,44,8,9], [5,6,7,6,67,8,63,4,5,20], ...]

目前我正在做这个双循环,非常慢:

list_arr=[]
for i in arr1:
    for j in arr2:
        if i[0]==j[0] and i[1]==j[1] and i[2]==j[2]:
            list_arr.append (j)

我还尝试创建(在第一个循环之后)arr2 的子数组,根据 i[0] 的值对其进行过滤(arr2_filt = [el for el in arr2 if el[0]==i[0]) .这个速度有点操作,但还是很慢。

你能帮我解决这个问题吗?

【问题讨论】:

您能否提供一些示例输入以及您的预期结果?!更容易提供帮助。 我加了一个例子,你可以看看。 您可以像***.com/a/53062049/4045774 一样执行此操作,但您使用 arr2[:,0:3] 创建树并检查 arr1。如果 arr2 中的点不完全一致,但在相同的小公差范围内,这也是有益的。 【参考方案1】:

方法#1

这是一个带有views 的矢量化文件-

# https://***.com/a/45313353/ @Divakar
def view1D(a, b): # a, b are arrays
    a = np.ascontiguousarray(a)
    b = np.ascontiguousarray(b)
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(void_dt).ravel(),  b.view(void_dt).ravel()

a,b = view1D(arr1,arr2[:,:3])
out = arr2[np.in1d(b,a)]

方法#2

另一个带有dimensionality-reduction 的整数 -

d = np.maximum(arr2[:,:3].max(0),arr1.max(0))
s = np.r_[1,d[:-1].cumprod()]
a,b = arr1.dot(s),arr2[:,:3].dot(s)
out = arr2[np.in1d(b,a)]

改进#1

对于前面列出的两种方法,我们可以使用np.searchsorted 替换np.in1d -

unq_a = np.unique(a)
idx = np.searchsorted(unq_a,b)
idx[idx==len(a)] = 0
out = arr2[unq_a[idx] == b]

改进 #2

对于使用np.searchsorted(也使用np.unique)的最后改进,我们可以改用argsort -

sidx = a.argsort()
idx = np.searchsorted(a,b,sorter=sidx)
idx[idx==len(a)] = 0
out = arr2[a[sidx[idx]]==b]

【讨论】:

【参考方案2】:

您可以在set的帮助下完成此操作

arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2 = np.array([[7,8,9,11,14,34],[23,12,11,10,12,13],[1,2,3,4,5,6]])

# create array from arr2 with only first 3 columns
temp = [i[:3] for i in arr2]

aset = set([tuple(x) for x in arr])
bset = set([tuple(x) for x in temp])
np.array([x for x in aset & bset])

输出

array([[7, 8, 9],
       [1, 2, 3]])

编辑

使用list comprehension

l = [list(i) for i in arr2 if i[:3] in arr]

print(l)

输出:

[[7, 8, 9, 11, 14, 34], [1, 2, 3, 4, 5, 6]]

【讨论】:

输出应该是 arr2 的行(附加到列表)以及所有其他信息,而不仅仅是坐标。由于 arr1 是 arr2 的子组(感兴趣的坐标),所以这样做没有意义。 感谢您的努力,但它不适用于此。它返回它找到“i”中存在的甚至 1 个值的所有行(因此其他 2 个是错误的)。【参考方案3】:

对于整数 Divakar 已经给出了很好的答案。如果你想比较浮点数,你必须考虑例如以下:

1.+1e-15==1.
False
1.+1e-16==1.
True

如果这种行为可能导致您的代码出现问题,我建议您执行最近邻搜索,并可能检查距离是否在指定阈值内。

import numpy as np
from scipy import spatial
def get_indices_of_nearest_neighbours(arr1,arr2):
  tree=spatial.cKDTree(arr2[:,0:3])
  #You can check here if the distance is small enough and otherwise raise an error
  dist,ind=tree.query(arr1, k=1)
  return ind

【讨论】:

以上是关于在数组的子数组中查找公共元素的主要内容,如果未能解决你的问题,请参考以下文章

仅返回嵌套数组中匹配的子文档元素

C ++:在子数组的数组中查找最大整数

ZZNUOJ_用C语言编写程序实现1149:查找子数组(附完整源码)

JavaScript中如何通过一个元素去查找该元素的子元素节点

大厂算法面试:使用移动窗口查找两个不重叠且元素和等于给定值的子数组

最大子数组之和