Ich versuche, die 2 Hauptkomponenten aus einem Datensatz in C++ mit Eigen zu berechnen.Hauptkomponentenanalyse mit Eigenbibliothek
Die Art, wie ich es im Moment mache, besteht darin, die Daten zwischen [0, 1]
zu normalisieren und dann den Mittelwert zu zentrieren. Danach berechne ich die Kovarianzmatrix und führe eine Eigenwertzerlegung darauf aus. Ich weiß, SVD ist schneller, aber ich bin verwirrt über die berechneten Komponenten. Hier
ist der Haupt Code, wie ich es tun (wo traindata
ist meine MxN Größe Eingangsmatrix):
Eigen::VectorXf normalize(Eigen::VectorXf vec) {
for (int i = 0; i < vec.size(); i++) { // normalize each feature.
vec[i] = (vec[i] - minCoeffs[i])/scalingFactors[i];
}
return vec;
}
// Calculate normalization coefficients (globals of type Eigen::VectorXf).
maxCoeffs = traindata.colwise().maxCoeff();
minCoeffs = traindata.colwise().minCoeff();
scalingFactors = maxCoeffs - minCoeffs;
// For each datapoint.
for (int i = 0; i < traindata.rows(); i++) { // Normalize each datapoint.
traindata.row(i) = normalize(traindata.row(i));
}
// Mean centering data.
Eigen::VectorXf featureMeans = traindata.colwise().mean();
Eigen::MatrixXf centered = traindata.rowwise() - featureMeans;
// Compute the covariance matrix.
Eigen::MatrixXf cov = centered.adjoint() * centered;
cov = cov/(traindata.rows() - 1);
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig(cov);
// Normalize eigenvalues to make them represent percentages.
Eigen::VectorXf normalizedEigenValues = eig.eigenvalues()/eig.eigenvalues().sum();
// Get the two major eigenvectors and omit the others.
Eigen::MatrixXf evecs = eig.eigenvectors();
Eigen::MatrixXf pcaTransform = evecs.rightCols(2);
// Map the dataset in the new two dimensional space.
traindata = traindata * pcaTransform;
Das Ergebnis dieses Code ist so etwas wie diese:
Um meine Ergebnisse zu bestätigen, habe ich das gleiche mit WEKA versucht. Also habe ich den Normalize- und den Center-Filter in dieser Reihenfolge benutzt. Dann filtert und speichert die Hauptkomponente die Ausgabe. Das Ergebnis ist dieses:
Technisch sollte ich das gleiche getan haben, aber das Ergebnis ist so anders. Kann jemand sehen, ob ich einen Fehler gemacht habe?
Eine Sache hinzuzufügen: Ich bin ziemlich sicher, dass WEKA SVD verwendet. Aber das sollte nicht den Unterschied im Ergebnis erklären oder? – Chris