Skip to content

Commit 5bb158a

Browse files
intercept methodology
1 parent 95a54f0 commit 5bb158a

29 files changed

+78
-130
lines changed

API_REFERENCE_FOR_REGRESSION.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,6 @@ The index of the term selected. So ***0*** is the first term, ***1*** is the sec
181181
***Returns the regression coefficient of the intercept term.***
182182

183183

184-
## Method: get_intercept_steps()
185-
186-
***Returns a numpy vector containing the regression coefficients of the intercept term by boosting step.***
187-
188-
189184
## Method: get_optimal_m()
190185

191186
***Returns the number of boosting steps in the model (the value that minimized validation error).***

aplr/aplr.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,6 @@ def get_feature_importance(self)->npt.ArrayLike:
8787
def get_intercept(self)->float:
8888
return self.APLRRegressor.get_intercept()
8989

90-
def get_intercept_steps(self)->npt.ArrayLike:
91-
return self.APLRRegressor.get_intercept_steps()
92-
9390
def get_optimal_m(self)->int:
9491
return self.APLRRegressor.get_optimal_m()
9592

cpp/APLRRegressor.h

Lines changed: 33 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ class APLRRegressor
5050
std::set<int> unique_groups_train;
5151
std::set<int> unique_groups_validation;
5252
std::vector<int> interaction_constraints;
53-
bool update_intercept_only_once;
5453

5554
void validate_input_to_fit(const MatrixXd &X,const VectorXd &y,const VectorXd &sample_weight,const std::vector<std::string> &X_names,
5655
const std::vector<size_t> &validation_set_indexes, const std::vector<size_t> &prioritized_predictors_indexes,
@@ -78,7 +77,7 @@ class APLRRegressor
7877
void add_necessary_given_terms_to_interaction(Term &interaction, Term &existing_model_term);
7978
void find_sorted_indexes_for_errors_for_interactions_to_consider();
8079
void add_promising_interactions_and_select_the_best_one();
81-
void update_intercept(size_t boosting_step);
80+
void update_intercept();
8281
void select_the_best_term_and_update_errors(size_t boosting_step, bool not_evaluating_prioritized_predictors=true);
8382
void update_terms(size_t boosting_step);
8483
void update_gradient_and_errors();
@@ -128,7 +127,6 @@ class APLRRegressor
128127
std::vector<std::string> term_names;
129128
VectorXd term_coefficients;
130129
size_t max_interaction_level;
131-
VectorXd intercept_steps;
132130
size_t max_interactions;
133131
size_t interactions_eligible;
134132
VectorXd validation_error_steps;
@@ -165,7 +163,6 @@ class APLRRegressor
165163
VectorXd get_validation_error_steps();
166164
VectorXd get_feature_importance();
167165
double get_intercept();
168-
VectorXd get_intercept_steps();
169166
size_t get_optimal_m();
170167
std::string get_validation_tuning_metric();
171168
std::vector<size_t> get_validation_indexes();
@@ -178,7 +175,7 @@ APLRRegressor::APLRRegressor(size_t m,double v,uint_fast32_t random_state,std::s
178175
reserved_terms_times_num_x{reserved_terms_times_num_x},intercept{intercept},m{m},v{v},
179176
loss_function{loss_function},link_function{link_function},validation_ratio{validation_ratio},n_jobs{n_jobs},random_state{random_state},
180177
bins{bins},verbosity{verbosity},max_interaction_level{max_interaction_level},
181-
intercept_steps{VectorXd(0)},max_interactions{max_interactions},interactions_eligible{0},validation_error_steps{VectorXd(0)},
178+
max_interactions{max_interactions},interactions_eligible{0},validation_error_steps{VectorXd(0)},
182179
min_observations_in_split{min_observations_in_split},ineligible_boosting_steps_added{ineligible_boosting_steps_added},
183180
max_eligible_terms{max_eligible_terms},number_of_base_terms{0},dispersion_parameter{dispersion_parameter},min_training_prediction_or_response{NAN_DOUBLE},
184181
max_training_prediction_or_response{NAN_DOUBLE}, validation_tuning_metric{validation_tuning_metric},
@@ -191,8 +188,8 @@ APLRRegressor::APLRRegressor(const APLRRegressor &other):
191188
loss_function{other.loss_function},link_function{other.link_function},validation_ratio{other.validation_ratio},
192189
n_jobs{other.n_jobs},random_state{other.random_state},bins{other.bins},
193190
verbosity{other.verbosity},term_names{other.term_names},term_coefficients{other.term_coefficients},
194-
max_interaction_level{other.max_interaction_level},intercept_steps{other.intercept_steps},
195-
max_interactions{other.max_interactions},interactions_eligible{other.interactions_eligible},validation_error_steps{other.validation_error_steps},
191+
max_interaction_level{other.max_interaction_level},max_interactions{other.max_interactions},
192+
interactions_eligible{other.interactions_eligible},validation_error_steps{other.validation_error_steps},
196193
min_observations_in_split{other.min_observations_in_split},ineligible_boosting_steps_added{other.ineligible_boosting_steps_added},
197194
max_eligible_terms{other.max_eligible_terms},number_of_base_terms{other.number_of_base_terms},
198195
feature_importance{other.feature_importance},dispersion_parameter{other.dispersion_parameter},min_training_prediction_or_response{other.min_training_prediction_or_response},
@@ -289,6 +286,12 @@ void APLRRegressor::throw_error_if_dispersion_parameter_is_invalid()
289286
}
290287
}
291288

