向量化具有数组参数的函数

Vectorizing A Function With Array Parameter

我目前正在尝试对某些数据应用卡方分析。 我想根据模型的两个系数绘制不同值的颜色图

def f(x, coeff):
    return coeff[0] + numpy.exp(coeff[1] * x)

def chi_squared(coeff, x, y, y_err):
    return numpy.sum(((y - f(x, coeff) / y_err)**2)

us = numpy.linspace(u0, u1, n)
vs = numpy.linspace(v0, v1, n)
rs = numpy.meshgrid(us, vs)

chi = numpy.vectorize(chi_squared)
chi(rs, x, y, y_error)

我尝试对函数进行矢量化,以便能够传递不同系数的网格来生成颜色图。

x,y的值y_err都是长度为n的一维数组。 而u、v是各种变化系数。

但是这不起作用,导致 IndexError: invalid index to scalar variable.

这是因为 coeff 是作为标量而不是向量传递的,但是我不知道如何更正它。

更新

我的目标是获取坐标数组

rs = [[[u0, v0], [u1, v0],..,[un, v0]],...,[[u0, vm],..,[un,vm]]

其中每个坐标都是传递给卡方法的系数参数。 这应该 return 一个二维数组,其中填充了适当坐标的卡方值

chi = [[c00, c10, ..., cn0], ..., [c0m, c1m, ..., cnm]]

然后我可以使用此数据使用 imshow 绘制颜色图

这是我第一次尝试 运行 您的代码:

In [44]: def f(x, coeff):
    ...:     return coeff[0] + numpy.exp(coeff[1] * x)
    ...: 
    ...: def chi_squared(coeff, x, y, y_err):
    ...:     return numpy.sum((y - f(x, coeff) / y_err)**2)

(我不得不删除最后一行的 (

首先猜测可能的数组值:

In [45]: x = np.arange(3)
In [46]: y = x
In [47]: y_err = x
In [48]: us = np.linspace(0,1,3)
In [49]: rs = np.meshgrid(us,us)
In [50]: rs
Out[50]: 
[array([[ 0. ,  0.5,  1. ],
        [ 0. ,  0.5,  1. ],
        [ 0. ,  0.5,  1. ]]), 
 array([[ 0. ,  0. ,  0. ],
        [ 0.5,  0.5,  0.5],
        [ 1. ,  1. ,  1. ]])]

In [51]: chi_squared(rs, x, y, y_err)
/usr/local/bin/ipython3:5: RuntimeWarning: divide by zero encountered in true_divide
  import sys
Out[51]: inf

哎呀,y_err 不应该是 0。再试一次:

In [52]: y_err = np.array([1,1,1])
In [53]: chi_squared(rs, x, y, y_err)
Out[53]: 53.262865105526018

如果我将 rs 列表转换为数组,它也有效:

In [55]: np.array(rs).shape
Out[55]: (2, 3, 3)
In [56]: chi_squared(np.array(rs), x, y, y_err)
Out[56]: 53.262865105526018

现在,vectorize 的目的是什么?

f函数returns一个(n,n)数组:

In [57]: f(x, rs)
Out[57]: 
array([[ 1.        ,  1.5       ,  2.        ],
       [ 1.        ,  2.14872127,  3.71828183],
       [ 1.        ,  3.21828183,  8.3890561 ]])

让我们修改 chi_squaredsum 一个轴

In [61]: def chi_squared(coeff, x, y, y_err, axis=None):
    ...:     return numpy.sum((y - f(x, coeff) / y_err)**2, axis=axis)

In [62]: chi_squared(np.array(rs), x, y, y_err)
Out[62]: 53.262865105526018

In [63]: chi_squared(np.array(rs), x, y, y_err, axis=0)
Out[63]: array([  3.        ,   6.49033483,  43.77253028])

In [64]: chi_squared(np.array(rs), x, y, y_err, axis=1)
Out[64]: array([  1.25      ,   5.272053  ,  46.74081211])

我很想将 coeff 更改为 coeff0, coeff1,以便从一开始就对该参数的传递方式给予更多控制,但这可能没有什么不同。

更新

既然您已经更具体地说明了 coeff 值与 xy 等的关系,我认为这可以通过简单的广播来解决。无需使用 np.vectorize.

首先,定义一个不同大小的网格;这样我们和代码就不会认为 coeff 网格的每个维度都与 xy 值有任何关系。

In [134]: rs = np.meshgrid(np.linspace(0,1,4), np.linspace(0,1,5), indexing='ij')
In [135]: coeff=np.array(rs)
In [136]: coeff.shape
Out[136]: (2, 4, 5)

现在看看给定 coeffxf 的样子。

In [137]: f(x, coeff[...,None]).shape
Out[137]: (4, 5, 3)

coeff 实际上是 (4,5,1),而 x 是 (1,1,3),结果是 (4,5,3)(通过广播规则)

同样的事情发生在 chi_squared 内部,最后一步 sum 在最后一个轴上(尺寸 3):

In [138]: chi_squared(coeff[...,None], x, y, y_err, axis=-1)
Out[138]: 
array([[  2.        ,   1.20406718,   1.93676807,   8.40646968,
         32.99441808],
       [  2.33333333,   2.15923164,   3.84810347,  11.80559574,
         38.73264336],
       [  3.33333333,   3.78106277,   6.42610554,  15.87138846,
         45.13753532],
       [  5.        ,   6.06956056,   9.67077427,  20.60384785,
         52.20909393]])
In [139]: _.shape
Out[139]: (4, 5)

coeff 对值一个值,(4,5) 网格。