我使用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。)
我开始使用变量coords作为元组列表(每个元组是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是数据点数量。这使我看起来没有给出足够的数据点而我的列表coords实际上重新组合了351个元组而不是pc中的4个参数!
从我在minipack中读到的内容,实际的罪魁祸首似乎是这一行(来自_check_func()):
res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
除非我弄错了,否则我会将其转化为
res = atleast_1d(distance(*(pc[:len(pc)],) + args)
但是我正在努力理解这与_check_func()函数的其余部分有什么关系。
我最终将coords更改为数组,然后将其作为sphere_param()
:coords = np.asarray(coords).T
的参数,它开始正常工作。我真的很想理解数据格式为什么会给我带来麻烦!
事先,非常感谢您的回答!
编辑:我注意到我对“距离”和“错误”功能的使用是强烈的真的不明智和误导,在原始代码中并非如此,所以它不是问题。现在更有意义。
答案 0 :(得分:0)
虽然我还没有充分使用此功能,但我可以告诉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元素的数组,每个&#39;点&#39;在coords
。这就是你想要的吗?
您在哪里明白leastsq
一次将coords
一个元组提供给lambda
?
args:元组 func的任何额外参数都放在这个元组中。
通常使用这些optimize
函数,您希望在一组条件上执行操作,然后需要迭代这些条件,在每个条件上调用优化。或者如果你想一次优化整个集合,那么你需要编写你的函数(错误等)来同时处理整个集合。
答案 1 :(得分:0)
您的err
功能必须获取完整的坐标列表并返回完整的距离列表。然后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)
答案 2 :(得分:0)
所以这是我从以前的帮助中得出的结论:
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个数据点也不足以获得正确的曲率!)。
当与我的第一个代码比较时,我仍然不太确定出了什么问题,我可能搞砸了全局/局部变量,尽管我真的不记得在我的任何函数中使用任何“全局”语句。 / p>