slope 0.29.0
Loading...
Searching...
No Matches
cv.h
Go to the documentation of this file.
1
11#pragma once
12
13#include "folds.h"
14#include "score.h"
15#include "slope.h"
16#include <vector>
17#ifdef _OPENMP
18#include <omp.h>
19#endif
20
21namespace slope {
22
30{
34 Eigen::MatrixXd score;
35
37 std::map<std::string, double> params;
38
40 Eigen::ArrayXd alphas;
41
43 Eigen::ArrayXd mean_scores;
44
47 Eigen::ArrayXd std_errors;
48};
49
58{
61 std::vector<GridResult> results;
62
65 std::map<std::string, double> best_params;
66
68 double best_score;
69
72
76};
77
86{
88 int n_folds = 10;
89
91 int n_repeats = 1;
92
94 std::string metric = "mse";
95
97 uint64_t random_seed = 42;
98
101 std::map<std::string, std::vector<double>> hyperparams = { { "q", { 0.1 } } };
102
104 std::optional<std::vector<std::vector<std::vector<int>>>> predefined_folds;
105};
106
118std::vector<std::map<std::string, double>>
119createGrid(const std::map<std::string, std::vector<double>>& param_values);
120
131void
132findBestParameters(CvResult& cv_result, const std::unique_ptr<Score>& scorer);
133
158template<typename MatrixType>
161 MatrixType& x,
162 const Eigen::MatrixXd& y_in,
163 const CvConfig& config = CvConfig())
164{
165 CvResult cv_result;
166
167 int n = y_in.rows();
168
169 auto loss = setupLoss(model.getLossType());
170
171 auto y = loss->preprocessResponse(y_in);
172 auto scorer = Score::create(config.metric);
173 auto grid = createGrid(config.hyperparams);
174
175 // Total number of evaluations (n_repeats * n_folds)
176 Folds folds =
177 config.predefined_folds.has_value()
178 ? Folds(config.predefined_folds.value())
179 : Folds(n, config.n_folds, config.n_repeats, config.random_seed);
180
181 int n_evals = folds.numEvals();
182
183 for (const auto& params : grid) {
184 GridResult result;
185 result.params = params;
186 model.setQ(params.at("q"));
187
188 auto initial_path = model.path(x, y);
189 result.alphas = initial_path.getAlpha();
190 int n_alpha = result.alphas.size();
191
192 assert((result.alphas > 0).all());
193
194 Eigen::MatrixXd scores = Eigen::MatrixXd::Zero(n_evals, n_alpha);
195
196 Eigen::setNbThreads(1);
197
198 // Thread-safety for exceptions
199 std::vector<std::string> thread_errors(n_evals);
200 bool had_exception = false;
201
202#ifdef _OPENMP
203 omp_set_max_active_levels(1);
204#pragma omp parallel for num_threads(Threads::get()) \
205 shared(scores, thread_errors, had_exception)
206#endif
207 for (int i = 0; i < n_evals; ++i) {
208 try {
209 auto [rep, fold] = std::div(i, folds.numFolds());
210
211 Slope thread_model = model;
212 thread_model.setModifyX(true);
213
214 // TODO: Maybe consider not copying at all?
215 auto [x_train, y_train, x_test, y_test] = folds.split(x, y, fold, rep);
216
217 auto path = thread_model.path(x_train, y_train, result.alphas);
218
219 for (int j = 0; j < n_alpha; ++j) {
220 auto eta = path(j).predict(x_test, "linear");
221 scores(i, j) = scorer->eval(eta, y_test, loss);
222 }
223 } catch (const std::exception& e) {
224 thread_errors[i] = e.what();
225#pragma omp atomic write
226 had_exception = true;
227 } catch (...) {
228 thread_errors[i] = "Unknown exception";
229#pragma omp atomic write
230 had_exception = true;
231 }
232 }
233
234 if (had_exception) {
235 std::string error_message = "Exception(s) during cross-validation:\n";
236 for (int i = 0; i < n_evals; ++i) {
237 if (!thread_errors[i].empty()) {
238 error_message +=
239 "Fold " + std::to_string(i) + ": " + thread_errors[i] + "\n";
240 }
241 }
242 throw std::runtime_error(error_message);
243 }
244
245 result.mean_scores = scores.colwise().mean();
246 result.std_errors = stdDevs(scores).array() / std::sqrt(n_evals);
247 result.score = std::move(scores);
248 cv_result.results.push_back(result);
249 }
250
251#ifdef _OPENMP
252 Eigen::setNbThreads(0);
253#endif
254
255 findBestParameters(cv_result, scorer);
256
257 return cv_result;
258}
259
260} // namespace slope
Manages data partitioning for cross-validation.
Definition folds.h:26
size_t numEvals() const
Get the total number of folds (repetitions * folds)
Definition folds.h:160
size_t numFolds() const
Get the number of folds.
Definition folds.h:146
std::tuple< MatrixType, Eigen::MatrixXd, MatrixType, Eigen::MatrixXd > split(MatrixType &x, const Eigen::MatrixXd &y, size_t fold_idx, size_t rep_idx=0) const
Split data into training and test sets for a specific fold and repetition.
Definition folds.h:123
static std::unique_ptr< Score > create(const std::string &metric)
Definition score.cpp:182
The SLOPE model.
Definition slope.h:29
SlopePath path(T &x, const Eigen::MatrixXd &y_in, Eigen::ArrayXd alpha=Eigen::ArrayXd::Zero(0), Eigen::ArrayXd lambda=Eigen::ArrayXd::Zero(0))
Computes SLOPE regression solution path for multiple alpha and lambda values.
Definition slope.cpp:27
const std::string & getLossType()
Get currently defined loss type.
Definition slope.cpp:579
void setModifyX(const bool modify_x)
Controls if x should be modified-in-place.
Definition slope.cpp:519
void setQ(double q)
Sets the q value.
Definition slope.cpp:434
Cross-validation fold management for SLOPE models.
Namespace containing SLOPE regression implementation.
Definition clusters.cpp:5
std::unique_ptr< Loss > setupLoss(const std::string &loss)
Factory function to create the appropriate loss function based on the distribution family.
void findBestParameters(CvResult &cv_result, const std::unique_ptr< Score > &scorer)
Identifies the best parameters from cross-validation results.
Definition cv.cpp:39
Eigen::VectorXd stdDevs(const Eigen::SparseMatrix< double > &x)
Computes the standard deviation for each column of a matrix.
Definition math.cpp:180
std::vector< std::map< std::string, double > > createGrid(const std::map< std::string, std::vector< double > > &param_values)
Creates a grid of parameter combinations from parameter value ranges.
Definition cv.cpp:6
CvResult crossValidate(Slope model, MatrixType &x, const Eigen::MatrixXd &y_in, const CvConfig &config=CvConfig())
Performs cross-validation on a SLOPE model to select optimal hyperparameters.
Definition cv.h:160
Scoring metrics for model evaluation.
SLOPE (Sorted L-One Penalized Estimation) optimization.
Configuration settings for cross-validation.
Definition cv.h:86
int n_repeats
Number of times to repeat the cross-validation (default: 1)
Definition cv.h:91
std::map< std::string, std::vector< double > > hyperparams
Definition cv.h:101
std::optional< std::vector< std::vector< std::vector< int > > > > predefined_folds
Optional user-defined fold assignments for custom cross-validation splits.
Definition cv.h:104
int n_folds
Number of folds for cross-validation (default: 10)
Definition cv.h:88
std::string metric
Evaluation metric used for model assessment (default: "mse")
Definition cv.h:94
uint64_t random_seed
Seed for random number generator to ensure reproducibility (default: 42)
Definition cv.h:97
Contains overall results from a cross-validation process.
Definition cv.h:58
double best_score
The score achieved by the optimal hyperparameter configuration.
Definition cv.h:68
std::map< std::string, double > best_params
Definition cv.h:65
std::vector< GridResult > results
Definition cv.h:61
int best_ind
Index of the best performing configuration in the results vector.
Definition cv.h:71
int best_alpha_ind
Definition cv.h:75
Stores cross-validation results for a specific set of hyperparameters.
Definition cv.h:30
Eigen::MatrixXd score
Definition cv.h:34
Eigen::ArrayXd mean_scores
Array of scores averaged across all folds for each alpha value.
Definition cv.h:43
std::map< std::string, double > params
Map of hyperparameter names to their values for the configuration.
Definition cv.h:37
Eigen::ArrayXd std_errors
Definition cv.h:47
Eigen::ArrayXd alphas
Array of regularization parameters used in the regularization path.
Definition cv.h:40