python - 将argsort与masking相结合以在移动窗口中获取最接近的值

har*_*son 5 python arrays numpy image-processing large-data

我有一些代码用于根据2D圆形窗口中的相邻值计算图像中的缺失值.它还使用来自相同位置处的一个或多个时间相邻图像的值(即,在第三维中移位的相同2D窗口).

对于缺少的每个位置,我需要根据整个窗口中可用的所有值计算值,但仅限于具有值的空间上最近的n个单元格(在图像/ Z轴位置),其中n是某个值,小于2D窗口中的单元格总数.

在那一刻,计算窗口中的所有内容要快得多,因为我的排序方法是使用数据获取最近的n个单元格是函数中最慢的部分,因为每次都必须重复它,即使距离方面也是如此.窗口坐标不会改变.我不确定这是否必要,并且觉得我必须能够获得一次排序的距离,然后在仅选择可用单元格的过程中屏蔽它们.

这是我的代码,用于选择要在间隙单元位置的窗口中使用的数据:

# radius will in reality be ~100
radius = 2
y,x = np.ogrid[-radius:radius+1, -radius:radius+1]
dist = np.sqrt(x**2 + y**2)
circle_template = dist > radius

# this will in reality be a very large 3 dimensional array
# representing daily images with some gaps, indicated by 0s
dataStack = np.zeros((2,5,5))
dataStack[1] = (np.random.random(25) * 100).reshape(dist.shape)
dataStack[0] = (np.random.random(25) * 100).reshape(dist.shape)

testdata = dataStack[1]
alternatedata = dataStack[0]
random_gap_locations = (np.random.random(25) * 30).reshape(dist.shape) > testdata
testdata[random_gap_locations] = 0
testdata[radius, radius] = 0

# in reality we will go through every gap (zero) location in the data 
# for each image and for each gap use slicing to get a window of 
# size (radius*2+1, radius*2+1) around it from each image, with the 
# gap being at the centre i.e. 
# testgaplocation = [radius, radius]
# and the variables testdata, alternatedata below will refer to these 
# slices

locations_to_exclude = np.logical_or(circle_template, np.logical_or
                                     (testdata==0, alternatedata==0))
# the places that are inside the circular mask and where both images 
# have data 
locations_to_include = ~locations_to_exclude
number_available = np.count_nonzero(locations_to_include)

# we only want to do the interpolation calculations from the nearest n 
# locations that have data available, n will be ~100 in reality
number_required = 3

available_distances = dist[locations_to_include]
available_data = testdata[locations_to_include]
available_alternates = alternatedata[locations_to_include]

if number_available > number_required:
    # In this case we need to find the closest number_required of elements, based
    # on distances recorded in dist, from available_data and available_alternates
    # Having to repeat this argsort for each gap cell calculation is slow and feels 
    # like it should be avoidable
    sortedDistanceIndices = available_distances.argsort(kind = 'mergesort',axis=None)
    requiredIndices = sortedDistanceIndices[0:number_required]
    selected_data = np.take(available_data, requiredIndices)
    selected_alternates = np.take(available_alternates , requiredIndices)
else:
    # we just use available_data and available_alternates as they are...

# now do stuff with the selected data to calculate a value for the gap cell
Run Code Online (Sandbox Code Playgroud)

这是有效的,但是在掩蔽的空间距离数据的argsort中采用了函数总时间的一半以上.(总共1.4mS的〜900uS - 这个功能将运行数百亿次,所以这是一个重要的区别!)

我确信我必须能够在函数外部执行此argsort,当最初设置空间距离窗口时,然后在掩蔽中包括那些排序索引,以获得第一个howManyToCalculate索引而不必重新做那种.答案可能涉及将我们从中提取的各个位放入记录数组中 - 但我无法弄清楚如果是这样的话.任何人都可以看到我如何使这部分过程更有效率?

小智 1

所以你想在循环之外进行排序:

sorted_dist_idcs = dist.argsort(kind='mergesort', axis=None)
Run Code Online (Sandbox Code Playgroud)

然后使用原始代码中的一些变量,这就是我能想到的,尽管它仍然感觉像是一个主要的往返。

loc_to_incl_sorted = locations_to_include.take(sorted_dist_idcs)
sorted_dist_idcs_to_incl = sorted_dist_idcs[loc_to_incl_sorted]

required_idcs = sorted_dist_idcs_to_incl[:number_required]
selected_data = testdata.take(required_idcs)
selected_alternates = alternatedata.take(required_idcs)
Run Code Online (Sandbox Code Playgroud)

请注意,required_idcs引用位置与原始代码中的位置testdata不同。available_data我使用这个片段take是为了方便地索引展平数组。