Cleb
Cleb

Reputation: 25997

How to efficiently populate an array with values from different functions?

I have an array x of length n_x, an array all_par1 of length n_par1 and a single parameter par2. Furthermore, two functions func1 and func2 that take these parameters and x as input.

I want to create an array with the dimensions n_x x 2 * n_par1, where the first half of the columns is populated with the values from func1 and the second half with values from func2.

I currently do it like this:

import numpy as np


def func1(x, par1):
    return x / (par1 + x)


def func2(x, par1, par2):
    return -par1 * x / ((par2 + x) ** 2)


def populate_matrix(xvec, par1_vec, par2):

    first_half = np.stack((func1(xvec, par1_i) for par1_i in par1_vec), axis=1)
    second_half = np.stack((func2(xvec, par1_i, par2) for par1_i in par1_vec), axis=1)

    return np.concatenate((first_half, second_half), axis=1)


np.random.seed(0)

all_par1 = [1., 2., 3.]
my_par2 = 5.

n_x = 2
x_variable_length = np.random.rand(n_x)
print x_variable_length

mat = populate_matrix(x_variable_length, all_par1, my_par2)

This gives me then e.g.

[[ 0.35434447  0.21532117  0.15464704 -0.01782479 -0.03564959 -0.05347438]
 [ 0.416974    0.26340313  0.19250415 -0.02189575 -0.0437915 -0.06568725]]

As n_x is 2, it has two rows, the first half of columns is generated with func1 which is always positive, the second half with values from func2 which are always negative.

I need to call this function a lot of times and I am wondering whether this is the most efficient way of doing it. Any ideas?

Not sure whether it is of interest but the actual dimensions are something like 300 x 100.

Upvotes: 0

Views: 259

Answers (1)

B. M.
B. M.

Reputation: 18628

Here is the vectored way for a 10x improvement on big arrays (100x200 in the tests) :

def populate_matrix_v(xvec, par1_vec, par2):
    n,m=xvec.size,par1_vec.size
    res= np.empty((n,m+m))
    res[:,:m]=func1(x_variable_length[:,None],par1_vec)
    res[:,m:]=func2(x_variable_length[:,None], par1_vec, par2) 
    return res

In [377]: %timeit matv = populate_matrix_v(x_variable_length, all_par1, my_par2)
171 µs ± 6.13 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [378]: %timeit mat = populate_matrix(x_variable_length, all_par1, my_par2)
1.88 ms ± 61.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Upvotes: 1

Related Questions