为什么元组列表作为 optimize.leasztsq 的参数失败?
why is list of tuple failing as an argument for optimize.leasztsq?
我使用 scipy.optimize 中的函数 leastsq 来拟合 3D 坐标中的球体坐标和半径。
所以我的代码如下所示:
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
(感谢:how do I fit 3D data。)
我开始使用变量坐标作为元组列表(每个元组是一个 x、y、z 坐标):
>> coords
>> [(0,0,0),(0,0,1),(-1,0,0),(0.57,0.57,0.57),...,(1,0,0),(0,1,0)]
这导致我出错:
>> 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
其中N为pc中存储的参数个数,M为数据点个数。这让我看起来好像没有提供足够的数据点,而我的列表坐标实际上将 351 个元组与 pc 中的 4 个参数重新分组!
从我在 minipack 中读到的内容来看,真正的罪魁祸首似乎是这一行(来自 _check_func()):
res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
除非我记错了,在我的例子中它翻译成
res = atleast_1d(distance(*(pc[:len(pc)],) + args)
但我很难理解这与 _check_func() 函数的其余部分的含义。
我最终将坐标更改为数组,然后将其作为 sphere_param()
的参数:coords = np.asarray(coords).T
,它开始工作得很好。我真的很想了解为什么数据格式给我带来麻烦!
提前,非常感谢您的回答!
编辑:我注意到我在 "distance" 和 "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)
这就是 3 的来源 - 你的 x, y, z = coords
。
distance([0,0,0,0],np.array(coords))
同样的错误。
distance([0,0,0,0],np.array(coords).T)
解决了那个问题(3 行可以拆分为 3 个变量),引发了另一个错误:NameError: name 'yc' is not defined
这看起来像是您给我们的代码中的错字,!顽皮,顽皮!。
更正:
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
中每个 'point' 一个值。那是你想要的吗?
您从哪里想到 leastsq
一次将您的 coords
一个元组提供给您的 lambda
?
args : tuple
Any extra arguments to func are placed in this tuple.
一般来说,使用这些 optimize
函数,如果您想对一组条件执行操作,则需要迭代这些条件,对每个条件调用优化。或者如果你想一次优化整个集合,那么你需要编写你的函数(错误等)来一次处理整个集合。
您的 err
函数必须采用完整的坐标列表和 return 完整的距离列表。 leastsq
然后将获取错误列表,对它们进行平方和求和,并将平方和最小化。
scipy.spatial.distance
里面也有距离函数,所以我推荐:
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)
>> cluster #it's more than 6000 point you won't have the same result
>> [(4, 30, 19), (3, 30, 19), (5, 30, 19), ..., (4, 30, 3), (4, 30, 35)]
>> sphere_params(cluster)
>> array([ -5.25734467, 20.73419249, 9.73428766])
>> np.asarray(cluster).shape
>> (6017,3)
>> sphere_params(np.asarray(cluster))
>> array([ -5.25734467, 20.73419249, 9.73428766])
将此版本与 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 个嘈杂的数据点也不足以获得正确的曲率!)。
与我的第一个代码进行比较时,我仍然不太确定哪里出了问题,我可能搞砸了 global/local 变量,尽管我真的不记得在其中使用过任何 "global" 语句我的任何功能。
我使用 scipy.optimize 中的函数 leastsq 来拟合 3D 坐标中的球体坐标和半径。
所以我的代码如下所示:
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
(感谢:how do I fit 3D data。)
我开始使用变量坐标作为元组列表(每个元组是一个 x、y、z 坐标):
>> coords
>> [(0,0,0),(0,0,1),(-1,0,0),(0.57,0.57,0.57),...,(1,0,0),(0,1,0)]
这导致我出错:
>> 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
其中N为pc中存储的参数个数,M为数据点个数。这让我看起来好像没有提供足够的数据点,而我的列表坐标实际上将 351 个元组与 pc 中的 4 个参数重新分组!
从我在 minipack 中读到的内容来看,真正的罪魁祸首似乎是这一行(来自 _check_func()):
res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
除非我记错了,在我的例子中它翻译成
res = atleast_1d(distance(*(pc[:len(pc)],) + args)
但我很难理解这与 _check_func() 函数的其余部分的含义。
我最终将坐标更改为数组,然后将其作为 sphere_param()
的参数:coords = np.asarray(coords).T
,它开始工作得很好。我真的很想了解为什么数据格式给我带来麻烦!
提前,非常感谢您的回答!
编辑:我注意到我在 "distance" 和 "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)
这就是 3 的来源 - 你的 x, y, z = coords
。
distance([0,0,0,0],np.array(coords))
同样的错误。
distance([0,0,0,0],np.array(coords).T)
解决了那个问题(3 行可以拆分为 3 个变量),引发了另一个错误:NameError: name 'yc' is not defined
这看起来像是您给我们的代码中的错字,!顽皮,顽皮!。
更正:
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
中每个 'point' 一个值。那是你想要的吗?
您从哪里想到 leastsq
一次将您的 coords
一个元组提供给您的 lambda
?
args : tuple Any extra arguments to func are placed in this tuple.
一般来说,使用这些 optimize
函数,如果您想对一组条件执行操作,则需要迭代这些条件,对每个条件调用优化。或者如果你想一次优化整个集合,那么你需要编写你的函数(错误等)来一次处理整个集合。
您的 err
函数必须采用完整的坐标列表和 return 完整的距离列表。 leastsq
然后将获取错误列表,对它们进行平方和求和,并将平方和最小化。
scipy.spatial.distance
里面也有距离函数,所以我推荐:
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)
>> cluster #it's more than 6000 point you won't have the same result
>> [(4, 30, 19), (3, 30, 19), (5, 30, 19), ..., (4, 30, 3), (4, 30, 35)]
>> sphere_params(cluster)
>> array([ -5.25734467, 20.73419249, 9.73428766])
>> np.asarray(cluster).shape
>> (6017,3)
>> sphere_params(np.asarray(cluster))
>> array([ -5.25734467, 20.73419249, 9.73428766])
将此版本与 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 个嘈杂的数据点也不足以获得正确的曲率!)。
与我的第一个代码进行比较时,我仍然不太确定哪里出了问题,我可能搞砸了 global/local 变量,尽管我真的不记得在其中使用过任何 "global" 语句我的任何功能。