【问题标题】:scipy smart optimizescipy 智能优化
【发布时间】:2011-03-06 21:29:50
【问题描述】:

我需要用直线拟合来自不同数据集的一些点。从每个数据集中我想拟合一条线。所以我得到了描述 i 线的参数 ai 和 bi:ai + bi*x。问题是我想强制每个 ai 都相等,因为我想要相同的截距。我在这里找到了一个教程:http://www.scipy.org/Cookbook/FittingData#head-a44b49d57cf0165300f765e8f1b011876776502f。不同之处在于我不知道我有多少数据集。我的代码是这样的:

from numpy import *
from scipy import optimize

# here I have 3 dataset, but in general I don't know how many dataset are they
ypoints = [array([0, 2.1, 2.4]),    # first dataset, 3 points
           array([0.1, 2.1, 2.9]),  # second dataset
           array([-0.1, 1.4])]      # only 2 points

xpoints = [array([0, 2, 2.5]),      # first dataset
           array([0, 2, 3]),        # second, also x coordinates are different
           array([0, 1.5])]         # the first coordinate is always 0

fitfunc = lambda a, b, x: a + b * x
errfunc = lambda p, xs, ys: array([ yi - fitfunc(p[0], p[i+1], xi) 
                                    for i, (xi,yi) in enumerate(zip(xs, ys)) ])


p_arrays = [r_[0.]] * len(xpoints)
pinit = r_[[ypoints[0][0]] + p_arrays]
fit_parameters, success = optimize.leastsq(errfunc, pinit, args = (xpoints, ypoints))

我明白了

Traceback (most recent call last):
  File "prova.py", line 19, in <module>
    fit_parameters, success = optimize.leastsq(errfunc, pinit, args = (xpoints,    ypoints))
  File "/usr/lib64/python2.6/site-packages/scipy/optimize/minpack.py", line 266, in  leastsq
    m = check_func(func,x0,args,n)[0]
  File "/usr/lib64/python2.6/site-packages/scipy/optimize/minpack.py", line 12, in  check_func
    res = atleast_1d(thefunc(*((x0[:numinputs],)+args)))
  File "prova.py", line 14, in <lambda>
    for i, (xi,yi) in enumerate(zip(xs, ys)) ])
ValueError: setting an array element with a sequence.

【问题讨论】:

    标签: python optimization scipy


    【解决方案1】:

    如果您只需要线性拟合,那么最好使用线性回归而不是非线性优化器来估计它。 使用 scikits.statsmodels 可以获得更多拟合统计信息。

    import numpy as np
    from numpy import array
    
    ypoints = np.r_[array([0, 2.1, 2.4]),    # first dataset, 3 points
               array([0.1, 2.1, 2.9]),  # second dataset
               array([-0.1, 1.4])]      # only 2 points
    
    xpoints = [array([0, 2, 2.5]),      # first dataset
               array([0, 2, 3]),        # second, also x coordinates are different
               array([0, 1.5])]         # the first coordinate is always 0
    
    xp = np.hstack(xpoints)
    indicator = []
    for i,a in enumerate(xpoints):
        indicator.extend([i]*len(a))
    
    indicator = np.array(indicator)
    
    
    x = xp[:,None]*(indicator[:,None]==np.arange(3)).astype(int)
    x = np.hstack((np.ones((xp.shape[0],1)),x))
    
    print np.dot(np.linalg.pinv(x), ypoints)
    # [ 0.01947973  0.98656987  0.98481549  0.92034684]
    

    回归矩阵有一个共同的截距,但每个数据集的列不同:

    >>> x
    array([[ 1. ,  0. ,  0. ,  0. ],
           [ 1. ,  2. ,  0. ,  0. ],
           [ 1. ,  2.5,  0. ,  0. ],
           [ 1. ,  0. ,  0. ,  0. ],
           [ 1. ,  0. ,  2. ,  0. ],
           [ 1. ,  0. ,  3. ,  0. ],
           [ 1. ,  0. ,  0. ,  0. ],
           [ 1. ,  0. ,  0. ,  1.5]])
    

    【讨论】:

    • 谢谢,我喜欢。问题是现在我需要使用错误,我的意思是:y 点有错误,我需要用 1/error^2 对它们进行加权。我怎样才能用你的代码做到这一点?
    • 最好的方法是使用 scikits.statsmodels,因为在这种情况下,所有的估计、预测和结果统计都是预制的。 pypi.python.org/pypi/scikits.statsmodels/0.2.0 和链接以获取预测的 y 参数 = np.dot(np.linalg.pinv(x), ypoints) ypred = np.dot(x, params) 错误 = ypoints - ypred ...如果你的意思是称重误差,要使用加权最小二乘法,那么 x 和 y 点都需要除以误差标准差,或者使用 scikits.statsmodels 中的 WLS 类。
    【解决方案2】:

    (旁注:使用def,而不是分配给名称的lambda——这完全是愚蠢的,而且只有缺点,lambda 的唯一用途是制作匿名函数! )。

    您的errfunc 应该返回一个浮点数序列(数组或其他),但事实并非如此,因为您试图将数组作为数组的项,这些数组是每个 y 点的差异(请记住,ypoints 又名ys 是一个数组列表!)和拟合函数的结果。因此,您需要将表达式yi - fitfunc(p[0], p[i+1], xi)“折叠”为单个浮点数,例如norm(yi - fitfunc(p[0], p[i+1], xi)).

    【讨论】:

    • 看不懂链接中例子的区别
    • @Wiso,该代码非常晦涩(带有未记录的r_ 等),但我确信它最终会从 errfunc 返回一系列浮点数,因为这是文档所需要的-- 使用调试器检查或使用prints 进行检测以验证您是否可以自己成功运行该代码(我不能——r_ 是什么?!)。
    • 好的,我解决了。通常 scipy 有据可查,r_ 函数在这里:docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html 解决方案是将array 更改为concatenate 以获得您所说的唯一数组。特别是我得到了系数:[ 0.01947973 0.98656987 0.98481549 0.92034684],它们似乎是正确的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 2017-03-24
    • 2022-01-11
    • 2017-03-11
    • 2014-09-05
    • 1970-01-01
    相关资源
    最近更新 更多