Python 为什么元组列表作为optimize.leasztsq的参数失败?

Python 为什么元组列表作为optimize.leasztsq的参数失败?,python,scipy,format,least-squares,Python,Scipy,Format,Least Squares,我使用scipy.optimize中的函数leastsq来拟合三维坐标中的球体坐标和半径 因此,我的代码如下所示: def distance(pc,point): xc,yc,zc,rd = pc x ,y ,z = point return np.sqrt((xc-x)**2+(yc-y)**2+(zc-z)**2) def sphere_params(coords): from scipy import optimize err = l

我使用scipy.optimize中的函数leastsq来拟合三维坐标中的球体坐标和半径

因此,我的代码如下所示:

def distance(pc,point):

    xc,yc,zc,rd = pc
    x ,y ,z     = point
    return np.sqrt((xc-x)**2+(yc-y)**2+(zc-z)**2)

def sphere_params(coords):

    from scipy import optimize

    err = lambda pc,point : distance(pc,point) - pc[3]

    pc = [0, 0, 0, 1]
    pc, success = optimize.leastsq(err, pc[:], args=(coords,))

    return pc
(由于以下原因而建造:)

我开始使用变量coords作为元组列表(每个元组是x,y,z坐标):

这让我犯了一个错误:

>> pc = sphere_params(coords)
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/home/michel/anaconda/lib/python2.7/site-packages/scipy/optimize/minpack.py", line 374, in leastsq
     raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m))
TypeError: Improper input: N=4 must not exceed M=3
除非我弄错了,在我的情况下,它会转化为

