Sto provando a calcolare i 2 principali componenti principali da un set di dati in C++ con Eigen.Analisi componenti principale con Eigen Library
Il modo in cui lo faccio al momento è di normalizzare i dati tra [0, 1]
e quindi centrare la media. Dopo di che computo la matrice di covarianza ed eseguo una decomposizione autovalore su di essa. So che SVD è più veloce, ma sono confuso riguardo ai componenti calcolati.
Ecco il codice importante di come lo faccio (dove traindata
è la mia matrice input dimensioni MXN):
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;
Il risultato di questo codice è qualcosa di simile:
Per confermare i miei risultati, ho provato lo stesso con WEKA. Quindi quello che ho fatto è usare il normalizzatore e il filtro centrale, in questo ordine. Quindi il componente principale filtra e salva + traccia l'output. Il risultato è questo:
Tecnicamente avrei fatto lo stesso, ma il risultato è così diverso. Qualcuno può vedere se ho fatto un errore?
Una cosa da aggiungere: sono sicuro che WEKA utilizza SVD. Ma questo non dovrebbe spiegare la differenza nel risultato o? – Chris