首页 > 解决方案 > How to fix broadcasting issues with numpy.vectorize()

问题描述

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?

标签: pythonnumpyvectorizationarray-broadcasting

解决方案


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])

推荐阅读