Суммарное суммирование числового массива по индексу - PullRequest
9 голосов
/ 31 августа 2010

Предположим, у вас есть массив значений, которые нужно будет суммировать вместе

d = [1,1,1,1,1]

и второй массив, определяющий, какие элементы должны суммироваться вместе

i = [0,0,1,2,2]

Результат будет сохранен в новом массиве размером max(i)+1. Например, i=[0,0,0,0,0] будет эквивалентно суммированию всех элементов d и сохранению результата в позиции 0 нового массива размером 1.

Я пытался реализовать это, используя

c = zeros(max(i)+1)
c[i] += d

Однако операция += добавляет каждый элемент только один раз, что дает неожиданный результат

[1,1,1]

вместо

[2,1,2]

Как правильно реализовать такое суммирование?

Ответы [ 5 ]

11 голосов
/ 11 сентября 2010

Если я правильно понял вопрос, для этого есть быстрая функция (при условии, что массив данных равен 1d)

>>> i = np.array([0,0,1,2,2])
>>> d = np.array([0,1,2,3,4])
>>> np.bincount(i, weights=d)
array([ 1.,  2.,  7.])

np.bincount возвращает массив для диапазона целых чисел (max (i)), даже если некоторые значения равны нулю

2 голосов
/ 17 июня 2014

Комментарий Juh_ является наиболее эффективным решением. Вот рабочий код:

import numpy as np
import scipy.ndimage as ni

i = np.array([0,0,1,2,2])
d = np.array([0,1,2,3,4])

n_indices = i.max() + 1
print ni.sum(d, i, np.arange(n_indices))
2 голосов
/ 02 сентября 2010

Это решение должно быть более эффективным для больших массивов (оно перебирает возможные значения индекса вместо отдельных записей i):

import numpy as np

i = np.array([0,0,1,2,2])
d = np.array([0,1,2,3,4])

i_max = i.max()
c = np.empty(i_max+1)
for j in range(i_max+1):
    c[j] = d[i==j].sum()

print c
[1. 2. 7.]
2 голосов
/ 31 августа 2010
def zeros(ilen):
 r = []
 for i in range(0,ilen):
     r.append(0)

i_list = [0,0,1,2,2]
d = [1,1,1,1,1]
result = zeros(max(i_list)+1)

for index in i_list:
  result[index]+=d[index]

print result
0 голосов
/ 02 июня 2015

В общем случае, когда вы хотите суммировать подматрицы по меткам, вы можете использовать следующий код

import numpy as np
from scipy.sparse import coo_matrix

def labeled_sum1(x, labels):
     P = coo_matrix((np.ones(x.shape[0]), (labels, np.arange(len(labels)))))
     res = P.dot(x.reshape((x.shape[0], np.prod(x.shape[1:]))))
     return res.reshape((res.shape[0],) + x.shape[1:])

def labeled_sum2(x, labels):
     res = np.empty((np.max(labels) + 1,) + x.shape[1:], x.dtype)
     for i in np.ndindex(x.shape[1:]):
         res[(...,)+i] = np.bincount(labels, x[(...,)+i])
     return res

Первый метод использует умножение разреженной матрицы. Второй - обобщение ответа пользователя 333700. Оба метода имеют сопоставимую скорость:

x = np.random.randn(100000, 10, 10)
labels = np.random.randint(0, 1000, 100000)
%time res1 = labeled_sum1(x, labels)
%time res2 = labeled_sum2(x, labels)
np.all(res1 == res2)

Выход:

Wall time: 73.2 ms
Wall time: 68.9 ms
True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...