Поиск индекса стоимости в массивах 3D

1
import numpy as np
# The 3D arrays have the axis: Z, X, Y
arr_keys = np.random.rand(20, 5, 5)
arr_vals = np.random.rand(20, 5, 5)
arr_idx = np.random.rand(5, 5)

Для каждой ячейки сетки в arr_idx я хочу найти Z-позицию самого близкого к ней значения в arr_keys (но с тем же местоположением X, Y) и вернуть значение в соответствующей позиции в массиве arr_vals. Есть ли способ сделать это без использования вложенных циклов?

Итак, если значение при X = 0, Y = 0 для arr_idx равно 0,5, я хочу найти ближайший к нему номер при X = 0, Y = 0, Z изменяется от 0 до 10 в arr_keys, а затем я хочу используйте Z-позицию этого числа (давайте назовем Z_prime), чтобы найти значение в arr_vals (Z_prime, X = 0, Y = 0)

  • 0
    Можно ли организовать ваши arr_keys и arr_vals как 5x5x20 (то есть массив 5x5 с каждым элементом сетки, имеющим вектор длины 20)? Тогда я могу придумать простой способ решения проблемы, не уверенный, будет ли он работать с вашей текущей формой.
  • 0
    хм, разве вы не можете просто использовать команду numpy в конце, чтобы получить желаемую форму?
Показать ещё 4 комментария
Теги:
numpy

4 ответа

2
Лучший ответ

Это тип проблемы, для которой был создан np.take_along_axis:

# shape (20, 5, 5)
diff = np.abs(arr_idx - arr_keys)

# argmin(..., keepdims=True) doesn't exist yet - this emulates it
# shape (1, 5, 5)
inds = np.expand_dims(np.argmin(diff, axis=0), axis=0)

# shape (1, 5, 5)
res = np.take_along_axis(arr_vals, inds, axis=0)

# shape (5, 5)
res = res.squeeze(axis=0)
  • 0
    спасибо @Eric, я был бы признателен, если бы вы могли добавить некоторые объяснения. Это выглядит как отличный soln
3

Я думаю, что ответ @xnx довольно хорош. Шахта длиннее, но я все равно отправлю ее;).

Кроме того, примечание: NumPy предназначен для эффективной обработки больших многомерных массивов путем векторизации операций. Поэтому я предложил бы избежать for петель как можно больше. Независимо от задачи, которую вы ищете, существует (как правило) способ сделать это, избегая циклов.

arr_keys = np.split(arr_keys, 20)
arr_keys = np.stack(arr_keys, axis=-1)[0]
arr_vals = np.split(arr_vals, 20)
arr_vals = np.stack(arr_vals, axis=-1)[0]

arr_idx = np.expand_dims(arr_idx, axis=-1)

difference = np.abs(arr_keys - arr_idx)
minimum = np.argmin(difference, axis=-1)

result = np.take_along_axis(arr_vals, np.expand_dims(minimum, axis=-1), axis=-1)
result = np.squeeze(result, axis=-1)
  • 0
    спасибо @Rohan, ответ от вашего soln, похоже, не соответствует решению xnx. Есть идеи, почему это может быть?
  • 0
    Хм, это странно. Дай мне проверить.
Показать ещё 2 комментария
2

Я думаю, что это может сработать: сверните оси в правильную ориентацию, найдите индекс значения (абсолютного) минимума для каждого из значений 5x5 X, Y и возьмите соответствующие значения Z из arr_vals:

idx = np.argmin(np.abs(np.rollaxis(arr_keys,0,3) - arr_idx[:,:,None]), axis=2)
i,j = np.ogrid[:5,:5]
arr_vals[idx[i,j],i,j]

Чтобы проверить это, попробуйте (3,2,2) случай:

In [15]: arr_keys
Out[15]: 
array([[[ 0.19681533,  0.26897784],
        [ 0.60469711,  0.09273087]],

       [[ 0.04961604,  0.3460404 ],
        [ 0.88406912,  0.41284309]],

       [[ 0.46298201,  0.33809574],
        [ 0.99604152,  0.4836324 ]]])

In [16]: arr_vals
Out[16]: 
array([[[ 0.88865681,  0.88287688],
        [ 0.3128103 ,  0.24188022]],

       [[ 0.23947227,  0.57913325],
        [ 0.85768064,  0.91701097]],

       [[ 0.78105669,  0.84144339],
        [ 0.81071981,  0.69217687]]])

In [17]: arr_idx
Out[17]: 
array([[[ 0.31352609],
        [ 0.75462329]],

       [[ 0.44445286],
        [ 0.97086161]]])

дает:

array([[ 0.88865681,  0.57913325],
       [ 0.3128103 ,  0.69217687]])
  • 0
    Спасибо! Что концептуально делает np.rollaxis(arr_keys,0,3) ? Изменится ли 3 если моя форма массива станет (200, 100, 50)?
  • 1
    Он поворачивает первую ось «назад», пока не окажется последней, поэтому (20,5,5) становится (5,5,20): см. Docs.scipy.org/doc/numpy/reference/generated/… - очевидно, эта функция должна быть заменена на Moveaxis в NumPy версии 1.11
Показать ещё 4 комментария
0

Немного подробней, чем уже размещенное решение, но легче понять.

import numpy as np
# The 3D arrays have the axis: Z, X, Y
arr_keys = np.random.rand(20, 5, 5)
arr_vals = np.random.rand(20, 5, 5)
arr_idx = np.random.rand(5, 5)

arr_idx = arr_idx[np.newaxis, :, :]
dist = np.abs(arr_idx - arr_keys)
dist_ind = np.argmin(dist, axis=0)
x = np.arange(0, 5, 1)
y = np.arange(0, 5, 1)
xx, yy = np.meshgrid(x, y)

res = arr_vals[dist_ind, yy, xx]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню