web-dev-qa-db-fra.com

Ajustement de courbe 3D

J'ai une grille régulière discrète de a,b points et leurs valeurs c correspondantes et je les interpole davantage pour obtenir une courbe lisse. Maintenant, à partir des données d'interpolation, je souhaite en outre créer une équation polynomiale pour l'ajustement de courbe. Comment adapter un tracé 3D dans un polynôme?

J'essaie de le faire dans MATLAB. J'ai utilisé la boîte à outils d'ajustement de surface dans MATLAB (r2010a) pour ajuster les données tridimensionnelles. Mais, comment peut-on trouver une formule qui s'adapte au mieux à un ensemble de données dans MATLAB/MAPLE ou tout autre logiciel. Aucun conseil? Les exemples les plus utiles seraient également de vrais exemples de code à consulter, PDF, sur le Web, etc.

Ce n'est qu'une petite partie de mes données.

a = [ 0.001 .. 0.011];

b = [1, .. 10];

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

Merci d'avance.

15
Syeda

Pour ajuster une courbe sur un ensemble de points, nous pouvons utiliser la régression moindres carrés ordinaires . Il y a page de solution par MathWorks décrivant le processus.

À titre d'exemple, commençons par quelques données aléatoires:

% some 3d points
data = mvnrnd([0 0 0], [1 -0.5 0.8; -0.5 1.1 0; 0.8 0 1], 50);

Comme @ BasSwinckels l'a montré, en construisant la matrice de conception désirée, vous pouvez utiliser mldivide ou pinv à résoudre le système surdéterminé exprimé en 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));

Ensuite, nous visualisons le résultat:

% 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


Comme cela a été mentionné, nous pouvons obtenir un ajustement polynomial d'ordre supérieur en ajoutant plus de termes à la matrice de variables indépendantes (le A dans Ax=b).

Disons que nous voulons adapter un modèle quadratique avec des termes constants, linéaires, d'interaction et au carré (1, x, y, xy, x ^ 2, y ^ 2). Nous pouvons le faire manuellement:

% 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));

Il existe également une fonction d'aide x2fx dans la boîte à outils statistiques qui aide à construire la matrice de conception pour quelques commandes de modèle:

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

Enfin, il existe une excellente fonction polyfitn sur l'échange de fichiers par John D'Errico qui vous permet de spécifier toutes sortes d'ordres polynomiaux et de termes impliqués:

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

2nd_order_polynomial

17
Amro

Il peut y avoir de meilleures fonctions sur l'échange de fichiers, mais une façon de le faire à la main est la suivante:

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

De même, vous pouvez effectuer un ajustement de second ordre:

%second order fit
M = [ones(size(x)), x, y, x.^2, x.*y, y.^2];
k2 = M\z;

qui semble avoir des problèmes numériques pour le jeu de données limité que vous avez donné. Tapez help mldivide pour plus de détails.

Pour effectuer une interpolation sur une grille régulière, vous pouvez procéder comme suit:

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')

Un ajustement de troisième ordre peut être effectué en utilisant la formule donnée par TryHard ci-dessous, mais les formules deviennent rapidement fastidieuses lorsque l'ordre augmente. Mieux vaut écrire une fonction qui peut construire M étant donné x, y et order si vous devez le faire plus d'une fois.

3
Bas Swinckels

Cela ressemble plus à une question philosophique qu'à une implémentation spécifique, en particulier à un bit - "comment trouver une formule qui correspond à un ensemble de données au mieux?" D'après mon expérience, c'est un choix que vous devez faire en fonction de ce que vous essayez de réaliser.

Qu'est-ce qui définit le "mieux" pour vous? Pour un problème d'ajustement des données, vous pouvez continuer à ajouter de plus en plus de coefficients polynomiaux et à faire une meilleure valeur R ^ 2 ... mais finirez par "sur-ajuster" les données. Un inconvénient des polynômes d'ordre élevé est le comportement en dehors des limites des données d'échantillon que vous avez utilisées pour s'adapter à votre surface de réponse - il peut rapidement exploser dans une direction sauvage qui peut ne pas être appropriée pour tout ce que vous essayez de modéliser .

Avez-vous une idée du comportement physique du système/des données que vous ajustez? Cela peut être utilisé comme base pour quel ensemble d'équations utiliser pour créer un modèle mathématique. Ma recommandation serait d'utiliser le modèle le plus économique (simple) avec lequel vous pouvez vous en sortir.

2
Tom S