289+
void APLRRegressor::throw_error_if_m_is_invalid()
290+
{
291+
if(m<1)
292+
throw std::runtime_error("The maximum number of boosting steps, m, must be at least 1.");
293+
}
294+
292295
void APLRRegressor::validate_input_to_fit(const MatrixXd &X,const VectorXd &y,const VectorXd &sample_weight,
293296
const std::vector<std::string> &X_names, const std::vector<size_t> &validation_set_indexes,
294297
const std::vector<size_t> &prioritized_predictors_indexes, const std::vector<int> &monotonic_constraints, const VectorXi &group,
@@ -546,21 +549,7 @@ void APLRRegressor::initialize(const std::vector<size_t> &prioritized_predictors
546549
terms.clear();
547550
terms.reserve(X_train.cols()*reserved_terms_times_num_x);
548551

549-
if(loss_function == "group_mse")
550-
{
551-
update_intercept_only_once = true;
552-
if(sample_weight_train.size()==0)
553-
intercept = y_train.mean();
554-
else
555-
intercept = (y_train.array()*sample_weight_train.array()).sum()/sample_weight_train.array().sum();
556-
}
557-
else
558-
{
559-
update_intercept_only_once = false;
560-
intercept=0;
561-
}
562-
intercept_steps=VectorXd::Constant(m, intercept);
563-
552+
double initial_prediction{0.0};
564553

565554
terms_eligible_current.reserve(X_train.cols()*reserved_terms_times_num_x);
566555
size_t X_train_cols{static_cast<size_t>(X_train.cols())};
@@ -602,9 +591,9 @@ void APLRRegressor::initialize(const std::vector<size_t> &prioritized_predictors
602591
}
603592
}
604593

605-
linear_predictor_current=VectorXd::Constant(y_train.size(),intercept);
594+
linear_predictor_current=VectorXd::Constant(y_train.size(),initial_prediction);
606595
linear_predictor_null_model=linear_predictor_current;
607-
linear_predictor_current_validation=VectorXd::Constant(y_validation.size(),intercept);
596+
linear_predictor_current_validation=VectorXd::Constant(y_validation.size(),initial_prediction);
608597
predictions_current=transform_linear_predictor_to_predictions(linear_predictor_current,link_function);
609598
predictions_current_validation=transform_linear_predictor_to_predictions(linear_predictor_current_validation,link_function);
610599

@@ -717,17 +706,31 @@ VectorXd APLRRegressor::differentiate_predictions()
717706
void APLRRegressor::execute_boosting_steps()
718707
{
719708
abort_boosting = false;
720-
for (size_t boosting_step = 0; boosting_step < m; ++boosting_step)
709+
update_intercept();
710+
for (size_t boosting_step = 1; boosting_step < m; ++boosting_step)
721711
{
722712
execute_boosting_step(boosting_step);
723713
if(abort_boosting) break;
724714
}
725715
}
726716

717+
void APLRRegressor::update_intercept()
718+
{
719+
double intercept_update;
720+
if(sample_weight_train.size()==0)
721+
intercept=neg_gradient_current.mean();
722+
else
723+
intercept=(neg_gradient_current.array()*sample_weight_train.array()).sum()/sample_weight_train.array().sum();
724+
linear_predictor_update=VectorXd::Constant(neg_gradient_current.size(),intercept);
725+
linear_predictor_update_validation=VectorXd::Constant(y_validation.size(),intercept);
726+
update_linear_predictor_and_predictions();
727+
update_gradient_and_errors();
728+
calculate_and_validate_validation_error(0);
729+
print_summary_after_boosting_step(0);
730+
}
731+
727732
void APLRRegressor::execute_boosting_step(size_t boosting_step)
728733
{
729-
if(!update_intercept_only_once)
730-
update_intercept(boosting_step);
731734
bool prioritize_predictors{!abort_boosting && prioritized_predictors_indexes.size()>0};
732735
if(prioritize_predictors)
733736
{
@@ -758,25 +761,6 @@ void APLRRegressor::execute_boosting_step(size_t boosting_step)
758761
print_summary_after_boosting_step(boosting_step);
759762
}
760763

761-
void APLRRegressor::update_intercept(size_t boosting_step)
762-
{
763-
double intercept_update;
764-
if(sample_weight_train.size()==0)
765-
intercept_update=v*neg_gradient_current.mean();
766-
else
767-
intercept_update=v*(neg_gradient_current.array()*sample_weight_train.array()).sum()/sample_weight_train.array().sum();
768-
linear_predictor_update=VectorXd::Constant(neg_gradient_current.size(),intercept_update);
769-
linear_predictor_update_validation=VectorXd::Constant(y_validation.size(),intercept_update);
770-
update_linear_predictor_and_predictions();
771-
update_gradient_and_errors();
772-
calculate_and_validate_validation_error(boosting_step);
773-
if(!abort_boosting)
774-
{
775-
intercept+=intercept_update;
776-
intercept_steps[boosting_step]=intercept;
777-
}
778-
}
779-
780764
void APLRRegressor::update_linear_predictor_and_predictions()
781765
{
782766
linear_predictor_current+=linear_predictor_update;
@@ -1219,13 +1203,6 @@ void APLRRegressor::print_summary_after_boosting_step(size_t boosting_step)
12191203

12201204
void APLRRegressor::update_coefficients_for_all_steps()
12211205
{
1222-
for (size_t j = 0; j < m; ++j)
1223-
{
1224-
bool fill_down_coefficient_steps{j>0 && is_approximately_zero(intercept_steps[j]) && !is_approximately_zero(intercept_steps[j-1])};
1225-
if(fill_down_coefficient_steps)
1226-
intercept_steps[j]=intercept_steps[j-1];
1227-
}
1228-
12291206
for (size_t i = 0; i < terms.size(); ++i)
12301207
{
12311208
for (size_t j = 0; j < m; ++j)
@@ -1249,7 +1226,6 @@ void APLRRegressor::find_optimal_m_and_update_model_accordingly()
12491226
{
12501227
size_t best_boosting_step_index;
12511228
validation_error_steps.minCoeff(&best_boosting_step_index);
1252-
intercept=intercept_steps[best_boosting_step_index];
12531229
for (size_t i = 0; i < terms.size(); ++i)
12541230
{
12551231
terms[i].coefficient = terms[i].coefficient_steps[best_boosting_step_index];
@@ -1274,10 +1250,6 @@ void APLRRegressor::revert_scaling_if_using_log_link_function()
12741250
{
12751251
y_train/=scaling_factor_for_log_link_function;
12761252
intercept+=std::log(1/scaling_factor_for_log_link_function);
1277-
for (Eigen::Index i = 0; i < intercept_steps.size(); ++i)
1278-
{
1279-
intercept_steps[i]+=std::log(1/scaling_factor_for_log_link_function);
1280-
}
12811253
}
12821254
}
12831255

@@ -1451,13 +1423,13 @@ VectorXd APLRRegressor::predict(const MatrixXd &X, bool cap_predictions_to_minma
14511423

14521424
VectorXd APLRRegressor::calculate_linear_predictor(const MatrixXd &X)
14531425
{
1454-
VectorXd predictions{VectorXd::Constant(X.rows(),intercept)};
1426+
VectorXd linear_predictor{VectorXd::Constant(X.rows(),intercept)};
14551427
for (size_t i = 0; i < terms.size(); ++i)
14561428
{
14571429
VectorXd contrib{terms[i].calculate_contribution_to_linear_predictor(X)};
1458-
predictions+=contrib;
1430+
linear_predictor+=contrib;
14591431
}
1460-
return predictions;
1432+
return linear_predictor;
14611433
}
14621434

14631435
void APLRRegressor::cap_predictions_to_minmax_in_training(VectorXd &predictions)
@@ -1531,11 +1503,6 @@ double APLRRegressor::get_intercept()
15311503
return intercept;
15321504
}
15331505

1534-
VectorXd APLRRegressor::get_intercept_steps()
1535-
{
1536-
return intercept_steps;
1537-
}
1538-
15391506
size_t APLRRegressor::get_optimal_m()
15401507
{
15411508
return m_optimal;
@@ -1549,10 +1516,4 @@ std::string APLRRegressor::get_validation_tuning_metric()
15491516
std::vector<size_t> APLRRegressor::get_validation_indexes()
15501517
{
15511518
return validation_indexes;
1552-
}
1553-
1554-
void APLRRegressor::throw_error_if_m_is_invalid()
1555-
{
1556-
if(m<1)
1557-
throw std::runtime_error("The maximum number of boosting steps, m, must be at least 1.");
15581519
}

cpp/pythonbinding.cpp

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,10 @@ PYBIND11_MODULE(aplr_cpp, m) {
3939
.def("get_validation_error_steps", &APLRRegressor::get_validation_error_steps)
4040
.def("get_feature_importance", &APLRRegressor::get_feature_importance)
4141
.def("get_intercept", &APLRRegressor::get_intercept)
42-
.def("get_intercept_steps", &APLRRegressor::get_intercept_steps)
4342
.def("get_optimal_m", &APLRRegressor::get_optimal_m)
4443
.def("get_validation_tuning_metric", &APLRRegressor::get_validation_tuning_metric)
4544
.def("get_validation_indexes", &APLRRegressor::get_validation_indexes)
4645
.def_readwrite("intercept", &APLRRegressor::intercept)
47-
.def_readwrite("intercept_steps", &APLRRegressor::intercept_steps)
4846
.def_readwrite("m", &APLRRegressor::m)
4947
.def_readwrite("m_optimal", &APLRRegressor::m_optimal)
5048
.def_readwrite("v", &APLRRegressor::v)
@@ -77,36 +75,35 @@ PYBIND11_MODULE(aplr_cpp, m) {
7775
[](const APLRRegressor &a) { // __getstate__
7876
/* Return a tuple that fully encodes the state of the object */
7977
return py::make_tuple(a.m,a.v,a.random_state,a.loss_function,a.n_jobs,a.validation_ratio,a.intercept,a.bins,a.verbosity,
80-
a.max_interaction_level,a.max_interactions,a.validation_error_steps,a.term_names,a.term_coefficients,a.terms,a.intercept_steps,
78+
a.max_interaction_level,a.max_interactions,a.validation_error_steps,a.term_names,a.term_coefficients,a.terms,
8179
a.interactions_eligible,a.min_observations_in_split,a.ineligible_boosting_steps_added,a.max_eligible_terms,
8280
a.number_of_base_terms,a.feature_importance,a.link_function,a.dispersion_parameter,a.min_training_prediction_or_response,a.max_training_prediction_or_response,
8381
a.validation_tuning_metric,a.validation_indexes,a.quantile,a.m_optimal);
8482
},
8583
[](py::tuple t) { // __setstate__
86-
if (t.size() != 30)
84+
if (t.size() != 29)
8785
throw std::runtime_error("Invalid state!");
8886

8987
/* Create a new C++ instance */
9088
APLRRegressor a(t[0].cast<size_t>(),t[1].cast<double>(),t[2].cast<uint_fast32_t>(),t[3].cast<std::string>(),
91-
t[22].cast<std::string>(),t[4].cast<size_t>(),t[5].cast<double>(),
92-
t[6].cast<double>(),100,t[7].cast<size_t>(),t[8].cast<size_t>(),t[9].cast<size_t>(),t[10].cast<double>(),t[17].cast<size_t>(),
93-
t[23].cast<double>(),t[28].cast<double>());
89+
t[21].cast<std::string>(),t[4].cast<size_t>(),t[5].cast<double>(),
90+
t[6].cast<double>(),100,t[7].cast<size_t>(),t[8].cast<size_t>(),t[9].cast<size_t>(),t[10].cast<double>(),t[16].cast<size_t>(),
91+
t[22].cast<double>(),t[27].cast<double>());
9492

9593
a.validation_error_steps=t[11].cast<VectorXd>();
9694
a.term_names=t[12].cast<std::vector<std::string>>();
9795
a.term_coefficients=t[13].cast<VectorXd>();
9896
a.terms=t[14].cast<std::vector<Term>>();
99-
a.intercept_steps=t[15].cast<VectorXd>();
100-
a.interactions_eligible=t[16].cast<size_t>();
101-
a.ineligible_boosting_steps_added=t[18].cast<size_t>();
102-
a.max_eligible_terms=t[19].cast<size_t>();
103-
a.number_of_base_terms=t[20].cast<size_t>();
104-
a.feature_importance=t[21].cast<VectorXd>();
105-
a.min_training_prediction_or_response=t[24].cast<double>();
106-
a.max_training_prediction_or_response=t[25].cast<double>();
107-
a.validation_tuning_metric=t[26].cast<std::string>();
108-
a.validation_indexes=t[27].cast<std::vector<size_t>>();
109-
a.m_optimal=t[29].cast<size_t>();
97+
a.interactions_eligible=t[15].cast<size_t>();
98+
a.ineligible_boosting_steps_added=t[17].cast<size_t>();
99+
a.max_eligible_terms=t[18].cast<size_t>();
100+
a.number_of_base_terms=t[19].cast<size_t>();
101+
a.feature_importance=t[20].cast<VectorXd>();
102+
a.min_training_prediction_or_response=t[23].cast<double>();
103+
a.max_training_prediction_or_response=t[24].cast<double>();
104+
a.validation_tuning_metric=t[25].cast<std::string>();
105+
a.validation_indexes=t[26].cast<std::vector<size_t>>();
106+
a.m_optimal=t[28].cast<size_t>();
110107

111108
return a;
112109
}

cpp/test ALRRegressor cauchy group_mse validation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ int main()
5555
save_as_csv_file("data/output.csv",predictions);
5656

5757
std::cout<<predictions.mean()<<"\n\n";
58-
tests.push_back(is_approximately_equal(predictions.mean(),20.2462,0.00001));
58+
tests.push_back(is_approximately_equal(predictions.mean(),12.764,0.00001));
5959

6060
//Test summary
6161
std::cout<<"\n\nTest summary\n"<<"Passed "<<std::accumulate(tests.begin(),tests.end(),0)<<" out of "<<tests.size()<<" tests.";

cpp/test ALRRegressor cauchy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ int main()
5252
save_as_csv_file("data/output.csv",predictions);
5353

5454
std::cout<<predictions.mean()<<"\n\n";
55-
tests.push_back(is_approximately_equal(predictions.mean(),19.7161,0.00001));
55+
tests.push_back(is_approximately_equal(predictions.mean(),12.108,0.00001));
5656

5757
//Test summary
5858
std::cout<<"\n\nTest summary\n"<<"Passed "<<std::accumulate(tests.begin(),tests.end(),0)<<" out of "<<tests.size()<<" tests.";

cpp/test ALRRegressor gamma rank unweighted.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ int main()
5353
save_as_csv_file("data/output.csv",predictions);
5454

5555
std::cout<<predictions.mean()<<"\n\n";
56-
tests.push_back(is_approximately_equal(predictions.mean(),23.6581,0.00001));
56+
tests.push_back(is_approximately_equal(predictions.mean(),23.6509,0.00001));
5757

5858
//Test summary
5959
std::cout<<"\n\nTest summary\n"<<"Passed "<<std::accumulate(tests.begin(),tests.end(),0)<<" out of "<<tests.size()<<" tests.";

cpp/test ALRRegressor gamma rank.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ int main()
5353
save_as_csv_file("data/output.csv",predictions);
5454

5555
std::cout<<predictions.mean()<<"\n\n";
56-
tests.push_back(is_approximately_equal(predictions.mean(),23.6581,0.00001));
56+
tests.push_back(is_approximately_equal(predictions.mean(),23.6509,0.00001));
5757

5858
//Test summary
5959
std::cout<<"\n\nTest summary\n"<<"Passed "<<std::accumulate(tests.begin(),tests.end(),0)<<" out of "<<tests.size()<<" tests.";

cpp/test ALRRegressor gamma.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ int main()
5353
save_as_csv_file("data/output.csv",predictions);
5454

5555
std::cout<<predictions.mean()<<"\n\n";
56-
tests.push_back(is_approximately_equal(predictions.mean(),23.6503,0.00001));
56+
tests.push_back(is_approximately_equal(predictions.mean(),23.6458,0.00001));
5757

5858
//Test summary
5959
std::cout<<"\n\nTest summary\n"<<"Passed "<<std::accumulate(tests.begin(),tests.end(),0)<<" out of "<<tests.size()<<" tests.";

cpp/test ALRRegressor int constr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ int main()
5252
save_as_csv_file("data/output.csv",predictions);
5353

5454
std::cout<<predictions.mean()<<"\n\n";
55-
tests.push_back(is_approximately_equal(predictions.mean(),23.4597,0.00001));
55+
tests.push_back(is_approximately_equal(predictions.mean(),23.5213,0.00001));
5656

5757
//std::cout<<model.validation_error_steps<<"\n\n";
5858

0 commit comments

Comments
 (0)