约束线性最小二乘法不适合数据

Constrained linear least squares not fitting data

我正在尝试将 n 度的 3D 曲面多项式拟合到 3D 中的某些数据点 space。我的系统要求表面在感兴趣的区域单调增加,即偏导数必须是非负的。这可以使用 Matlab 的内置 lsqlin 函数来实现。

所以这是我为实现这一目标所做的工作:

我有一个接受四个参数的函数; x1 和 x2 是我的解释变量,y 是我的因变量。最后,我可以指定多项式拟合的阶数。首先,我使用来自 x1 和 x2 的数据以及我想要的拟合度构建设计矩阵 A。接下来我构建矩阵 D,它是我的数据点偏导数的容器。注意:矩阵 D 是矩阵 A 长度的两倍,因为所有数据点都必须根据 x1 和 x2 进行区分。我通过将 b 设置为零来指定 Dx >= 0。

最后,我调用了 lsqlin。我使用“-D”,因为 Matlab 将函数定义为 Dx <= b。

function w_mono = monotone_surface_fit(x1, x2, y, order_fit)

% Initialize design matrix
A = zeros(length(x1), 2*order_fit+2);

% Adjusting for bias term
A(:,1) = ones(length(x1),1); 


% Building design matrix
for i = 2:order_fit+1
    A(:,(i-1)*2:(i-1)*2+1) = [x1.^(i-1), x2.^(i-1)];
end

% Initialize matrix containing derivative constraint.
% NOTE: Partial derivatives must be non-negative
D = zeros(2*length(y), 2*order_fit+1);


% Filling matrix that holds constraints for partial derivatives
% NOTE: Matrix D will be double length of A since all data points will have a partial derivative constraint in both x1 and x2 directions. 
for i = 2:order_fit+1
     D(:,(i-1)*2:(i-1)*2+1) = [(i-1)*x1.^(i-2), zeros(length(x2),1); ...
                                 zeros(length(x1),1), (i-1)*x2.^(i-2)];
end

% Limit of derivatives
b = zeros(2*length(y), 1);

% Constrained LSQ fit
options = optimoptions('lsqlin','Algorithm','interior-point');

% Final weights of polynomial
w_mono = lsqlin(A,y,-D,b,[],[],[],[],[], options);

end

所以现在我得到了一些权重,但不幸的是它们根本没有捕获数据的结构。我附上了一张图片,这样你就可以知道它看起来有多糟糕。

我会给你我的绘图脚本和一些虚拟数据,所以你可以试试。

%% Plot different order polynomials to data with constraints

x1 = [-5;12;4;9;18;-1;-8;13;0;7;-5;-8;-6;14;-1;1;9;14;12;1;-5;9;-10;-2;9;7;-1;19;-7;12;-6;3;14;0;-8;6;-2;-7;10;4;-5;-7;-4;-6;-1;18;5;-3;3;10];
x2 = [81.25;61;73;61.75;54.5;72.25;80;56.75;78;64.25;85.25;86;80.5;61.5;79.25;76.75;60.75;54.5;62;75.75;80.25;67.75;86.5;81.5;62.75;66.25;78.25;49.25;82.75;56;84.5;71.25;58.5;77;82;70.5;81.5;80.75;64.5;68;78.25;79.75;81;82.5;79.25;49.5;64.75;77.75;70.25;64.5];
y = [-6.52857142857143;-1.04736842105263;-5.18750000000000;-3.33157894736842;-0.117894736842105;-3.58571428571429;-5.61428571428572;0;-4.47142857142857;-1.75438596491228;-7.30555555555556;-8.82222222222222;-5.50000000000000;-2.95438596491228;-5.78571428571429;-5.15714285714286;-1.22631578947368;-0.340350877192983;-0.142105263157895;-2.98571428571429;-4.35714285714286;-0.963157894736842;-9.06666666666667;-4.27142857142857;-3.43684210526316;-3.97894736842105;-6.61428571428572;0;-4.98571428571429;-0.573684210526316;-8.22500000000000;-3.01428571428571;-0.691228070175439;-6.30000000000000;-6.95714285714286;-2.57232142857143;-5.27142857142857;-7.64285714285714;-2.54035087719298;-3.45438596491228;-5.01428571428571;-7.47142857142857;-5.38571428571429;-4.84285714285714;-6.78571428571429;0;-0.973684210526316;-4.72857142857143;-2.84285714285714;-2.54035087719298];

