在数组的子数组中查找公共元素
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
【讨论】:
以上是关于在数组的子数组中查找公共元素的主要内容,如果未能解决你的问题,请参考以下文章
ZZNUOJ_用C语言编写程序实现1149:查找子数组(附完整源码)
JavaScript中如何通过一个元素去查找该元素的子元素节点