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)
134 if (iRank == 0) iRank = 1;
136 iRank = std::min(iRank, p);
140 for (
int i = 0; i < p - iRank; ++i) {
145 MatrixXd covPca = evecs * evals.asDiagonal() * evecs.transpose();
147 return {covPca,
static_cast<double>(iRank)};
158 Skigen::FactorAnalysis<double> fa(iNFactors, iMaxIter, dTol);
159 fa.fit(matData.transpose());
160 return {fa.covariance(), fa.log_likelihood()};
166 const MatrixXd& matCov)
168 const int p =
static_cast<int>(matTestData.rows());
169 const int n =
static_cast<int>(matTestData.cols());
172 SelfAdjointEigenSolver<MatrixXd> solver(matCov);
173 VectorXd evals = solver.eigenvalues().array().max(1e-30);
174 MatrixXd evecs = solver.eigenvectors();
177 double logDet = evals.array().log().sum();
180 MatrixXd covInv = evecs * evals.array().inverse().matrix().asDiagonal() * evecs.transpose();
183 MatrixXd Stest = (matTestData * matTestData.transpose()) /
static_cast<double>(n);
186 double trInvS = (covInv * Stest).trace();
189 return -0.5 * (
static_cast<double>(p) * std::log(2.0 *
M_PI) + logDet + trInvS);
197 const int n =
static_cast<int>(matData.cols());
199 if (iNFolds < 2) iNFolds = 2;
200 if (iNFolds > n) iNFolds = n;
203 std::vector<int> indices(
static_cast<size_t>(n));
204 std::iota(indices.begin(), indices.end(), 0);
207 std::mt19937 gen(42);
208 std::shuffle(indices.begin(), indices.end(), gen);
211 const int nMethods = 6;
212 std::vector<double> avgLL(
static_cast<size_t>(nMethods), 0.0);
214 const int foldSize = n / iNFolds;
216 for (
int fold = 0; fold < iNFolds; ++fold) {
218 int testStart = fold * foldSize;
219 int testEnd = (fold == iNFolds - 1) ? n : (fold + 1) * foldSize;
220 int nTest = testEnd - testStart;
221 int nTrain = n - nTest;
223 MatrixXd trainData(matData.rows(), nTrain);
224 MatrixXd testData(matData.rows(), nTest);
228 for (
int i = 0; i < n; ++i) {
229 int col = indices[
static_cast<size_t>(i)];
230 if (i >= testStart && i < testEnd) {
231 testData.col(testIdx++) = matData.col(col);
233 trainData.col(trainIdx++) = matData.col(col);
238 trainData.colwise() -= trainData.rowwise().mean();
239 testData.colwise() -= testData.rowwise().mean();
244 MatrixXd cov = (trainData * trainData.transpose()) /
static_cast<double>(nTrain);
246 cov.diagonal().array() += 1e-10 * cov.trace() /
static_cast<double>(cov.rows());
256 auto [cov, rho] =
oas(trainData);
266 auto [cov, rank] =
pca(trainData);
268 cov.diagonal().array() += 1e-10 * cov.trace() /
static_cast<double>(cov.rows());
279 for (
int m = 0; m < nMethods; ++m) {
280 avgLL[
static_cast<size_t>(m)] /=
static_cast<double>(iNFolds);
285 double bestLL = avgLL[0];
286 for (
int m = 1; m < nMethods; ++m) {
287 if (avgLL[
static_cast<size_t>(m)] > bestLL) {
288 bestLL = avgLL[
static_cast<size_t>(m)];
294 std::pair<MatrixXd, double> result;
295 switch (bestMethod) {
297 MatrixXd cov = (matData * matData.transpose()) /
static_cast<double>(n);
298 cov.diagonal().array() += 1e-10 * cov.trace() /
static_cast<double>(cov.rows());
299 result = {cov,
static_cast<double>(bestMethod)};
302 case 1: result =
ledoitWolf(matData); result.second =
static_cast<double>(bestMethod);
break;
303 case 2: result =
oas(matData); result.second =
static_cast<double>(bestMethod);
break;
304 case 3: result =
diagonalFixed(matData); result.second =
static_cast<double>(bestMethod);
break;
305 case 4: result =
pca(matData); result.second =
static_cast<double>(bestMethod);
break;
306 case 5: result =
factorAnalysis(matData); result.second =
static_cast<double>(bestMethod);
break;
307 default: result =
ledoitWolf(matData); result.second = 1.0;
break;
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.