2015-09-26 2 views
3

У меня есть приложение, в котором мне нужно суммировать произвольные группы индексов в массиве 3D NumPy. Встроенная процедура суммирования массива NumPy суммирует все индексы вдоль одного из размеров ndarray. Вместо этого мне нужно суммировать диапазоны индексов вдоль одного из измерений в моем массиве и возвращать новый массив.NumPy sum вдоль непересекающихся индексов

Например, предположим, что у меня есть ndarray с формой (70,25,3). Я хочу суммировать первое измерение вдоль определенных диапазонов индексов и возвращать новый 3D-массив. Рассмотрим сумму от 0:25, 25:50 и 50:75, которая вернет массив формы (3,25,3).

Есть ли простой способ сделать «несвязанные суммы» по одному измерению массива NumPy для получения этого результата?

+0

Являются ли эти * диапазоны * того же диапазона? – Divakar

ответ

8

Вы можете использовать np.add.reduceat как общий подход к этой проблеме. Это работает, даже если диапазоны не имеют одинаковой длины.

Подводя ломтики 0:25, 25:50 и 50:75 вдоль оси 0, проходит в индексах [0, 25, 50]:

np.add.reduceat(a, [0, 25, 50], axis=0) 

Этот метод также может быть использован для суммирования несмежных диапазонов. Например, чтобы подвести ломтики 0:25, 37:47 и 51:75, написать:

np.add.reduceat(a, [0,25, 37,47, 51], axis=0)[::2] 

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

a.reshape(3, a.shape[0]//3, a.shape[1], a.shape[2]).sum(axis=1) 
+0

Вам не нужны повторяющиеся индексы, если диапазоны смежны, i.е. '[0, 25, 50]' будет выполнять ту же работу в этом случае. – Jaime

+0

@Jaime: О! Спасибо за улучшение - я обновлю ответ. –

+0

Большое спасибо за это решение, оно работает точно так, как я надеялся! – wbinventor

1

Вы можете использовать np.split, чтобы разделить ваш массив затем использовать np.sum суммировать ваши детали вдоль второй оси:

np.sum(np.split(my_array,3),axis=1) 

Демо:

>>> a=np.arange(270).reshape(30,3,3) 
>>> np.sum(np.split(a,3),axis=1) 
array([[[ 405, 415, 425], 
     [ 435, 445, 455], 
     [ 465, 475, 485]], 

     [[1305, 1315, 1325], 
     [1335, 1345, 1355], 
     [1365, 1375, 1385]], 

     [[2205, 2215, 2225], 
     [2235, 2245, 2255], 
     [2265, 2275, 2285]]]) 

Также обратите внимание, что если у вас есть различные длины среза вы можете передать конец вам ломтиков до np.split функции:

>>> new=np.sum(np.split(a,[10,20,]),axis=1) 
>>> new 
array([[[ 405, 415, 425], 
     [ 435, 445, 455], 
     [ 465, 475, 485]], 

     [[1305, 1315, 1325], 
     [1335, 1345, 1355], 
     [1365, 1375, 1385]], 

     [[2205, 2215, 2225], 
     [2235, 2245, 2255], 
     [2265, 2275, 2285]]]) 
+0

'' 'np.split''' принимает произвольный массив индексов в качестве аргумента вместо целого (для четного разделения) - можете ли вы заставить его работать для * произвольного split *? – wwii

+0

@wwii Действительно, обновлено! – Kasramvd

+0

@ Kasramvd: Я думаю, что точка @ wwii заключалась в том, что для использования подхода «split» здесь диапазоны должны иметь одинаковую длину. Если бы нам нужны диапазоны разной длины вдоль оси, например, такие, которые указаны в 'np.split (a, [10,15,30])', мы не можем суммировать их так, как показывает этот ответ. –

1

Просто суммируйте каждую часть и используйте результаты для создания нового массива.

import numpy as np 
i1, i2 = (2,7) 

a = np.ones((10,5,3)) 
b = np.sum(a[0:i1,...], 0) 
c = np.sum(a[i1:i2,...], 0) 
d = np.sum(a[i2:,...], 0) 

g = np.array([b,c,d]) 

>>> g.shape 
(3, 5, 3) 
>>> g 
array([[[ 2., 2., 2.], 
     [ 2., 2., 2.], 
     [ 2., 2., 2.], 
     [ 2., 2., 2.], 
     [ 2., 2., 2.]], 

     [[ 5., 5., 5.], 
     [ 5., 5., 5.], 
     [ 5., 5., 5.], 
     [ 5., 5., 5.], 
     [ 5., 5., 5.]], 

     [[ 3., 3., 3.], 
     [ 3., 3., 3.], 
     [ 3., 3., 3.], 
     [ 3., 3., 3.], 
     [ 3., 3., 3.]]]) 
>>> 
Смежные вопросы