res = atleast_1d(distance(*(pc[:len(pc)],) + args)
但是我花了很长时间试图理解这意味着什么,以及_check_func()函数的其余部分

最后,我将coords更改为一个数组,然后将其作为
sphere_param()
的参数:
coords=np.asarray(coords).T
,它开始正常工作。我真的很想理解为什么数据格式给我带来麻烦

在此,非常感谢您的回答


编辑:我注意到我在“distance”和“err”函数中使用coords是不明智和误导性的,在我的原始代码中不是这样,所以它不是问题的核心。现在让我们来解释一下。

虽然我没有太多地使用这个函数,但据我所知,
coords
会按原样传递给您的
distance
函数。如果允许错误检查,至少会这样。事实上,错误检查可能会尝试这样做,如果
distance
引发错误,则会引发错误。让我们试试看

In [91]: coords=[(0,0,0),(0,0,1),(-1,0,0),(0.57,0.57,0.57),(1,0,0),(0,1,0)]

In [92]: distance([0,0,0,0],coords)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-92-113da104affb> in <module>()
----> 1 distance([0,0,0,0],coords)

<ipython-input-89-64c557cd95e0> in distance(pc, coords)
      2 
      3         xc,yx,zx,rd = pc
----> 4         x ,y ,z     = coords
      5         return np.sqrt((xc-x)**2+(yc-y)**2+(zc-z)**2)
      6 

ValueError: too many values to unpack (expected 3)
同样的错误

distance([0,0,0,0],np.array(coords).T)
超过该问题(可拆分为3个变量的3行),将引发另一个错误:
NameError:未定义名称“yc”

这看起来像是你给我们的密码输入错误!淘气,淘气

更正如下:

In [97]: def distance(pc,coords):

        xc,yc,zc,rd = pc
        x ,y ,z     = coords
        return np.sqrt((xc-x)**2+(yc-y)**2+(zc-z)**2)
   ....: 

In [98]: distance([0,0,0,0],np.array(coords).T)
Out[98]: array([ 0.        ,  1.        ,  1.        ,  0.98726896,  1.        ,  1.        ])

# and wrapping the array in a tuple, as `leastsq` does
In [102]: distance([0,0,0,0],*(np.array(coords).T,))
Out[102]: array([ 0.        ,  1.        ,  1.        ,  0.98726896,  1.        ,  1.        ])
我得到了一个5元素数组,在
coords
中,每个“点”对应一个值。这就是你想要的吗

您是从哪里想到的
leastsq
一次将
coords
一个元组馈送给
lambda

参数:元组 func的任何额外参数都放置在此元组中


通常,使用这些
optimize
函数,如果希望对一组条件执行操作,则需要迭代这些条件,对每个条件调用optimize。或者,如果您想一次对整个集合进行优化,那么您需要编写函数(err等)以一次处理整个集合

虽然我没有经常使用这个函数,但据我所知,
coords
会按原样传递给您的
distance
函数。如果允许错误检查,至少会这样。事实上,错误检查可能会尝试这样做,如果
distance
引发错误,则会引发错误。让我们试试看

In [91]: coords=[(0,0,0),(0,0,1),(-1,0,0),(0.57,0.57,0.57),(1,0,0),(0,1,0)]

In [92]: distance([0,0,0,0],coords)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-92-113da104affb> in <module>()
----> 1 distance([0,0,0,0],coords)

<ipython-input-89-64c557cd95e0> in distance(pc, coords)
      2 
      3         xc,yx,zx,rd = pc
----> 4         x ,y ,z     = coords
      5         return np.sqrt((xc-x)**2+(yc-y)**2+(zc-z)**2)
      6 

ValueError: too many values to unpack (expected 3)
同样的错误

distance([0,0,0,0],np.array(coords).T)
超过该问题(可拆分为3个变量的3行),将引发另一个错误:
NameError:未定义名称“yc”

这看起来像是你给我们的密码输入错误!淘气,淘气

更正如下:

In [97]: def distance(pc,coords):

        xc,yc,zc,rd = pc
        x ,y ,z     = coords
        return np.sqrt((xc-x)**2+(yc-y)**2+(zc-z)**2)
   ....: 

In [98]: distance([0,0,0,0],np.array(coords).T)
Out[98]: array([ 0.        ,  1.        ,  1.        ,  0.98726896,  1.        ,  1.        ])

# and wrapping the array in a tuple, as `leastsq` does
In [102]: distance([0,0,0,0],*(np.array(coords).T,))
Out[102]: array([ 0.        ,  1.        ,  1.        ,  0.98726896,  1.        ,  1.        ])
我得到了一个5元素数组,在
coords
中,每个“点”对应一个值。这就是你想要的吗

您是从哪里想到的
leastsq
一次将
coords
一个元组馈送给
lambda

参数:元组 func的任何额外参数都放置在此元组中


通常,使用这些
optimize
函数,如果希望对一组条件执行操作,则需要迭代这些条件,对每个条件调用optimize。或者,如果您想一次对整个集合进行优化,那么您需要编写函数(err等)以一次处理整个集合

您的
err
函数必须获取完整的坐标列表并返回完整的距离列表<然后,code>leastsq将获取错误列表,对它们进行平方和,并最小化平方和

中还有距离函数,因此我建议:

from scipy.spatial.distance import cdist
from scipy.optimize import leastsq

def distance_cdist(pc, coords):
    return cdist([pc], coords).squeeze()

def distance_norm(pc, points):
    """ pc must be shape (D+1,) array
        points can be (N, D) or (D,) array """
    c = np.asarray(pc[:3])
    points = np.atleast_2d(points)
    return np.linalg.norm(points-c, axis=1)

def sphere_params(coords):
    err = lambda pc, coords: distance(pc[:3], coords) - pc[3]
    pc = [0, 0, 0, 1]
    pc, success = leastsq(err, pc, args=(coords,))
    return pc

coords = [(0,0,0),(0,0,1),(-1,0,0),(0.57,0.57,0.57),(1,0,0),(0,1,0)]
sphere_params(coords)

您的
err
函数必须获取完整的坐标列表并返回完整的距离列表<然后,code>leastsq将获取错误列表,对它们进行平方和,并最小化平方和

中还有距离函数,因此我建议:

from scipy.spatial.distance import cdist
from scipy.optimize import leastsq

def distance_cdist(pc, coords):
    return cdist([pc], coords).squeeze()

def distance_norm(pc, points):
    """ pc must be shape (D+1,) array
        points can be (N, D) or (D,) array """
    c = np.asarray(pc[:3])
    points = np.atleast_2d(points)
    return np.linalg.norm(points-c, axis=1)

def sphere_params(coords):
    err = lambda pc, coords: distance(pc[:3], coords) - pc[3]
    pc = [0, 0, 0, 1]
    pc, success = leastsq(err, pc, args=(coords,))
    return pc

coords = [(0,0,0),(0,0,1),(-1,0,0),(0.57,0.57,0.57),(1,0,0),(0,1,0)]
sphere_params(coords)

下面是我从以前的帮助中得出的结论:

import numpy as np
from scipy.optimize import leastsq

def a_dist(a,B):
    # works with - a : reference point - B : coordinates matrix
    return np.linalg.norm(a-B, axis=1) 

def parametric(coords):

    err = lambda pc,point : a_dist(pc,point) - 18

    pc = [0, 0, 0] # Initial guess for the parameters
    pc, success = leastsq(err, pc[:], args=(coords,))

    return pc
它肯定同时适用于元组列表和形状数组(N,3)

将此版本与Askewchan的相结合,即:

def sphere_params(coords):
    err = lambda pc, coords: distance(pc[:3], coords) - pc[3]
    pc = [0, 0, 0, 1]
    pc, success = leastsq(err, pc, args=(coords,))
    return pc
也很好,老实说,我没有花时间尝试你的解决方案。但是,我确实不再将半径作为拟合参数。我发现它一点也不健壮(即使是6000个嘈杂的数据点也不足以获得正确的曲率!)


与我的第一个代码相比,我仍然不太确定哪里出了问题,虽然我真的不记得在我的任何函数中使用过任何“全局”语句,但我可能弄错了全局/局部变量。

因此,我从以前的帮助中得出以下结论:

import numpy as np
from scipy.optimize import leastsq

def a_dist(a,B):
    # works with - a : reference point - B : coordinates matrix
    return np.linalg.norm(a-B, axis=1) 

def parametric(coords):

    err = lambda pc,point : a_dist(pc,point) - 18

    pc = [0, 0, 0] # Initial guess for the parameters
    pc, success = leastsq(err, pc[:], args=(coords,))

    return pc
它肯定同时适用于元组列表和形状数组(N,3)

将此版本与Askewchan的相结合,即:

def sphere_params(coords):
    err = lambda pc, coords: distance(pc[:3], coords) - pc[3]
    pc = [0, 0, 0, 1]
    pc, success = leastsq(err, pc, args=(coords,))
    return pc
也很好,老实说,我没有花时间尝试你的解决方案。但是,我确实不再将半径作为拟合参数。我发现它一点也不健壮(即使是6000个嘈杂的数据点也不足以获得正确的曲率!)


与我的第一个代码相比,我仍然不太确定哪里出了问题,虽然我真的不记得在我的任何函数中使用过任何“全局”语句,但我可能弄错了全局/局部变量。

距离函数将坐标解包为
x,y,z=[(x0,y0,z0),(x1,y1,z1),(x2,y2,z2),(x3,y3,z3),等等]
,这将使列表的第一个元素变为
x
,第二个元素变为
y
,第三个元素变为
z
,但您的列表实际上比这长得多。也就是说,它将尝试将
x
设置为
(x0,y0,z0)
。你想要什么