Сумма numy элементов с данным индексом - PullRequest
0 голосов
/ 11 июня 2018

Этот код реализует регрессию одной переменной без перехвата.Это работает, но я не могу найти способ сделать это, не прибегая к использованию медленной итерации Python.Любые идеи?

# y: numpy array of n values, for large n
# coeff: numpy array of n values, for large n
# L : size of result
# l_indices : numpy array of indices from 0 to L-1

def simple_regression(y, coeff, L, l_index):
    numerator = y*coeff
    denominator = np.square(coeff)
    numsum = np.zeros(L)
    denomsum = np.zeros(L)
    for (n,d,l) in zip(numerator,denominator,l_index):
        numsum[l] += n
        denomsum[l] += d
    return numsum / denomsum

в основном операция, подобная следующей, которая не делает кучу выделения памяти:

 numsum[l] = np.sum(numerator[l_index == l])

(Выполнение этого способа намного ниже, чем мой первыйкод)

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

Вы можете использовать numpy.bincount:

import numpy as np

def simple_regression(y, coeff, L, l_index):
    numerator = y*coeff
    denominator = np.square(coeff)
    numsum = np.zeros(L)
    denomsum = np.zeros(L)
    for (n,d,l) in zip(numerator,denominator,l_index):
        numsum[l] += n
        denomsum[l] += d
    return numsum / denomsum

def simple_regression_pp(y, coeff, L, l_index):
    numerator = y*coeff
    denominator = np.square(coeff)
    numsum = np.bincount(l_index, numerator, L)
    denomsum = np.bincount(l_index, denominator, L)
    return numsum / denomsum

def simple_regression_br(y, coeff, L, l_index):
    numerator = y*coeff
    denominator = np.square(coeff)
    numsum = np.zeros(L)
    denomsum = np.zeros(L)
    np.add.at(numsum, l_index, numerator)
    np.add.at(denomsum, l_index, denominator)
    return numsum / denomsum

L, N = 1_000, 1_000_000
y, coeff = np.random.random((2, N))
l_index = np.random.randint(0, L, (N,))

from timeit import timeit

print('OP', timeit("simple_regression(y, coeff, L, l_index)", globals=globals(),
                   number=10), 'sec')
print('pp', timeit("simple_regression_pp(y, coeff, L, l_index)",
                   globals=globals(), number=10), 'sec')
print('br', timeit("simple_regression_br(y, coeff, L, l_index)",
                   globals=globals(), number=10), 'sec')

Пробный прогон:

OP 6.602819449035451 sec
pp 0.12009818502701819 sec
br 1.5504542298149318 sec
0 голосов
/ 11 июня 2018

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

numsum[l_index] += numerator
denomsum[l_index] += denominator

, если ваш индекс не известен как уникальный, вы можете сделать то же самое, используя numpy.add.at:

numpy.add.at(numsum, l_index, numerator)
numpy.add.at(denomsum, l_index, denominator)
...