3D曲线拟合

18

我有一个离散的规则网格,其中包含a,b个点和它们对应的c值,并通过插值创建了一个平滑曲线。现在,我想从插值数据中进一步创建用于曲线拟合的多项式方程。如何在三维图中进行多项式拟合?

我尝试使用MATLAB进行这个操作。我使用了MATLAB(r2010a)中的曲面拟合工具箱来拟合三维数据。但是,在MATLAB / MAPLE或任何其他软件中如何找到最佳的拟合一组数据的公式呢?有什么建议吗?此外,最有用的是寻找一些真实的代码示例、PDF文件等等。

这只是我的数据的一小部分。

a = [ 0.001 .. 0.011];

b = [1, .. 10];

c = [ -.304860225, .. .379710865]; 

提前致谢。

3个回答

21
为了将曲线拟合到一组点上,我们可以使用普通最小二乘回归ordinary least-squares。MathWorks有一篇solution page描述了这个过程。
例如,让我们从一些随机数据开始:
% some 3d points
data = mvnrnd([0 0 0], [1 -0.5 0.8; -0.5 1.1 0; 0.8 0 1], 50);

正如 @BasSwinckels 所示,通过构建所需的design matrix,您可以使用mldividepinv解决表示为Ax=b的超定系统

% best-fit plane
C = [data(:,1) data(:,2) ones(size(data,1),1)] \ data(:,3);    % coefficients

% evaluate it on a regular grid covering the domain of the data
[xx,yy] = meshgrid(-3:.5:3, -3:.5:3);
zz = C(1)*xx + C(2)*yy + C(3);

% or expressed using matrix/vector product
%zz = reshape([xx(:) yy(:) ones(numel(xx),1)] * C, size(xx));

接下来我们将结果可视化:

% plot points and surface
figure('Renderer','opengl')
line(data(:,1), data(:,2), data(:,3), 'LineStyle','none', ...
    'Marker','.', 'MarkerSize',25, 'Color','r')
surface(xx, yy, zz, ...
    'FaceColor','interp', 'EdgeColor','b', 'FaceAlpha',0.2)
grid on; axis tight equal;
view(9,9);
xlabel x; ylabel y; zlabel z;
colormap(cool(64))

1st_order_polynomial


正如所提到的,我们可以通过向自变量矩阵(在Ax=b中的A)添加更多项来获得高阶多项式拟合。
假设我们想要拟合一个包含常数、线性、交互和平方项(1、x、y、xy、x^2、y^2)的二次模型。我们可以手动完成这个过程:
% best-fit quadratic curve
C = [ones(50,1) data(:,1:2) prod(data(:,1:2),2) data(:,1:2).^2] \ data(:,3);
zz = [ones(numel(xx),1) xx(:) yy(:) xx(:).*yy(:) xx(:).^2 yy(:).^2] * C;
zz = reshape(zz, size(xx));

统计工具箱中还有一个辅助函数x2fx,可帮助构建几种模型阶数的设计矩阵:

C = x2fx(data(:,1:2), 'quadratic') \ data(:,3);
zz = x2fx([xx(:) yy(:)], 'quadratic') * C;
zz = reshape(zz, size(xx));

最后,在John D'Errico的文件交换中有一个优秀的函数polyfitn,它允许您指定各种多项式阶数和涉及的项:

model = polyfitn(data(:,1:2), data(:,3), 2);
zz = polyvaln(model, [xx(:) yy(:)]);
zz = reshape(zz, size(xx));

2nd_order_polynomial


1
我该如何在Python中执行相同类型的操作呢?!需要一点帮助,谢谢@Amro。 - diffracteD
5
@diffracteD:我已将代码翻译成Python语言:https://gist.github.com/amroamroamro/1db8d69b4b65e8bc66a6 - Amro
(询问您的Github代码)是否逻辑上可以采用更高阶多项式拟合来评估表面? - diffracteD
@diffracteD:是的,你可以这样做,但是你应该小心拟合过高阶数的模型。 - Amro
可以给我建议一个使用Python代码从拟合曲面中获取最小/最大值的方法吗?谢谢。 - diffracteD
显示剩余2条评论

3

可能在文件交换中有更好的功能,但手动完成的一种方法如下:

x = a(:); %make column vectors
y = b(:);
z = c(:);

%first order fit
M = [ones(size(x)), x, y];
k1 = M\z; 
%least square solution of z = M * k1, so z = k1(1) + k1(2) * x + k1(3) * y

同样地,您可以进行二阶拟合:
%second order fit
M = [ones(size(x)), x, y, x.^2, x.*y, y.^2];
k2 = M\z;

您提供的有限数据集似乎存在数值问题。请键入 help mldivide 了解更多详情。

如果要在某个规则网格上进行插值,可以按照以下方式操作:

ngrid = 20;
[A,B] = meshgrid(linspace(min(a), max(a), ngrid), ...
                 linspace(min(b), max(b), ngrid));
M = [ones(numel(A),1), A(:), B(:), A(:).^2, A(:).*B(:), B(:).^2];
C2_fit = reshape(M * k2, size(A)); % = k2(1) + k2(2)*A + k2(3)*B + k2(4)*A.^2 + ...

%plot to compare fit with original data
surfl(A,B,C2_fit);shading flat;colormap gray
hold on
plot3(a,b,c, '.r')

可以使用TryHard下面给出的公式进行3阶拟合,但是当阶数增加时,公式很快变得繁琐。最好编写一个函数,可以根据需要多次构造M,给定x、y和order即可。

1
使用 M = [ones(size(x)), x, y, x.^2, x.*y, y.^2, x.^3, x.^2.*y, x.*y.^2, y.^3] 进行三阶拟合可以取得不错的效果,加一。 - Buck Thorn
抱歉回复晚了!感谢Bas Swinckels和Try hard的回复。很好的解决方案。但是,有没有一种方法可以通过编程或使用MATLAB中的任何工具找到最佳拟合的公式/方程?如何找到最适合上述给定数据集的公式? - Syeda
我也收到了这个警告。警告:秩不足,秩=5,tol=9.9961e-013。你能帮我理解一下这是什么意思吗?谢谢。 - Syeda
在搜索polyfit、2D、3D、fit、matlab等任何组合时,会出现很多答案,这是我遇到不知道的问题时经常做的事情。你肯定会在file-exchange上找到一些解决方案。但你必须自己去做,我们不是来帮你完成所有的(家庭)作业的... - Bas Swinckels
你说你只提供了一小部分的数据,请尝试适应整个数据集,看看是否会有所改变。你提供的数据中 a 只有两个不同的值(0.001 和 0.0011),因此尝试使用二次多项式进行拟合是无法定义的... - Bas Swinckels

2
这似乎更像是一种哲学问题而不是具体的实现,特别是对于位数 - “如何找到最适合一组数据的公式?” 在我的经验中,这是一个取决于您想要实现什么目标的选择
那么对于您来说,“最好”的定义是什么?对于数据拟合问题,您可以不断添加更多的多项式系数并获得更好的R^2值......但最终会“过度拟合”数据。高阶多项式的缺点是在超出您用来拟合响应曲面的样本数据边界外的行为 - 它可能会迅速朝某些不适合您尝试建模的方向偏离。
您是否了解您正在拟合的系统/数据的物理行为?这可以用作创建数学模型所使用的一组方程的基础。我建议您使用尽可能经济(简单)的模型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接