我正在拼命寻找一种有效的方法来检查两个2D numpy Arrays是否相交。
所以我所拥有的是两个具有任意数量的2D数组的数组,如:
A=np.array([[2,3,4],[5,6,7],[8,9,10]])
B=np.array([[5,6,7],[1,3,4]])
C=np.array([[1,2,3],[6,6,7],[10,8,9]])
如果至少有一个向量与另一个向量相交,那么我需要的是一个True,否则为false。所以它应该给出这样的结果:
f(A,B) -> True
f(A,C) -> False
我是python的新手,起初我用Python列表编写了我的程序,但是当然效率非常低。该程序需要数天才能完成,所以我现在正在研究numpy.array
解决方案,但这些数组实际上并不容易处理。
以下是关于我的程序和Python列表解决方案的一些上下文:
我正在做的是像3维度中的自我避免随机游走。 http://en.wikipedia.org/wiki/Self-avoiding_walk。但是,不是做一个随机游走,并希望它达到一个理想的长度(例如,我希望链条积累1000个珠子)而不会达到死胡同,我会做以下事情:
我创建了一个具有所需长度N的“扁平”链:
X=[]
for i in range(0,N+1):
X.append((i,0,0))
现在我折叠这条平链:
步骤1.-6。必须进行很多次(例如,对于长度为1000的链,~5000次),所以这些步骤必须有效地完成。我基于列表的解决方案如下:
def PivotFold(chain):
randPiv=random.randint(1,N) #Chooses a random pivotelement, N is the Chainlength
Pivot=chain[randPiv] #get that pivotelement
C=[] #C is going to be a shifted copy of the chain
intersect=False
for j in range (0,N+1): # Here i shift the hole chain to get the pivotelement to the origin, so i can use simple rotations around the origin
C.append((chain[j][0]-Pivot[0],chain[j][1]-Pivot[1],chain[j][2]-Pivot[2]))
rotRand=random.randint(1,18) # rotRand is used to choose a direction and a Rotation (2 possible direction * 9 rotations = 18 possibilitys)
#Rotations around Z-Axis
if rotRand==1:
for j in range (randPiv,N+1):
C[j]=(-C[j][1],C[j][0],C[j][2])
if C[0:randPiv].__contains__(C[j])==True:
intersect=True
break
elif rotRand==2:
for j in range (randPiv,N+1):
C[j]=(C[j][1],-C[j][0],C[j][2])
if C[0:randPiv].__contains__(C[j])==True:
intersect=True
break
...etc
if intersect==False: # return C if there was no intersection in C
Shizz=C
else:
Shizz=chain
return Shizz
函数PivotFold(链)将在最初的扁平链X上使用很多次。这是非常天真的写的所以也许你有一些改善这个^^我认为numpyarrays会很好,因为我可以有效地移动和旋转整个链而不会遍历所有元素......
答案 0 :(得分:3)
使用here概述的相同构思,您可以执行以下操作:
def make_1d_view(a):
a = np.ascontiguousarray(a)
dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(dt).ravel()
def f(a, b):
return len(np.intersect1d(make_1d_view(A), make_1d_view(b))) != 0
>>> f(A, B)
True
>>> f(A, C)
False
这不适用于浮点类型(它不会将+0.0和-0.0视为相同的值),np.intersect1d
使用排序,因此它具有线性,而非线性的性能。您可以通过在代码中复制np.intersect1d
的源来挤压一些性能,而不是检查返回数组的长度,在布尔索引数组上调用np.any
。
答案 1 :(得分:2)
这应该这样做:
In [11]:
def f(arrA, arrB):
return not set(map(tuple, arrA)).isdisjoint(map(tuple, arrB))
In [12]:
f(A, B)
Out[12]:
True
In [13]:
f(A, C)
Out[13]:
False
In [14]:
f(B, C)
Out[14]:
False
寻找路口?好的,set
听起来像是一个合乎逻辑的选择。
但是numpy.array
或list
不可以播放?好的,将它们转换为tuple
。
这就是主意。
numpy
做法涉及非常难以理解的广播:
In [34]:
(A[...,np.newaxis]==B[...,np.newaxis].T).all(1)
Out[34]:
array([[False, False],
[ True, False],
[False, False]], dtype=bool)
In [36]:
(A[...,np.newaxis]==B[...,np.newaxis].T).all(1).any()
Out[36]:
True
一些时间结果:
In [38]:
#Dan's method
%timeit set_comp(A,B)
10000 loops, best of 3: 34.1 µs per loop
In [39]:
#Avoiding lambda will speed things up
%timeit f(A,B)
10000 loops, best of 3: 23.8 µs per loop
In [40]:
#numpy way probably will be slow, unless the size of the array is very big (my guess)
%timeit (A[...,np.newaxis]==B[...,np.newaxis].T).all(1).any()
10000 loops, best of 3: 49.8 µs per loop
numpy
方法也会占用RAM,因为A[...,np.newaxis]==B[...,np.newaxis].T
步创建了一个3D数组。
答案 2 :(得分:2)
您还可以通过一些np.tile
和np.swapaxes
业务来完成工作!
def intersect2d(X, Y):
"""
Function to find intersection of two 2D arrays.
Returns index of rows in X that are common to Y.
"""
X = np.tile(X[:,:,None], (1, 1, Y.shape[0]) )
Y = np.swapaxes(Y[:,:,None], 0, 2)
Y = np.tile(Y, (X.shape[0], 1, 1))
eq = np.all(np.equal(X, Y), axis = 1)
eq = np.any(eq, axis = 1)
return np.nonzero(eq)[0]
为了更具体地回答这个问题,您只需要检查返回的数组是否为空。
答案 3 :(得分:1)
这应该比for-loop解决方案更快,不是O(n ^ 2),但它不是完全numpythonic。不知道如何更好地利用numpy
def set_comp(a, b):
sets_a = set(map(lambda x: frozenset(tuple(x)), a))
sets_b = set(map(lambda x: frozenset(tuple(x)), b))
return not sets_a.isdisjoint(sets_b)
答案 4 :(得分:0)
我认为如果两个阵列设置了子阵列,你想要真实!你可以用这个:
def(A,B):
for i in A:
for j in B:
if i==j
return True
return False
答案 5 :(得分:0)
使用numpy_indexed包可以有效解决此问题(免责声明:我是其作者):
import numpy_indexed as npi
len(npi.intersection(A, B)) > 0