使用 lmfit minimize 在 3D 点的数据集上拟合 3D 线
Using lmfit minimize to fit a 3D line on a dataset of 3D points
我正在使用 lmfit minimize 在 3D 点数据集上拟合 3D 线。
from lmfit import minimize, Parameters, report_fit,fit_report, printfuncs
import numpy as np
#Parameters of parametric equations:
#x = p[0] + p[1]*t;
#y = p[2] + p[3]*t;
#z = t;
params = Parameters()
params.add('x0', value= 1)
params.add('x1', value= 1)
params.add('y0', value= 1)
params.add('y1', value= 1)
#Function to be minimized - sum of distances between the line and each point
def fun(params,x,y,z):
x0 = params['x0'].value; x1 = params['x1'].value
y0 = params['y0'].value; y1 = params['y1'].value
d = 0
v0 = np.array([x0, y0, 0.0])
v1 = np.array([x0+x1, y0+y1, 1.])
for point in range(len(x)):
p = np.array([x[point], y[point], z[point]])
d += np.linalg.norm(np.cross(v1-v0,v0-p))/np.linalg.norm(v1-v0)
return d
result = minimize(fun, params,args=(x,y,z)))
result.params.pretty_print()
print(fit_report(result))
错误是TypeError: Improper input: N=4 must not exceed M=1.
我理解这是因为只有 1 个残差(距离)和 4 个参数,但这正是我所需要的。我想优化4个参数以获得最小的距离总和。
似乎是方法问题。
The objective function should return the value to be minimized. For the >Levenberg-Marquardt algorithm from leastsq() or least_squares(), this >returned value must be an array, with a length greater than or equal to >the number of fitting variables in the model.
使用 Nelder,我得到了结果。
虽然不是正确的。所以仍然不确定代码。
问题是在您的情况下 fun
returns 是一个标量。这对于某些方法来说很好,但是正如您正确指出的那样 least_squares
需要一个数组。我认为重写你的 objective 函数,使其 returns 一个数组应该可以解决这个问题 - 查看描述和示例 here.
要使用 Levenberg-Marquardt 最小化(lmfit.minimize()
的默认方法),您应该 return 距离的 ndarray。也就是说,不要自己进行最小二乘求和。通过 return 完整数组(一组特定参数值的所有距离观察值),您可以让拟合算法更好地探索参数对拟合质量的影响。
我正在使用 lmfit minimize 在 3D 点数据集上拟合 3D 线。
from lmfit import minimize, Parameters, report_fit,fit_report, printfuncs
import numpy as np
#Parameters of parametric equations:
#x = p[0] + p[1]*t;
#y = p[2] + p[3]*t;
#z = t;
params = Parameters()
params.add('x0', value= 1)
params.add('x1', value= 1)
params.add('y0', value= 1)
params.add('y1', value= 1)
#Function to be minimized - sum of distances between the line and each point
def fun(params,x,y,z):
x0 = params['x0'].value; x1 = params['x1'].value
y0 = params['y0'].value; y1 = params['y1'].value
d = 0
v0 = np.array([x0, y0, 0.0])
v1 = np.array([x0+x1, y0+y1, 1.])
for point in range(len(x)):
p = np.array([x[point], y[point], z[point]])
d += np.linalg.norm(np.cross(v1-v0,v0-p))/np.linalg.norm(v1-v0)
return d
result = minimize(fun, params,args=(x,y,z)))
result.params.pretty_print()
print(fit_report(result))
错误是TypeError: Improper input: N=4 must not exceed M=1.
我理解这是因为只有 1 个残差(距离)和 4 个参数,但这正是我所需要的。我想优化4个参数以获得最小的距离总和。
似乎是方法问题。
The objective function should return the value to be minimized. For the >Levenberg-Marquardt algorithm from leastsq() or least_squares(), this >returned value must be an array, with a length greater than or equal to >the number of fitting variables in the model.
使用 Nelder,我得到了结果。 虽然不是正确的。所以仍然不确定代码。
问题是在您的情况下 fun
returns 是一个标量。这对于某些方法来说很好,但是正如您正确指出的那样 least_squares
需要一个数组。我认为重写你的 objective 函数,使其 returns 一个数组应该可以解决这个问题 - 查看描述和示例 here.
要使用 Levenberg-Marquardt 最小化(lmfit.minimize()
的默认方法),您应该 return 距离的 ndarray。也就是说,不要自己进行最小二乘求和。通过 return 完整数组(一组特定参数值的所有距离观察值),您可以让拟合算法更好地探索参数对拟合质量的影响。