我正在尋找一種方法將二維陣列中的每個值與其周圍的值進行比較,并回傳哪些值接近感興趣的值(在閾值內)。
我探索的方法涉及遍歷 2D 陣列的每個元素,但我覺得這不是最快或最佳的方法。
輸入將是一個 2D 陣列(大小:ixj),輸出將是兩個 3D 陣列 (kxixj),其中“額外”維度用于存盤閾值內附近元素的 i 和 j 索引。
一些代碼來說明我目前在做什么:
import numpy as np
from tqdm import tqdm
np.random.seed(seed=10)
arr = np.random.random((100, 100)) # Some 2D input array
threshold = 0.5
# Arrays for the row and col indices
i_all, j_all = np.mgrid[0:arr.shape[0],
0:arr.shape[1]]
# Footprint around the current element (ie looking at the 8 elements around the central value). Must be odd.
footprint = (3, 3)
footprint_size = np.product(footprint)
# Prepare output for i and j indices
output_i = np.full((footprint_size, *arr.shape), np.nan)
output_j = np.full((footprint_size, *arr.shape), np.nan)
for p, element in enumerate(tqdm(arr.flatten())): # Iterate through each element
i, j = np.unravel_index(p, arr.shape)
# Create mask of elements to compare to
mask = ((i_all >= (i - (footprint[0] - 1) / 2)) &
(i_all <= (i (footprint[0] - 1) / 2)) &
(j_all >= (j - (footprint[1] - 1) / 2)) &
(j_all <= (j (footprint[1] - 1) / 2)))
# Create mask of those within the threshold
close_mask = abs(arr[mask] - element) <= threshold
if np.nansum(close_mask) < np.product(footprint): # If at edges need to pad to be able to index into output arrays
output_i[:, i, j] = np.pad(i_all[mask][close_mask].flatten().astype(float),
(int(footprint_size - np.nansum(close_mask)), 0),
mode='constant', constant_values=np.nan)
output_j[:, i, j] = np.pad(j_all[mask][close_mask].flatten().astype(float),
(int(footprint_size - np.nansum(close_mask)), 0),
mode='constant', constant_values=np.nan)
else: # Don't need to pad here
output_i[:, i, j] = i_all[mask][close_mask]
output_j[:, i, j] = j_all[mask][close_mask]
# Output: two 3D arrays of indices corresponding to elements within the threshold of the element of interest for rows and cols
這適用于小陣列,但當陣列有 ~10^6 個元素時非常慢。我的另一個想法是將陣列滑過自身來比較值。這可能會更快,但我很好奇是否有任何其他想法或內置函式可以做類似的事情。
uj5u.com熱心網友回復:
我不知道在哪里,但我很確定你的方法有一些錯誤。查看結果時,最后一個 (100x100) 子陣列包含所有索引。
我寫的結果看起來更好,速度提高了大約 1000 倍,但仍然需要您進行一些測驗。我可能犯了一些錯誤。
def faster_method(arr, threshold, footprint):
temp_arr = np.full((arr.shape[0] footprint[0] - 1, arr.shape[1] footprint[1] - 1), np.nan)
temp_arr[footprint[0] // 2: footprint[0] // 2 arr.shape[0],
footprint[1] // 2: footprint[1] // 2 arr.shape[1]] = arr
temp_i_all, temp_j_all = np.mgrid[-(footprint[0] // 2): arr.shape[0] footprint[0] // 2,
-(footprint[1] // 2): arr.shape[1] footprint[1] // 2]
footprint_size = np.product(footprint)
output_i = np.full((footprint_size, *arr.shape), np.nan)
output_j = np.full((footprint_size, *arr.shape), np.nan)
output_idx = 0
for neighbour_vertical_position in range(footprint[0]):
for neighbour_horizontal_position in range(footprint[0]):
if neighbour_vertical_position == footprint[0] // 2 and neighbour_horizontal_position == footprint[1] // 2:
# center point, not a neighbour, so we can keep np.nan for it everywhere
continue
current_neighbour = temp_arr[neighbour_horizontal_position: neighbour_horizontal_position arr.shape[0],
neighbour_vertical_position: neighbour_vertical_position arr.shape[1]]
current_i_all = temp_i_all[neighbour_horizontal_position: neighbour_horizontal_position arr.shape[0],
neighbour_vertical_position: neighbour_vertical_position arr.shape[1]]
current_j_all = temp_j_all[neighbour_horizontal_position: neighbour_horizontal_position arr.shape[0],
neighbour_vertical_position: neighbour_vertical_position arr.shape[1]]
is_close_array = np.abs(arr - current_neighbour) > threshold
output_i[output_idx] = current_i_all 0 / is_close_array
output_j[output_idx] = current_j_all 0 / is_close_array
return output_i, output_j
uj5u.com熱心網友回復:
使用 dankal444 的答案,我設法讓這個作業:
這比問題中的原始代碼(~1000 倍)快得多。
def slidingCompare(arr, footprint=(3, 3), threshold=0.5):
"""
arr: 2D array | input
footprint: tuple | search window dimensions (must be odd)
threshold: float | Threshold for neighbours to be close
"""
import numpy as np
assert footprint[0] % 2 == 1, "Footprint dimensions should be odd. "
assert footprint[0] % 2 == 1, "Footprint dimensions should be odd. "
temp_arr = np.full((arr.shape[0] footprint[0] - 1,
arr.shape[1] footprint[1] - 1), np.nan)
temp_arr[footprint[0] // 2:footprint[0] // 2 arr.shape[0],
footprint[1] // 2:footprint[1] // 2 arr.shape[1]] = arr
# Arrays for the row and col indices
i_all, j_all = np.mgrid[-(footprint[0] // 2):arr.shape[0] (footprint[0] // 2),
-(footprint[1] // 2):arr.shape[1] (footprint[1] // 2)]
# Footprint around the current element (ie looking at the 8 elements around the central value). Must be odd.
footprint_size = np.product(footprint)
# Prepare output for i and j indices
output_i = np.full((footprint_size, *arr.shape), np.nan)
output_j = np.full((footprint_size, *arr.shape), np.nan)
output_ix = np.arange(footprint_size).reshape(footprint)
for vert_pos in np.arange(footprint[0]):
for horiz_pos in np.arange(footprint[1]):
neighbour = temp_arr[vert_pos: vert_pos arr.shape[0],
horiz_pos: horiz_pos arr.shape[1]]
close_mask = abs(arr - neighbour) <= threshold
output_i[output_ix[vert_pos, horiz_pos], close_mask] = i_all[vert_pos: vert_pos arr.shape[0],
horiz_pos: horiz_pos arr.shape[1]][close_mask]
output_j[output_ix[vert_pos, horiz_pos], close_mask] = j_all[vert_pos: vert_pos arr.shape[0],
horiz_pos: horiz_pos arr.shape[1]][close_mask]
# Output: two 3D arrays of indices corresponding to elements within the threshold of the element of interest for rows and cols
return output_i, output_j
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/372134.html
