2015-03-03 2 views
1

Скажем, у меня есть массив чиселуменьшить массив над диапазонами

np.array(([1, 4, 2, 1, 2, 5])) 

И я хочу, чтобы вычислить сумму по списку ломтиков

((0, 3), (2, 4), (2, 6)) 

Давать

[(1 + 4 + 2), (2 + 1), (2 + 1 + 2 + 5)] 

Есть ли хороший способ сделать это в numpy?

Ищете что-то эквивалентное

def reduce(a, ranges): 
    np.array(list(np.sum(a[low:high]) for (low, high) in ranges)) 

Похоже, есть, вероятно, некоторые фантазии NumPy способ сделать это, хотя. Кто-нибудь знает?

+0

Вы уже используете numpy. Что вам нужно больше? –

ответ

1

Один из способов - использовать np.add.reduceat. Если a это массив значений [1, 4, 2, 1, 2, 5]:

>>> np.add.reduceat(a, [0,3, 2,4, 2])[::2] 
array([ 7, 3, 10], dtype=int32) 

Здесь индексы среза передаются в список и суммируются для возврата [ 7, 1, 3, 2, 10] (то есть суммы a[0:3], a[3:], a[2:4], a[4:], a[2:]). Нам нужен только любой элемент из этого массива.


Longer альтернативный подход ...

Тот факт, что ломтики разной длины делает это немного сложнее vectorise в NumPy, но вот один из способов подойти к решению проблемы.

Учитывая массив значений и массив ломтиков, чтобы сделать ...

a = np.array(([1, 4, 2, 1, 2, 5])) 
slices = np.array([(0, 3), (2, 4), (2, 6)]) 

... создать маску, как массив z, что для каждого среза, будет использоваться для «нулевого выхода "значения из a мы не хотим подводить:

z = np.zeros((3, 6)) 
s1 = np.arange(6) >= s[:, 0][:,None] 
s2 = np.arange(6) < s[:, 1][:,None] 
z[s1 & s2] = 1 

Тогда вы можете сделать:

>>> (z * a).sum(axis=1) 
array([ 7., 3., 10.]) 

Быстрое %timeit показывает, что это немного быстрее, чем понимание списка, хотя нам пришлось построить z и z * a. Если slices имеет длину 3000, этот метод примерно в 40 раз быстрее.

Однако обратите внимание, что массив z будет иметь форму (len(slices), len(a)), которая не может быть столь же практичным, если a или slices оба очень долго - итеративный подход может быть предпочтительным, чтобы избежать больших временных массивов в памяти.

Смежные вопросы