114 const int p =
static_cast<int>(matData.rows());
115 const int n =
static_cast<int>(matData.cols());
118 const MatrixXd
S = (matData * matData.transpose()) /
static_cast<double>(n);
121 SelfAdjointEigenSolver<MatrixXd> solver(
S);
122 VectorXd evals = solver.eigenvalues();
123 MatrixXd evecs = solver.eigenvectors();
127 const double maxEval = evals.maxCoeff();
128 const double threshold = maxEval * 1e-10;
130 for (
int i = 0; i < p; ++i) {
131 if (evals(i) > threshold)
137 iRank = std::min(iRank, p);
141 for (
int i = 0; i < p - iRank; ++i) {
146 MatrixXd covPca = evecs * evals.asDiagonal() * evecs.transpose();
148 return {covPca,
static_cast<double>(iRank)};
159 Skigen::FactorAnalysis<double> fa(iNFactors, iMaxIter, dTol);
160 fa.fit(matData.transpose());
161 return {fa.covariance(), fa.log_likelihood()};
167 const MatrixXd& matCov)
169 const int p =
static_cast<int>(matTestData.rows());
170 const int n =
static_cast<int>(matTestData.cols());
173 SelfAdjointEigenSolver<MatrixXd> solver(matCov);
174 VectorXd evals = solver.eigenvalues().array().max(1e-30);
175 MatrixXd evecs = solver.eigenvectors();
178 double logDet = evals.array().log().sum();
181 MatrixXd covInv = evecs * evals.array().inverse().matrix().asDiagonal() * evecs.transpose();
184 MatrixXd Stest = (matTestData * matTestData.transpose()) /
static_cast<double>(n);
187 double trInvS = (covInv * Stest).trace();
190 return -0.5 * (
static_cast<double>(p) * std::log(2.0 *
M_PI) + logDet + trInvS);
198 const int n =
static_cast<int>(matData.cols());
206 std::vector<int> indices(
static_cast<size_t>(n));
207 std::iota(indices.begin(), indices.end(), 0);
210 std::mt19937 gen(42);
211 std::shuffle(indices.begin(), indices.end(), gen);
214 const int nMethods = 6;
215 std::vector<double> avgLL(
static_cast<size_t>(nMethods), 0.0);
217 const int foldSize = n / iNFolds;
219 for (
int fold = 0; fold < iNFolds; ++fold) {
221 int testStart = fold * foldSize;
222 int testEnd = (fold == iNFolds - 1) ? n : (fold + 1) * foldSize;
223 int nTest = testEnd - testStart;
224 int nTrain = n - nTest;
226 MatrixXd trainData(matData.rows(), nTrain);
227 MatrixXd testData(matData.rows(), nTest);
231 for (
int i = 0; i < n; ++i) {
232 int col = indices[
static_cast<size_t>(i)];
233 if (i >= testStart && i < testEnd) {
234 testData.col(testIdx++) = matData.col(col);
236 trainData.col(trainIdx++) = matData.col(col);
241 trainData.colwise() -= trainData.rowwise().mean();
242 testData.colwise() -= testData.rowwise().mean();
247 MatrixXd cov = (trainData * trainData.transpose()) /
static_cast<double>(nTrain);
249 cov.diagonal().array() += 1e-10 * cov.trace() /
static_cast<double>(cov.rows());
259 auto [cov, rho] =
oas(trainData);
269 auto [cov, rank] =
pca(trainData);
271 cov.diagonal().array() += 1e-10 * cov.trace() /
static_cast<double>(cov.rows());
282 for (
int m = 0; m < nMethods; ++m) {
283 avgLL[
static_cast<size_t>(m)] /=
static_cast<double>(iNFolds);
288 double bestLL = avgLL[0];
289 for (
int m = 1; m < nMethods; ++m) {
290 if (avgLL[
static_cast<size_t>(m)] > bestLL) {
291 bestLL = avgLL[
static_cast<size_t>(m)];
297 std::pair<MatrixXd, double> result;
298 switch (bestMethod) {
300 MatrixXd cov = (matData * matData.transpose()) /
static_cast<double>(n);
301 cov.diagonal().array() += 1e-10 * cov.trace() /
static_cast<double>(cov.rows());
302 result = {cov,
static_cast<double>(bestMethod)};
307 result.second =
static_cast<double>(bestMethod);
310 result =
oas(matData);
311 result.second =
static_cast<double>(bestMethod);
315 result.second =
static_cast<double>(bestMethod);
318 result =
pca(matData);
319 result.second =
static_cast<double>(bestMethod);
323 result.second =
static_cast<double>(bestMethod);
static std::pair< Eigen::MatrixXd, double > factorAnalysis(const Eigen::MatrixXd &matData, int iNFactors=0, int iMaxIter=200, double dTol=1e-6)
Factor Analysis covariance estimator via EM algorithm.