我有跟随2D数组
regions = array([[3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4],
[3, 3, 3, 3, 8, 8, 8, 8, 8, 4, 4, 4, 4],
[3, 3, 3, 3, 8, 8, 8, 8, 8, 4, 4, 4, 4],
[3, 3, 3, 3, 8, 8, 8, 8, 8, 4, 4, 4, 4],
[3, 6, 6, 6, 8, 8, 8, 8, 8, 7, 7, 7, 4],
[3, 6, 6, 6, 8, 8, 8, 8, 8, 7, 7, 7, 4],
[3, 6, 6, 6, 6, 8, 8, 8, 7, 7, 7, 7, 4],
[3, 6, 6, 6, 6, 2, 2, 2, 7, 7, 7, 7, 4],
[5, 6, 6, 6, 6, 2, 2, 2, 7, 7, 7, 7, 1],
[5, 6, 6, 6, 6, 2, 2, 2, 7, 7, 7, 7, 1],
[5, 6, 6, 6, 6, 2, 2, 2, 7, 7, 7, 7, 1],
[5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1],
[5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1]])
我想查找所有个别号码的相邻号码。例如,3
是4,5,6,8
的后续行为。目前,我正在使用for loop
按照下面提到的代码进行此练习。
numbers = scipy.unique(regions)
for i in numbers:
index = i-1
slices = scipy.ndimage.find_objects(regions)
sub_im = regions[slices[index]]
im = sub_im == i
neighbors = scipy.ndimage.binary_dilation(input=im, structure=disk(1))
neighbors = neighbors*sub_im
neighbors_list = scipy.unique(neighbors)[1:] - 1
print (neighbors_list)
问题是我不想用于循环,因为我的区域数组大约是数百万。如果没有for循环,有没有快速解决这个问题的方法?
答案 0 :(得分:1)
您可以使用=TEXTJOIN("",FALSE,B3:ALM3)
,numpy
和np.roll()
使用np.where()
完成此操作。这个想法是将每个条目追加到它的四个邻居,然后将这些五个列表中的唯一成员(条目及其四个邻居)拉出来。这是一个应该澄清的实现:
np.unique()
这会产生# make a 3d array with the matrix entry and its four neighbors
neighbor_array = np.array([regions,
np.roll(regions,+1,axis=0),
np.roll(regions,-1,axis=0),
np.roll(regions,+1,axis=1),
np.roll(regions,-1,axis=1),
])
# if you want neighbors to include wraparounds, use above; if not, prune
neighbor_array_pruned = neighbor_array[:,1:-1,1:-1]
# reshape to a 2d array entries x neighbors
neighbor_list = np.reshape(neighbor_array_pruned,[5,-1]).T
# get uniques into a dictionary
neighbor_dict = {}
for num in np.unique(regions):
neighbor_dict[num] = np.unique(neighbor_list[np.where(neighbor_list[:,0]==num)])
:
neighbor_dict
注意我修剪了边缘;如果你想包括环绕邻居或做一些更细微的事情,你可以详细说明修剪线。
答案 1 :(得分:1)
我建议使用类似这种方法的东西,它在矩阵元素的数量上是线性的(考虑到你不能支付少于扫描至少一次所有矩阵的元素)。基本上,我将相邻数字列表分组,然后在此基础上计算邻居条目。
import numpy as np
import collections
def adj_to_neighbor_dict(adj):
assert hasattr(adj, "__iter__")
neighbor_dict = collections.defaultdict(lambda: set())
for i,j in adj:
if i == j:
continue
neighbor_dict[i].add(j)
neighbor_dict[j].add(i)
return neighbor_dict
def get_neighbors_2d(npmatrix):
assert len(npmatrix.shape) == 2
I, J = range(npmatrix.shape[0]-1), range(npmatrix.shape[1]-1)
adj_set = set(
(npmatrix[i,j], npmatrix[i+1,j])
for i in I
for j in J
) | set(
(npmatrix[i,j], npmatrix[i,j+1])
for i in I
for j in J
)
return adj_to_neighbor_dict(adj_set)
我在一个包含10个不同数字(np.random.randint(0,10,(1000,1000))
)的1M元素的随机矩阵上进行了测试,花了1.61秒。
更新:
相同的方法可用于3D阵列。执行此操作的代码如下:
def get_neighbors_3d(npmatrix):
assert len(npmatrix.shape) == 3
I, J, K = range(npmatrix.shape[0]-1), range(npmatrix.shape[1]-1), range(npmatrix.shape[2]-1)
adj_set = set(
(npmatrix[i,j,k], npmatrix[i+1,j,k])
for i in I
for j in J
for k in K
) | set(
(npmatrix[i,j,k], npmatrix[i,j+1,k])
for i in I
for j in J
for k in K
) | set(
(npmatrix[i,j,k], npmatrix[i,j,k+1])
for i in I
for j in J
for k in K
)
return adj_to_neighbor_dict(adj_set)
我在一个包含10个不同数字(np.random.randint(0,10,(100,100,100))
)的1M元素的随机矩阵上测试了这个函数,花了2.60秒。
我还建议一个通用的解决方案,它不是基于np.array的形状:
def npmatrix_shape_iter(shape):
num_dimensions = len(shape)
last_dimension = num_dimensions-1
coord = [0] * num_dimensions
while True:
yield tuple(coord)
coord[last_dimension] += 1
for i in xrange(last_dimension, 0, -1):
if coord[i] < shape[i]:
break
coord[i] = 0
coord[i-1] += 1
# end condition: all the dimensions have been explored
if coord[0] >= shape[0]:
break
def adj_position_iter(tpl):
new_tpl = list(tpl)
for i in xrange(len(tpl)):
new_tpl[i] += 1
yield tuple(new_tpl)
new_tpl[i] -= 1
def get_neighbors(npmatrix):
neighbors = set(
(npmatrix[tpl], npmatrix[adj_tpl])
for tpl in npmatrix_shape_iter(tuple(np.array(npmatrix.shape)-1))
for adj_tpl in adj_position_iter(tpl)
)
neighbor_dict = collections.defaultdict(lambda: [])
for i,j in neighbors:
if i == j:
continue
neighbor_dict[i].append(j)
neighbor_dict[j].append(i)
return neighbor_dict
由于这个功能很普遍,所以需要做更多的工作,实际上它比以前的工作慢。在第一次测试的相同2D矩阵上,它需要6.71秒,而在第二次测试的3D矩阵上需要7.96秒。
更新2:
我用更快(也希望也更容易)的版本更新了2D和3D矩阵的代码。如果没有关于矩阵内部数字位置的其他限制,则无法在不扫描所有矩阵单元的情况下发现所有颜色:使用for循环,我们当前正在执行此操作。您可以用来完成任务的每个功能都将在内部扫描整个矩阵(至少)。顺便说一下,我并不是说这是最快的解决方案,因为一个替代解决方案可以是使用cython或本地numpy代码(如果存在的话)。