2015-05-14 2 views
1

Итак, у меня есть этот массив, правильно?Назначить массив, добавив несколько копий индекса

a=np.zeros(5) 

Я хочу добавить к нему значения по заданным индексам, где индексы могут быть дублирующими.

например.

a[[1, 2, 2]] += [1, 2, 3] 

Я хочу, чтобы это произвести array([ 0., 1., 5., 0., 0.]), но ответ я получаю array([ 0., 1., 3., 0., 0.]).

Мне бы хотелось, чтобы это работало с многомерными массивами и вещательными индексами и всем этим. Есть идеи?

ответ

3

Вам необходимо использовать np.add.at, чтобы обойти проблему буферизации, с которой вы сталкиваетесь с += (значения не накапливаются при повторных индексах). Укажите массив, индексы и значение для добавления в месте этих показателей:

>>> a = np.zeros(5) 
>>> np.add.at(a, [1, 2, 2], [1, 2, 3]) 
>>> a 
array([ 0., 1., 5., 0., 0.]) 

at является частью других ufuncs тоже (умножение, деление, и так далее). Этот метод также будет работать для многомерных массивов.

1

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

Вот реализация -

import numpy as np 

a=np.zeros(5)  # initialize output array 

idx = [1, 2, 2]  # indices 
vals = [1, 2, 3]  # values 

a[:max(idx)+1] = np.bincount(idx,vals) # finally store the bincounts 

выполнение тесты

Вот некоторое время выполнения тесты для двух наборов входных datasizes сравнения предлагаемых bincount подхода, основанного и на основе подхода add.at, перечисленный в other answer:

Datasize # 1 -

In [251]: a=np.zeros(1000) 
    ...: idx = np.sort(np.random.randint(1,1000,(500))).tolist() 
    ...: vals = np.random.rand(500).tolist() 
    ...: 

In [252]: %timeit np.add.at(a, idx, vals) 
10000 loops, best of 3: 63.4 µs per loop 

In [253]: %timeit a[:max(idx)+1] = np.bincount(idx,vals) 
10000 loops, best of 3: 42.4 µs per loop 

DataSize # 2 -

In [254]: a=np.zeros(10000) 
    ...: idx = np.sort(np.random.randint(1,10000,(5000))).tolist() 
    ...: vals = np.random.rand(5000).tolist() 
    ...: 

In [255]: %timeit np.add.at(a, idx, vals) 
1000 loops, best of 3: 597 µs per loop 

In [256]: %timeit a[:max(idx)+1] = np.bincount(idx,vals) 
1000 loops, best of 3: 404 µs per loop 
Смежные вопросы