1

I am writing a custom function that I want to have behaving as if it where a numpy-function, having the ability to take in an array, and perform the same operation on every element of the input list, and returning a list of same shape with all the results.

Luckily, there is a solution for this: numpy.vectorize()

So I used that: I have a function that creates a model in the form of a sine wave, and it takes in two variables: one numpy list X containing some input values for the sine function, and one numpy list param that contains the four possible parameters that a sine curve can have.

import numpy as np
def sine(X, param):
    #Unpacking param
    A = param[0]
    P = param[1]
    Phi = param[2]
    B = param[3]

    #translating variables
    #Phi = t0/P
    f = X/P
    Y = A*np.sin(2*np.pi*(f + Phi)) + B
    return Y

Because only the input values X need the broadcasting while the all the parameters are necessary all the time, so, according to the documentation, the way to vecorise the function is as follows:

np_sine = np.vectorize(sine, excluded=['param']) #makes sine() behave like a numpy function

...so that param is properly excluded from vectorisation.

This method is useful, since I will be fitting this model to a dataset, which requires occasionally tweaking the parameters, meanwhile, with this method the code where I need it is only one line long:

CHIsqrt = np.sum(((ydata - np_sine(xdata, param))/yerr)**2)

where ydata, xdata and yerr are equally long lists of datapoints and where param is the list of four parameters.

Yet, the result was a broadcasting error:

 File "C:\Users\Anonymous\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\function_base.py", line 2831, in _vectorize_call outputs = ufunc(*inputs)
 ValueError: operands could not be broadcast together with shapes (500,) (4,)

Since the list param is 4 elements long, I get that the function ignored my commands to exclude it from vectorisation. That is a problem.

I tried specifying that the end result should be a ndArray, which did not change the error.

np_sine = np.vectorize(sine, excluded=['param'], otypes=[np.ndarray])

What would be the correct way to use this function?

0

1 Answer 1

1

You've specified excluded wrong.

In [270]: def foo(x, param):
     ...:     a,b,c = param
     ...:     return a*x
     ...: 
In [271]: f = np.vectorize(foo, excluded=[1])  # specify by position
In [272]: f(np.arange(4),[1,3,2])
Out[272]: array([0, 1, 2, 3])

For a keyword arg:

In [277]: def foo(x, param=[0,0,0]):
     ...:     a,b,c = param
     ...:     return a*x
     ...:
In [278]: f = np.vectorize(foo, excluded=['param'])
In [279]: f(np.arange(4),param=[1,3,2])
Out[279]: array([0, 1, 2, 3])
Sign up to request clarification or add additional context in comments.

3 Comments

Interesting that using the string does not work for normal arguments. The documentation has an example saying >>> def mypolyval(p, x): which clearly has two normal arguments. Then it goes on to exclude p by saying >>> vpolyval = np.vectorize(mypolyval, excluded=['p']). Your solution works, so the documentation is wrong.
But in the example p is passed as keyword parameter, p=[1, 2, 3]. vpolyval([1, 2, 3], x=[0, 1]) only works after .excluded.add(0). Excluded may actually be referring to the parameter in the vectorized function, not the source (though in a sense they are the same).
Your named excluded might work with np_sine(xdata, param=param).

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.