对于给定的2d数据数组,如何以粗体检索7和11的位置(索引)。 因为只有它们是邻居中被相同值包围的元素
import numpy as np
data = np.array([
[0,1,2,3,4,7,6,7,8,9,10],
[3,3,3,4,7,7,7,8,11,12,11],
[3,3,3,5,7,**7**,7,9,11,11,11],
[3,4,3,6,7,7,7,10,11,**11**,11],
[4,5,6,7,7,9,10,11,11,11,11]
])
print data
答案 0 :(得分:4)
使用scipy,您可以将这些点描述为其邻域的最大值和最小值:
import numpy as np
import scipy.ndimage.filters as filters
def using_filters(data):
return np.where(np.logical_and.reduce(
[data == f(data, footprint=np.ones((3,3)), mode='constant', cval=np.inf)
for f in (filters.maximum_filter, filters.minimum_filter)]))
using_filters(data)
# (array([2, 3]), array([5, 9]))
仅使用numpy,您可以将data
与其自身的8个移位切片进行比较,以找到相等的点:
def using_eight_shifts(data):
h, w = data.shape
data2 = np.empty((h+2, w+2))
data2[(0,-1),:] = np.nan
data2[:,(0,-1)] = np.nan
data2[1:1+h,1:1+w] = data
result = np.where(np.logical_and.reduce([
(data2[i:i+h,j:j+w] == data)
for i in range(3)
for j in range(3)
if not (i==1 and j==1)]))
return result
正如您在上面所看到的,此策略生成一个扩展数组,该数组在数据周围具有NaN边界。这允许移位的切片表示为data2[i:i+h,j:j+w]
。
如果您知道要与邻居进行比较,那么您可能有必要从一开始就使用NaN的边界定义data
,这样您就不必像上面那样创建第二个数组。
使用八个班次(和比较)比在data
中循环每个单元格并将其与其邻居进行比较要快得多:
def using_quadratic_loop(data):
return np.array([[i,j]
for i in range(1,np.shape(data)[0]-1)
for j in range(1,np.shape(data)[1]-1)
if np.all(data[i-1:i+2,j-1:j+2]==data[i,j])]).T
这是一个基准:
using_filters : 0.130
using_eight_shifts : 0.340
using_quadratic_loop : 18.794
以下是用于生成基准的代码:
import timeit
import operator
import numpy as np
import scipy.ndimage.filters as filters
import matplotlib.pyplot as plt
data = np.array([
[0,1,2,3,4,7,6,7,8,9,10],
[3,3,3,4,7,7,7,8,11,12,11],
[3,3,3,5,7,7,7,9,11,11,11],
[3,4,3,6,7,7,7,10,11,11,11],
[4,5,6,7,7,9,10,11,11,11,11]
])
data = np.tile(data, (50,50))
def using_filters(data):
return np.where(np.logical_and.reduce(
[data == f(data, footprint=np.ones((3,3)), mode='constant', cval=np.inf)
for f in (filters.maximum_filter, filters.minimum_filter)]))
def using_eight_shifts(data):
h, w = data.shape
data2 = np.empty((h+2, w+2))
data2[(0,-1),:] = np.nan
data2[:,(0,-1)] = np.nan
data2[1:1+h,1:1+w] = data
result = np.where(np.logical_and.reduce([
(data2[i:i+h,j:j+w] == data)
for i in range(3)
for j in range(3)
if not (i==1 and j==1)]))
return result
def using_quadratic_loop(data):
return np.array([[i,j]
for i in range(1,np.shape(data)[0]-1)
for j in range(1,np.shape(data)[1]-1)
if np.all(data[i-1:i+2,j-1:j+2]==data[i,j])]).T
np.testing.assert_equal(using_quadratic_loop(data), using_filters(data))
np.testing.assert_equal(using_eight_shifts(data), using_filters(data))
timing = dict()
for f in ('using_filters', 'using_eight_shifts', 'using_quadratic_loop'):
timing[f] = timeit.timeit('{f}(data)'.format(f=f),
'from __main__ import data, {f}'.format(f=f),
number=10)
for f, t in sorted(timing.items(), key=operator.itemgetter(1)):
print('{f:25}: {t:.3f}'.format(f=f, t=t))
答案 1 :(得分:3)
我使用了列表理解,但可能有更好的方法
A = [(i,j) for i in range(1,data.shape[0]-1) for j in range(1,data.shape[1]-1) if all((data[i-1:i+2,j-1:j+2]==data[i,j]).flatten())]
编辑:
如果你想要表单数组([i,j],dtype = int64),那么你只需要修改第一部分:
A= [np.array([i,j], dtype=np.int64) for i in range(1,data.shape[0]-1) for j in range(1,data.shape[1]-1) if all((data[i-1:i+2,j-1:j+2]==data[i,j]).flatten())]
答案 2 :(得分:1)
我测试了它,以下代码可以使用:
for i in range(1,np.shape(data)[0]-1):
for j in range(1,np.shape(data)[1]-1):
if np.all(data[i-1:i+2,j-1:j+2]==data[i,j]):
print np.array([i,j], dtype=np.int64)
答案 3 :(得分:1)
displacements = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
for x in range(1, data.shape[0] - 1):
for y in range(1, data.shape[1] - 1):
if all((data[x][y] == data[x + a][y + b]) for a, b in displacements):
print np.array([x, y], dtype=np.int64)
不像其他答案一样狡猾,但它很清楚并打印出正确的输出。我认为更改/添加位移值也更容易一些。
哎呀,没想到你想要所有8个邻居。虽然容易修复。 :)