Наиболее эффективный способ работы с массивом n-dim на основе эталонного массива n-dim - PullRequest
0 голосов
/ 29 октября 2019

У меня есть два пустых массива одинаковой формы: dat_ara и ref_ara.

Я хотел бы выполнить операцию op_func на axis = -1 из dat_ara, однако я хотел бы толькодля работы с выбранным срезом значений в каждом массиве срез задается, когда пороговое значение thres пересекается с эталонным массивом ref_ara.

Для иллюстрации в простом случае, когда массивыпросто 2-dim, у меня есть:

thres = 4

op_func = np.average

ref_ara = array([[1, 2, 1, 4, 3, 5, 1, 5, 2, 5],
                 [1, 2, 2, 1, 1, 1, 2, 7, 5, 8],
                 [2, 3, 2, 5, 1, 6, 5, 2, 7, 3]]) 

dat_ara = array([[1, 0, 0, 1, 1, 1, 1, 0, 1, 1],
                 [1, 1, 1, 1, 1, 1, 1, 0, 1, 0],
                 [1, 0, 1, 1, 1, 1, 0, 1, 1, 1]]) 

Мы видим, что thres нарушен в 5-м, 7-м и 3-м индексе 1-го, 2-го и 3-го массива в axis=0 из ref_ara. Поэтому желаемый результат будет

out_ara = array([op_func(array([1, 0, 0, 1, 1, 1]), 
                 op_func(array([1, 1, 1, 1, 1, 1, 1, 0]),
                 op_func(array([1, 0, 1, 1])])

Эта проблема трудна, поскольку требует ссылки на ref_ara. Если бы это было не так, я мог бы просто использовать numpy.apply_along_axis.

Я попытался расширить размеры двух массивов, чтобы связать их для вычисления, то есть:

assos_ara = np.append(np.expand_dims(dat_ara, axis=-1), np.expand_dims(ref_ara, axis=-1), axis=-1)

Ноопять же, numpy.apply_along_axis требует, чтобы функция ввода работала только с 1-мерными массивами, и, таким образом, я все еще не могу использовать эту функцию.

Единственный другой способ, который я знаю, это перебирать индексы массивов, однако,с массивами, имеющими постоянные изменяющиеся размеры двух массивов, это сложный вопрос, более того, он неэффективен в вычислительном отношении.

Я бы очень хотел использовать векторизованные функции, чтобы помочь этому процессу. Какой самый эффективный способ это сделать?

1 Ответ

1 голос
/ 29 октября 2019

Это хороший вариант использования для замаскированных массивов, поскольку они позволяют вам выполнять обычные операции с пустыми частями над частями ваших данных.

Предположим, что каждая строка содержит хотя бы одно значение, которое больше, чемпорог. Вы можете вычислить индексы точек останова как

breaks = np.argmax(ref_ara > thres, axis=-1)   # 5, 7, 3

. Затем вы можете создать маску, используя ответ на вопрос , который я связывал ранее. Маски, как правило, являются лучшим способом обработки данных неправильной формы в numpy.

mask = np.arange(ref_ara.shape[-1]) <= breaks.reshape(*breaks.shape, 1)

Здесь нам не нужно делать что-то необычное с arange, потому что оно находится в последнем измерении. Если бы это было не так, вы бы хотели вставить 1 в форму разрывов, в которые будет помещен диапазон, и дополнить хвост формы диапазона также единицами.

Теперь замаскированный массив и ufuncрешения слегка расходятся. Версия маскированного массива является более общей, поэтому она стоит первой:

data = np.ma.array(data_ara, mask=~mask)

Маскированные массивы интерпретируют маску в обратном направлении по сравнению с обычным логическим индексированием, поэтому мы инвертируем маску. Кроме того, вы можете вычислить маску с > вместо <=. Вычисления теперь тривиальны:

out_ara = np.ma.average(data, axis=-1).data

Гораздо менее общая альтернатива - разбить вашу работу на уфунки и использовать маскировку, которую они предоставляют. Это просто для np.average, то есть просто np.sum и np.divide, но может быть сложнее для более сложных операций.

Начиная с numpy 1.17.0, np.sum имеет ключевое слово where:

out_ara = np.sum(dat_ara, where=mask, axis=-1) / breaks
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...