1 #ifndef SUPPORT_VECTOR_REGRESSION_HPP
2 #define SUPPORT_VECTOR_REGRESSION_HPP
43 int degree = 3,
double gamma = 1.0,
double coef0 = 0.0);
55 void fit(
const std::vector<std::vector<double>>& X,
const std::vector<double>& y);
62 std::vector<double>
predict(
const std::vector<std::vector<double>>& X)
const;
72 std::vector<std::vector<double>> X_train;
73 std::vector<double> y_train;
74 std::vector<double> alpha;
75 std::vector<double> alpha_star;
78 std::function<double(
const std::vector<double>&,
const std::vector<double>&)> kernel;
83 void initialize_kernel();
95 double predict_sample(
const std::vector<double>& x)
const;
103 double compute_kernel(
const std::vector<double>& x1,
const std::vector<double>& x2)
const;
113 std::vector<double> errors;
118 void initialize_errors();
124 void update_error(
size_t i);
131 size_t select_second_index(
size_t i);
135 int degree,
double gamma,
double coef0)
136 : C(C), epsilon(epsilon), kernel_type(kernel_type), degree(degree), gamma(gamma), coef0(coef0), b(0.0) {
138 rng.seed(std::random_device{}());
143 void SupportVectorRegression::initialize_kernel() {
144 if (kernel_type == KernelType::LINEAR) {
145 kernel = [](
const std::vector<double>& x1,
const std::vector<double>& x2) {
146 return std::inner_product(x1.begin(), x1.end(), x2.begin(), 0.0);
148 }
else if (kernel_type == KernelType::POLYNOMIAL) {
149 kernel = [
this](
const std::vector<double>& x1,
const std::vector<double>& x2) {
150 return std::pow(gamma * std::inner_product(x1.begin(), x1.end(), x2.begin(), 0.0) + coef0, degree);
152 }
else if (kernel_type == KernelType::RBF) {
153 kernel = [
this](
const std::vector<double>& x1,
const std::vector<double>& x2) {
155 for (
size_t i = 0; i < x1.size(); ++i) {
156 double diff = x1[i] - x2[i];
159 return std::exp(-gamma * sum);
167 size_t n_samples = X_train.size();
169 alpha.resize(n_samples, 0.0);
170 alpha_star.resize(n_samples, 0.0);
178 std::vector<double> predictions;
179 predictions.reserve(X.size());
180 for (
const auto& x : X) {
181 predictions.push_back(predict_sample(x));
186 void SupportVectorRegression::initialize_errors() {
187 size_t n_samples = X_train.size();
188 errors.resize(n_samples);
189 for (
size_t i = 0; i < n_samples; ++i) {
190 errors[i] = predict_sample(X_train[i]) - y_train[i];
194 double SupportVectorRegression::predict_sample(
const std::vector<double>& x)
const {
196 size_t n_samples = X_train.size();
197 for (
size_t i = 0; i < n_samples; ++i) {
198 double coeff = alpha[i] - alpha_star[i];
199 if (std::abs(coeff) > 1e-8) {
200 result += coeff * compute_kernel(X_train[i], x);
206 double SupportVectorRegression::compute_kernel(
const std::vector<double>& x1,
const std::vector<double>& x2)
const {
207 return kernel(x1, x2);
210 void SupportVectorRegression::update_error(
size_t i) {
211 errors[i] = predict_sample(X_train[i]) - y_train[i];
214 size_t SupportVectorRegression::select_second_index(
size_t i) {
215 size_t n_samples = X_train.size();
216 std::uniform_int_distribution<size_t> dist(0, n_samples - 1);
217 size_t j = dist(rng);
224 void SupportVectorRegression::solve() {
225 size_t n_samples = X_train.size();
226 size_t max_passes = 5;
230 while (passes < max_passes) {
231 size_t num_changed_alphas = 0;
232 for (
size_t i = 0; i < n_samples; ++i) {
233 double E_i = errors[i];
236 bool violate_KKT_alpha = ((alpha[i] < C) && (E_i > epsilon)) || ((alpha[i] > 0) && (E_i < epsilon));
239 bool violate_KKT_alpha_star = ((alpha_star[i] < C) && (E_i < -epsilon)) || ((alpha_star[i] > 0) && (E_i > -epsilon));
241 if (violate_KKT_alpha || violate_KKT_alpha_star) {
242 size_t j = select_second_index(i);
243 double E_j = errors[j];
246 double K_ii = compute_kernel(X_train[i], X_train[i]);
247 double K_jj = compute_kernel(X_train[j], X_train[j]);
248 double K_ij = compute_kernel(X_train[i], X_train[j]);
249 double eta = K_ii + K_jj - 2 * K_ij;
255 double alpha_i_old = alpha[i];
256 double alpha_star_i_old = alpha_star[i];
257 double alpha_j_old = alpha[j];
258 double alpha_star_j_old = alpha_star[j];
261 double delta_alpha = 0.0;
263 if (violate_KKT_alpha) {
264 delta_alpha = std::min(C - alpha[i], std::max(-alpha[i], (E_i - E_j) / eta));
265 alpha[i] += delta_alpha;
266 alpha[j] -= delta_alpha;
267 }
else if (violate_KKT_alpha_star) {
268 delta_alpha = std::min(C - alpha_star[i], std::max(-alpha_star[i], -(E_i - E_j) / eta));
269 alpha_star[i] += delta_alpha;
270 alpha_star[j] -= delta_alpha;
274 double b1 = b - E_i - delta_alpha * (K_ii - K_ij);
275 double b2 = b - E_j - delta_alpha * (K_ij - K_jj);
277 if ((alpha[i] > 0 && alpha[i] < C) || (alpha_star[i] > 0 && alpha_star[i] < C))
279 else if ((alpha[j] > 0 && alpha[j] < C) || (alpha_star[j] > 0 && alpha_star[j] < C))
288 num_changed_alphas++;
292 if (num_changed_alphas == 0)
Support Vector Regression using the ε-insensitive loss function.
Definition: SupportVectorRegression.hpp:22
~SupportVectorRegression()
Destructor for SupportVectorRegression.
Definition: SupportVectorRegression.hpp:141
std::vector< double > predict(const std::vector< std::vector< double >> &X) const
Predicts target values for the given input data.
Definition: SupportVectorRegression.hpp:177
KernelType
Kernel function types.
Definition: SupportVectorRegression.hpp:27
void fit(const std::vector< std::vector< double >> &X, const std::vector< double > &y)
Fits the SVR model to the training data.
Definition: SupportVectorRegression.hpp:164
SupportVectorRegression(double C=1.0, double epsilon=0.1, KernelType kernel_type=KernelType::RBF, int degree=3, double gamma=1.0, double coef0=0.0)
Constructs a SupportVectorRegression model.
Definition: SupportVectorRegression.hpp:134