0

This code implements a single variable regression without an intercept. It works, but I can't figure out a way to do it without resorting to using slow python iteration. Any ideas?

# 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

fundamentally an operation like the following, that doesn't do a bunch of memory allocation:

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

(Doing it that way is much lower then my first code)

2 Answers 2

1

You can use 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')

Sample run:

OP 6.602819449035451 sec
pp 0.12009818502701819 sec
br 1.5504542298149318 sec
Sign up to request clarification or add additional context in comments.

Comments

1

if you know your index l_index only has unique values, you can do:

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

if your index is not known to be unique you can do the same thing using numpy.add.at:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.