% Used to plot the surface in all points in the grid
X1 = meshgrid(-10:1:20);
X2 = flipud(meshgrid(30:2:90).');

figure;
for i = 1:4

    w_mono = monotone_surface_fit(x1, x2, y, i);

    y_nr = w_mono(1)*ones(size(X1)) + w_mono(2)*ones(size(X2));

    for j = 1:i
        y_nr = w_mono(j*2)*X1.^j + w_mono(j*2+1)*X2.^j;
    end

    subplot(2,2,i);
    scatter3(x1, x2, y); hold on;

    axis tight;

    mesh(X1, X2, y_nr);
    set(gca, 'ZDir','reverse');

    xlabel('x1'); ylabel('x2');
    zlabel('y');
%     zlim([-10 0])
end

我想这可能与我没有指定感兴趣区域有关,但我真的不知道。在此先感谢您的帮助。

好的,我明白了。

主要问题只是绘图脚本中的一个错误。 y_nr 的值应该在循环中更新而不是被覆盖。

我还发现二阶导数应该是单调递减的。如果有人感兴趣,这是更新后的代码。

%% Plot different order polynomials to data with constraints

x1 = [-5;12;4;9;18;-1;-8;13;0;7;-5;-8;-6;14;-1;1;9;14;12;1;-5;9;-10;-2;9;7;-1;19;-7;12;-6;3;14;0;-8;6;-2;-7;10;4;-5;-7;-4;-6;-1;18;5;-3;3;10];
x2 = [81.25;61;73;61.75;54.5;72.25;80;56.75;78;64.25;85.25;86;80.5;61.5;79.25;76.75;60.75;54.5;62;75.75;80.25;67.75;86.5;81.5;62.75;66.25;78.25;49.25;82.75;56;84.5;71.25;58.5;77;82;70.5;81.5;80.75;64.5;68;78.25;79.75;81;82.5;79.25;49.5;64.75;77.75;70.25;64.5];
y = [-6.52857142857143;-1.04736842105263;-5.18750000000000;-3.33157894736842;-0.117894736842105;-3.58571428571429;-5.61428571428572;0;-4.47142857142857;-1.75438596491228;-7.30555555555556;-8.82222222222222;-5.50000000000000;-2.95438596491228;-5.78571428571429;-5.15714285714286;-1.22631578947368;-0.340350877192983;-0.142105263157895;-2.98571428571429;-4.35714285714286;-0.963157894736842;-9.06666666666667;-4.27142857142857;-3.43684210526316;-3.97894736842105;-6.61428571428572;0;-4.98571428571429;-0.573684210526316;-8.22500000000000;-3.01428571428571;-0.691228070175439;-6.30000000000000;-6.95714285714286;-2.57232142857143;-5.27142857142857;-7.64285714285714;-2.54035087719298;-3.45438596491228;-5.01428571428571;-7.47142857142857;-5.38571428571429;-4.84285714285714;-6.78571428571429;0;-0.973684210526316;-4.72857142857143;-2.84285714285714;-2.54035087719298];

% Used to plot the surface in all points in the grid
X1 = meshgrid(-10:1:20);
X2 = flipud(meshgrid(30:2:90).');

figure;
for i = 1:4

    w_mono = monotone_surface_fit(x1, x2, y, i);

    % NOTE: Should only have 1 bias term
    y_nr = w_mono(1)*ones(size(X1));

    for j = 1:i
        y_nr = y_nr + w_mono(j*2)*X1.^j + w_mono(j*2+1)*X2.^j;
    end

    subplot(2,2,i);
    scatter3(x1, x2, y); hold on;

    axis tight;

    mesh(X1, X2, y_nr);
    set(gca, 'ZDir','reverse');

    xlabel('x1'); ylabel('x2');
    zlabel('y');
%     zlim([-10 0])
end

这是更新后的函数

function [w_mono, w] = monotone_surface_fit(x1, x2, y, order_fit)

% Initialize design matrix
A = zeros(length(x1), 2*order_fit+1);

% Adjusting for bias term
A(:,1) = ones(length(x1),1); 

% Building design matrix
for i = 2:order_fit+1
    A(:,(i-1)*2:(i-1)*2+1) = [x1.^(i-1), x2.^(i-1)];
end

% Initialize matrix containing derivative constraint.
% NOTE: Partial derivatives must be non-negative
D = zeros(2*length(y), 2*order_fit+1);

for i = 2:order_fit+1
    D(:,(i-1)*2:(i-1)*2+1) = [(i-1)*x1.^(i-2), zeros(length(x2),1); ...
        zeros(length(x1),1), -(i-1)*x2.^(i-2)];
end

% Limit of derivatives
b = zeros(2*length(y), 1);

% Constrained LSQ fit
options = optimoptions('lsqlin','Algorithm','active-set');
w_mono = lsqlin(A,y,-D,b,[],[],[],[],[], options);
w = lsqlin(A,y);

end

最后是拟合图(使用了新的模拟,但拟合也适用于给定的虚拟数据)。