Python 用数组参数对函数进行矢量化

Python 用数组参数对函数进行矢量化,python,numpy,vectorization,chi-squared,Python,Numpy,Vectorization,Chi Squared,我目前正在尝试对一些数据进行卡方分析。 我想根据模型的两个系数绘制一个不同值的彩色地图 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(v

我目前正在尝试对一些数据进行卡方分析。 我想根据模型的两个系数绘制一个不同值的彩色地图

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的1D数组。 u,v是各种变化系数

但是,这不起作用,导致
索引器错误:标量变量的索引无效。

这是因为coeff是作为标量而不是向量传递的,但是我不知道如何纠正这一点

更新

我的目标是获取一组坐标

rs = [[[u0, v0], [u1, v0],..,[un, v0]],...,[[u0, vm],..,[un,vm]]
其中,每个坐标是传递给卡方法的系数参数。 这将返回一个二维数组,其中填充了相应坐标的卡方值

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\u 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
现在,将
矢量化的目的是什么

f
函数返回一个(n,n)数组:

让我们修改
卡方
以给出

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
值与
x
y
等的关系,我发现这可以通过简单的广播解决。无需使用
np.vectorize

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

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)
现在看看当给定此
coeff
x
时,f
是什么样子

In [137]: f(x, coeff[...,None]).shape
Out[137]: (4, 5, 3)
coeff
是有效的(4,5,1),而
x
是(1,1,3),导致(4,5,3)(根据广播规则)

卡方
中也会发生同样的情况,最后一步是
求和
在最后一个轴上(大小3):


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

New
vectorize
接受一个
签名
参数。如果您提供一个示例
f
函数,我们可能能够计算出正确的签名。看起来我需要示例
x
y
。我还想知道您是否需要
向量化
中的表达式可能是b路演数组正确。总之,我们需要更多的工作示例。假设f是一个二阶多项式,并添加了一个指数项。将使用一个工作示例进行更新是
x
y
y\u错误
标量,还是它们需要包含在广播中?另一个需要注意的是
rs
from
meshgrid
是一个包含2个数组的列表。
vectorize
将其包装在
np.asarray
中,生成一个3d数组。
np.sum
不带轴,返回一个值(即它对展平数组求和)。此“工作示例”包括:未定义的u0、未定义的u1、未定义的n、未定义的v0、未定义的v1、未定义的x、未定义的y、未定义的y_错误,以及卡方函数中不匹配的括号。这不是我对工作示例的想法。无论如何,hpaulj已经告诉你答案:meshgrid不做你认为它做的事情,请再次阅读它的描述。抱歉。我没有理解iliar有一个工作示例的概念,特别是因为我没有这样的工作代码。我已经研究了meshgrid,我正在更新我的代码这很接近,我想生成一个卡方值的2D数组Perfect!谢谢,看起来我需要对广播做更多的阅读,我只知道基本知识。一个问题,我需要什么将系数传递为系数[…,无]
In [137]: f(x, coeff[...,None]).shape
Out[137]: (4, 5, 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)