我试图在下面创建一个函数,但我不知道如何执行此操作。
我们说我有一个2D numpy数组,如
import numpy as np
arr = np.array([[ 1, 2, 3, 4], [ 1, 6, 7, 8], [ 1, 1, 1, 12], [13, 3, 15, 16]])
这是一个4x4矩阵,打印时看起来像这样:
array([[ 1, 2, 3, 4],
[ 1, 6, 7, 8],
[ 1, 1, 1, 12],
[13, 3, 15, 16]])
我想访问arr
的元素并将它们相互比较。对于每个元素,我想看看是否所有周围的八个元素(顶部,底部,左侧,右侧,左上角,右上角,左下角,右下角)是否大于,小于或等于此元素我在。
我想过在这样的函数中使用if语句:
if arr[i][j] == arr[i][j+1]:
print("Found a pair! %d is equal to %d, it's in location (%d, %d)", % (arr[i][j], arr[i][j+1], i, j+1))
elif:
arr[i][j] > arr[i][j+1]:
print("%d is greater than %d, it's in location (%d, %d)", % (arr[i][j], arr[i][j+1], i, j+1))
else:
print("%d is less than %d, it's in location (%d, %d)", % (arr[i][j], arr[i][j+1], i, j+1))
然而,(1)我必须对所有八个周围元素位置执行此操作,并且(2)我不确定如何编写函数以使其正确地从一个位置移动到另一个位置。我想,不知怎的,必须使用递归来实现这一点。也可以使用while循环。
我计划保存所有"对"与...相等,并用这些创建字典。
EDIT1:
我仍然需要了解维度的位置:
我们的原始矩阵成形(4,4):
当我们水平比较相邻对时,我们找到一个形状为(4,3)的数组:
arr[:-1] == arr[1:]
#output
array([[ True, False, False, False],
[ True, False, False, False],
[False, False, False, False]], dtype=bool)
当我们垂直比较相邻对时,我们找到一个形状为(3,4)的数组:
arr[:, :-1] == arr[:, 1:]
# output
array([[False, False, False],
[False, False, False],
[ True, True, False],
[False, False, False]], dtype=bool)
当我将这两个结合起来以确定是否有两个垂直和水平对时,我怎么知道我没有混合位置?
答案 0 :(得分:2)
虽然我没有完全清楚你想要做什么,但相邻的数组切片可能是一种方便的方法。例如,arr[:-1] == arr[1:]
将告诉您相邻行中哪些对。然后,arr[arr[:-1] == arr[1:]]
可以为您提供这些值的数组,argwhere
可以为您提供索引。
>>> import numpy as np
>>> arr
array([[3, 1, 0, 2, 3, 3],
[2, 1, 2, 2, 3, 3],
[2, 3, 0, 1, 1, 0],
[2, 1, 3, 3, 1, 2]])
>>> hpairs = (arr[:, :-1] == arr[:, 1:])
>>> hpairs
array([[False, False, False, False, True],
[False, False, True, False, True],
[False, False, False, True, False],
[False, False, True, False, False]], dtype=bool)
>>> arr[hpairs]
array([3, 2, 3, 1, 3])
>>> np.argwhere(hpairs)
array([[0, 4],
[1, 2],
[1, 4],
[2, 3],
[3, 2]], dtype=int64)
根据需要更改==
运算符和切片方向。
我们得到一个较小的数组作为比较的结果是有道理的。毕竟,可能的水平对的数量比阵列宽度小一个。如果用于比较arr[:, :-1] == arr[:, 1:]
的任一切片用布尔数组索引,我们得到对的左数或右数。类似于其他方向。
如果有多个方向的对,怎么办?我想,这取决于你想用它们做什么。假设你想找到一个至少有三个相等数字的星团,其形状为L转180度。换句话说,任何位置是垂直的上部,右侧是水平对。 (与以前相同的样本数据。)
>>> vpairs = (arr[:-1] == arr[1:])
>>> hpairs[:-1] & vpairs[:, 1:]
array([[False, False, False, False, True],
[False, False, False, False, False],
[False, False, False, True, False]], dtype=bool)
如果你想计算每个位置的相等邻居的数量,这是一种方法。
>>> backslashpairs = (arr[:-1, :-1] == arr[1:, 1:])
>>> slashpairs = (arr[1:, :-1] == arr[:-1, 1:])
>>>
>>> equal_neighbors = np.zeros_like(arr, dtype=int)
>>> equal_neighbors[:-1] += vpairs
>>> equal_neighbors[1:] += vpairs
>>> equal_neighbors[:, :-1] += hpairs
>>> equal_neighbors[:, 1:] += hpairs
>>> equal_neighbors[1:, :-1] += slashpairs
>>> equal_neighbors[:-1, 1:] += slashpairs
>>> equal_neighbors[:-1, :-1] += backslashpairs
>>> equal_neighbors[1:, 1:] += backslashpairs
>>> equal_neighbors
array([[0, 1, 0, 2, 3, 3],
[1, 1, 2, 2, 3, 3],
[2, 1, 0, 2, 2, 0],
[1, 0, 2, 1, 2, 0]])
答案 1 :(得分:1)
可能有一些不错的numpy或scipy功能可以做到这一点,但不是我所知道的。
以下是解决此问题的一种解决方案。
为了给它添加一些混淆,我已将行编入索引x
,将列编入y
。这只是意味着(2, 1)
处的元素是7
。
带有边角的技巧只是用边框展开矩阵,稍后会被忽略。
import numpy as np
arr = np.array([[1, 2, 3, 4], [1, 6, 7, 8], [1, 2, 3, 12], [13, 3, 15, 16]])
arr2 = np.zeros((arr.shape[0]+2, arr.shape[1]+2), dtype=arr.dtype)
arr2[1:-1,1:-1] = arr
results = np.zeros(arr2.shape + (9,), dtype=np.int)
print(arr)
transform = {'y': [-1, 0, 1, -1, 1, -1, 0, 1],
'x': [-1, -1, -1, 0, 0, 1, 1, 1]}
for x in range(1, arr2.shape[0]-1):
for y in range(1, arr2.shape[1]-1):
subarr = arr2[x-1:x+2,y-1:y+2].flatten()
mid = len(subarr)//2
value = subarr[mid]
greater = (subarr > value).astype(np.int)
smaller = (subarr < value).astype(np.int)
results[x,y,:] += greater
results[x,y,:] -= smaller
results = np.dstack((results[1:-1,1:-1,:4], results[1:-1,1:-1,5:]))
xpos, ypos, zpos = np.where(results == 0)
matches = []
for x, y, z in zip(xpos, ypos, zpos):
matches.append(((x, y), x+transform['x'][z], y+transform['y'][z]))
print(matches)
导致
[[ 1 2 3 4]
[ 1 1 7 8]
[ 1 2 3 12]
[13 3 15 16]]
[((0, 0), 1, 0), ((0, 0), 1, 1), ((1, 0), 0, 0), ((1, 0), 1, 1), ((1, 0), 2, 0), ((1, 1), 0, 0), ((1, 1), 1, 0), ((1, 1), 2, 0), ((2, 0), 1, 0), ((2, 0), 1, 1), ((2, 2), 3, 1), ((3, 1), 2, 2)]
在上面的代码中,我将相邻匹配存储在z维度中等于,大于或大于0,1或-1。通过使用简单的变换,z维度的索引转换为与所考虑的点的偏移。
dstack
步骤并不是必需的,但是它除去了添加的边框和自我匹配(没有简单的方法来“切出”数组中间的元素)。
可以通过简单地查找where条件来找到大于或小于匹配的对,因为这些匹配在results
数组中存储为1或-1。
我没有使用dict来存储结果,因为这基本上是不可能的:单个点可以有多个匹配:dict只能为一个点存储一个匹配(使用(x,y)坐标元组作为关键)。因此匹配存储在列表中,每个元素都是
的元组((x, y), (xmatch, ymatch))
元组
由于每对都是双向匹配的,因此所有匹配对都在matches
中包含两次。