Ich habe 65 Stichproben von 21-dimensionalen Daten ( hier eingefügt ) und konstruiere daraus die Kovarianzmatrix. Bei der Berechnung in C ++ wird hier die Kovarianzmatrix eingefügt . Und wenn ich in Matlab aus den Daten berechnet werde (wie unten gezeigt), wird die Kovarianzmatrix hier eingefügt
Matlab-Code zur Berechnung von cov aus Daten:
data = csvread('path/to/data');
matlab_cov = cov(data);
Wie Sie sehen können, sind die Unterschiede in den Kovarianzmatrizen winzig (~ e-07), was wahrscheinlich auf numerische Probleme im Compiler mit Gleitkomma-Arithmetik zurückzuführen ist.
Wenn ich jedoch die pseudo-inverse Kovarianzmatrix aus der von matlab und der von meinem C ++ - Code erzeugten Kovarianzmatrix berechne, erhalte ich sehr unterschiedliche Ergebnisse. Ich berechne sie auf die gleiche Weise, dh:
data = csvread('path/to/data');
matlab_cov = cov(data);
my_cov = csvread('path/to/cov_file');
matlab_inv = pinv(matlab_cov);
my_inv = pinv(my_cov);
Der Unterschied ist so groß, dass bei der Berechnung des Mahalanobis-Abstands von einer Probe ( hier eingefügt ) zur Verteilung der 65 Proben durch:
Mit den verschiedenen inversen Kovarianzmatrizen ( ) erhalte ich sehr unterschiedliche Ergebnisse, dh:
(65/(64^2))*((sample-sample_mean)*my_inv*(sample-sample_mean)')
ans =
1.0167e+05
(65/(64^2))*((sample-sample_mean)*matlab_inv*(sample-sample_mean)')
ans =
109.9612
Ist es normal, dass die kleinen (e-7) Unterschiede in der Kovarianzmatrix einen solchen Effekt auf die Berechnung der pseudoinversen Matrix haben? Und wenn ja, was kann ich tun, um diesen Effekt abzuschwächen?
Wenn dies nicht gelingt, kann ich andere Entfernungsmetriken verwenden, die nicht die inverse Kovarianz beinhalten? Ich verwende den Mahalanobis-Abstand, da wir wissen, dass er für n Proben einer Beta-Verteilung folgt, die ich für Hypothesentests verwende
Vielen Dank im Voraus
BEARBEITEN: Hinzufügen von C ++ - Code zur Berechnung der Kovarianzmatrix unten:
Die vector<vector<double> >
repräsentiert die Sammlung von Zeilen aus der eingefügten Datei.
Mat covariance_matrix = Mat(21, 21, CV_32FC1, cv::Scalar(0));
for(int j = 0; j < 21; j++){
for(int k = 0; k < 21; k++){
for(std::vector<vector<double> >::iterator it = data.begin(); it!= data.end(); it++){
covariance_matrix.at<float>(j,k) += (it->at(j) - mean.at(j)) * (it->at(k) - mean[k]);
}
covariance_matrix.at<float>(j,k) /= 64;
}
}
Antworten:
Die Matrizen, die Sie invertieren möchten, sind keine "gültigen" Kovarianzmatrizen, da sie nicht eindeutig positiv sind. numerisch haben sie sogar einige Eigenwerte, die negativ sind (aber nahe bei Null liegen). Dies ist höchstwahrscheinlich auf Maschinennullen zurückzuführen, beispielsweise ist der letzte Eigenwert Ihrer Matrix "matlab_covariance" -0.000000016313723. Um positiv positiv zu korrigieren, können Sie zwei Dinge tun:
Eine nicht negative Matrix hat keine Inverse, aber eine Pseudo-Inverse (alle Matrizen mit reellen oder komplexen Einträgen haben eine Pseudo-Inverse), dennoch ist die Moore-Penrose-Pseudo-Inverse rechenintensiver als eine echte Inverse und wenn Das Inverse existiert, es ist gleich dem Pseudo-Inversen. Also mach einfach das Gegenteil :)
Beide Methoden versuchen praktisch, mit den Eigenwerten umzugehen, die sich zu Null (oder unter Null) ergeben. Die erste Methode ist etwas handgewellt, aber wahrscheinlich viel schneller zu implementieren. Für etwas etwas stabileres möchten Sie vielleicht die SVD berechnen und dann das gleich dem Absoluten des kleinsten Eigenwerts (damit Sie nicht negativ werden) plus etwas sehr Kleines (damit Sie positiv werden) setzen. Achten Sie nur darauf, dass eine Matrix, die offensichtlich negativ (oder bereits positiv) ist, nicht positiv beeinflusst wird. Beide Methoden ändern die Konditionierungsnummer Ihrer Matrix.λ
In statistischer Hinsicht fügen Sie Ihren Messungen Rauschen hinzu, indem Sie dieses über die Diagonale Ihrer Kovarianzmatrix addieren. (Da die Diagonale der Kovarianzmatrix die Varianz jedes Punktes ist und Sie diesen Werten etwas hinzufügen, sagen Sie einfach "die Varianz an den Punkten, für die ich Messwerte habe, ist tatsächlich etwas größer als ursprünglich angenommen".)λ
Ein schneller Test für die positive Bestimmtheit einer Matrix ist das Vorhandensein (oder Nichtvorhandensein) der Cholesky-Zersetzung derselben.
Auch als rechnerische Anmerkung:
EDIT: Wenn Sie eine Cholesky-Zerlegung Ihrer Matrix so dass (Sie müssen dies tun, um zu überprüfen, ob Sie eine Pos.Def. Matrix haben), sollten Sie in der Lage sein, das System sofort zu lösen . Sie lösen einfach Ly = b für y durch Vorwärtssubstitution und dann L ^ Tx = y für x durch Rückwärtssubstitution. (Verwenden Sie im Eigen einfach die .solve (x) -Methode Ihres Cholesky-Objekts.) Vielen Dank an bnaul und Zen für den Hinweis, dass ich mich so sehr darauf konzentriert habe, das be Pos.Def zu erhalten. dass ich vergessen habe, warum uns das überhaupt interessiert hat :)K LLT Kx=b K
quelle
Die veröffentlichten Antworten und Kommentare machen alle gute Hinweise auf die Gefahren der Invertierung nahezu singulärer Matrizen. Soweit ich das beurteilen kann, hat jedoch niemand erwähnt, dass für die Berechnung der Mahalanobis-Entfernung keine Umkehrung der Stichproben-Kovarianz erforderlich ist. In dieser StackOverflow-Frage finden Sie eine Beschreibung der Verwendung der Zerlegung.LU
Das Prinzip ist dasselbe wie das Lösen eines linearen Systems: Wenn versucht wird, nach zu lösen, so dass , gibt es viel effizientere und numerisch stabilere Methoden als .A x = b x = A - 1 bx Ax=b x=A−1b
Bearbeiten: Es ist wahrscheinlich selbstverständlich, aber diese Methode liefert den genauen Abstandswert, während das Addieren von zu und das Invertieren nur eine Annäherung ergibt.S.λI S
quelle
LU
funktioniert die Zerlegung jedoch auch nicht. Ich werde in meiner Antwort einen Kommentar dazu hinzufügen.(Jahre später) ein winziges Beispiel: Mit Rangmangel werden Eigenwerte von innerhalb der Maschinengenauigkeit 0 sein - und ungefähr die Hälfte dieser "Nullen" kann :r < n , n - r A T A < 0A r<n, n−r ATA <0
quelle