我有一个100乘100的numpy矩阵。矩阵主要用零填充,但也包含一些数量的整数。例如:
[0 0 0 0 0 0 0 1]
[0 2 2 0 0 0 0 0]
[0 0 2 0 0 0 0 0] False
[0 0 0 0 0 0 0 0]
[0 3 3 0 0 0 0 0]
确定矩阵是否包含任意数量的不同类型的相邻整数的最有效方法是什么?
以上示例将返回False。这是一个True示例,其中包含指示邻接的行:
[0 0 0 0 0 0 0 1]
[0 2 2 1 1 0 0 0] <---- True
[0 0 2 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 3 3 0 0 0 0 0]
对角线不算相邻。所以这个例子也会返回False:
[0 0 0 1 1 1 1 1]
[0 2 2 0 1 0 0 0]
[0 0 2 0 0 0 0 0] False
[0 3 0 0 0 0 0 0]
[3 3 3 0 0 0 0 0]
我不需要确定邻接的位置,只是确定它是否存在。
目前,我不能比在矩阵中找到每个非零元素然后检查其4个侧翼元素做得更好。
感谢所有出色的答案。
答案 0 :(得分:6)
如果您可以使用scipy,那么使用ndimage.label
和ndimage.labeled_comprehension
非常容易:
import numpy as np
from scipy import ndimage
def multiple_unique_item(array):
return len(np.unique(array)) > 1
def adjacent_diff(array):
labeled_array, num_labels = ndimage.label(array)
labels = np.arange(1, num_labels+1)
any_multiple = ndimage.labeled_comprehension(array, labeled_array, labels,
multiple_unique_item, bool, 0)
return any_multiple.any()
label
默认标记不包含对角线的0的相邻值。然后,理解将与标签关联的所有值传递给辅助函数 - 辅助函数检查是否存在多个唯一值。最后,它会检查是否有任何标签有多个值并返回此值。
要在测试输入数组上测试:
arr1 = np.array([[0,0,0,0,0,0,0,1],
[0,2,2,1,1,0,0,0],
[0,0,2,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,3,3,0,0,0,0,0]])
arr2 = np.array([[0,0,0,1,1,1,1,1],
[0,2,2,0,1,0,0,0],
[0,0,2,0,0,0,0,0],
[0,3,0,0,0,0,0,0],
[3,3,3,0,0,0,0,0]])
arr3 = np.array([[0,0,0,0,0,0,0,1],
[0,2,2,0,0,0,0,0],
[0,0,2,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,3,3,0,0,0,0,0]])
>>> adjacent_diff(arr1)
True
>>> adjacent_diff(arr2)
False
>>> adjacent_diff(arr3)
False
答案 1 :(得分:3)
查看您的问题的描述,检查其在数组中的位置的每个可能的非零整数值可能没有太多的计算工作量,并查看是否存在交叉点。现在,这通常是矫枉过正,但在你的规模上可能会有效:你可以获得每个整数集合的索引,并使用scipy.spatial.distance.cdist
计算它们的距离。我确信基于diff
或其他东西的某些智能解决方案效率更高,但无论如何我都玩得很开心:
import numpy as np
from scipy.spatial.distance import cdist
from itertools import combinations
M1 = np.array(
[[0,0,0,0,0,0,0,1],
[0,2,2,1,1,0,0,0],
[0,0,2,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,3,3,0,0,0,0,0]])
M2 = np.array(
[[0,0,0,1,1,1,1,1],
[0,2,2,0,1,0,0,0],
[0,0,2,0,0,0,0,0],
[0,3,0,0,0,0,0,0],
[3,3,3,0,0,0,0,0]])
def overlaps_eh(M):
uniques = np.delete(np.unique(M),0) # get integers present
unival_inds = [np.transpose(np.where(M==unival)) for unival in uniques]
# unival_inds[k] contains the i,j indices of each element with the kth unique value
for i1,i2 in combinations(range(len(unival_inds)),2):
if np.any(cdist(unival_inds[i1],unival_inds[i2],'cityblock')==1):
return True
# if we're here: no adjacencies
return False
首先,我们将非零唯一矩阵元素收集到数组uniques
中。然后,对于每个唯一值,我们在输入数组中找到具有此值的每个元素的i,j
索引。然后我们检查每对唯一值(使用itertools.combinations
生成),并使用scipy.spatial.distance.cdist
来测量每对矩阵元素的成对距离。使用曼哈顿距离,如果任何元素对具有距离1,则它们是相邻的。因此,我们只需返回True
,以防这些距离为1,否则我们会返回False
。
答案 2 :(得分:3)
这是一种大量使用切片的方法,它只是关注性能的视图 -
def distinct_ints(a):
# Mask of zeros, non-zeros as we would use them frequently
zm = a==0
nzm = ~zm
# Look for distint ints across rows
row_thresh = (nzm[:,1:] & zm[:,:-1]).sum(1)
row_out = ((nzm[:,1:] & (a[:,1:] != a[:,:-1])).sum(1)>row_thresh).any()
# Look for distint ints across cols
col_thresh = (nzm[1:] & zm[:-1]).sum(0)
col_out = ((nzm[1:] & (a[1:] != a[:-1])).sum(0)>col_thresh).any()
# Any from rows or cols
out = row_out | col_out
return out
答案 3 :(得分:2)
以下是使用masked array:
的解决方案import numpy as np
import numpy.ma as ma
a = np.array([[0,1,0], [0,1,0], [2,2,2]]) # sample data
x = ma.masked_equal(a, 0) # mask zeros
adjacencies = np.count_nonzero(np.diff(x, axis=0).filled(0)) + np.count_nonzero(np.diff(x, axis=1).filled(0))
在最后一行,diff
应用于屏蔽数组(忽略零条目); diff
中的非零条目表示数组a
中的不同非零条目。变量adjacencies
将具有邻接的总数(也许您只想知道它是否为0)。在上面的例子中,它是1.
答案 4 :(得分:1)
可以用numpy.diff
来做,但是,不应该认为零的事实使事情变得复杂。
您可以将零设置为大或小的值,以免导致问题:
a[a == 0] = -999
或者使用float数组并将其设置为nan
或inf
:
a[a == 0] = numpy.nan
然后只需在每个方向上查找1
的首阶差异:
numpy.any(numpy.abs(numpy.diff(a, axis=0)) == 1) or numpy.any(numpy.abs(numpy.diff(a, axis=1)) == 1)