Skip to content

Commit e341ed0

Browse files
960
1 parent a39bd12 commit e341ed0

File tree

10 files changed

+234
-26
lines changed

10 files changed

+234
-26
lines changed

API_REFERENCE_FOR_CLASSIFICATION.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# APLRClassifier
22

3-
## class aplr.APLRClassifier(m:int=3000, v:float=0.1, random_state:int=0, n_jobs:int=0, cv_folds:int=5, bins:int=300, verbosity:int=0, max_interaction_level:int=1, max_interactions:int=100000, min_observations_in_split:int=20, ineligible_boosting_steps_added:int=10, max_eligible_terms:int=5, boosting_steps_before_interactions_are_allowed: int = 0, monotonic_constraints_ignore_interactions: bool = False, early_stopping_rounds: int = 500, num_first_steps_with_linear_effects_only: int = 0)
3+
## class aplr.APLRClassifier(m:int=3000, v:float=0.1, random_state:int=0, n_jobs:int=0, cv_folds:int=5, bins:int=300, verbosity:int=0, max_interaction_level:int=1, max_interactions:int=100000, min_observations_in_split:int=20, ineligible_boosting_steps_added:int=10, max_eligible_terms:int=5, boosting_steps_before_interactions_are_allowed: int = 0, monotonic_constraints_ignore_interactions: bool = False, early_stopping_rounds: int = 500, num_first_steps_with_linear_effects_only: int = 0, penalty_for_non_linearity: float = 0.0, penalty_for_interactions: float = 0.0)
44

55
### Constructor parameters
66

@@ -52,6 +52,12 @@ If validation loss does not improve during the last ***early_stopping_rounds***
5252
#### num_first_steps_with_linear_effects_only (default = 0)
5353
Specifies the number of initial boosting steps that are reserved only for linear effects. 0 means that non-linear effects are allowed from the first boosting step. Reasons for setting this parameter to a higher value than 0 could be to 1) build a more interpretable model with more emphasis on linear effects or 2) build a linear only model by setting ***num_first_steps_with_linear_effects_only*** to no less than ***m***.
5454

55+
#### penalty_for_non_linearity (default = 0.0)
56+
Specifies a penalty in the range [0.0, 1.0] on terms that are not linear effects. A higher value increases model interpretability but can hurt predictiveness.
57+
58+
#### penalty_for_interactions (default = 0.0)
59+
Specifies a penalty in the range [0.0, 1.0] on interaction terms. A higher value increases model interpretability but can hurt predictiveness.
60+
5561

5662
## Method: fit(X:npt.ArrayLike, y:List[str], sample_weight:npt.ArrayLike = np.empty(0), X_names:List[str]=[], cv_observations: npt.ArrayLike = np.empty([0, 0]), prioritized_predictors_indexes:List[int]=[], monotonic_constraints:List[int]=[], interaction_constraints:List[List[int]]=[])
5763

API_REFERENCE_FOR_REGRESSION.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# APLRRegressor
22

3-
## class aplr.APLRRegressor(m:int=3000, v:float=0.1, random_state:int=0, loss_function:str="mse", link_function:str="identity", n_jobs:int=0, cv_folds:int=5, bins:int=300, max_interaction_level:int=1, max_interactions:int=100000, min_observations_in_split:int=20, ineligible_boosting_steps_added:int=10, max_eligible_terms:int=5, verbosity:int=0, dispersion_parameter:float=1.5, validation_tuning_metric:str="default", quantile:float=0.5, calculate_custom_validation_error_function:Optional[Callable[[npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike], float]]=None, calculate_custom_loss_function:Optional[Callable[[npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike], float]]=None, calculate_custom_negative_gradient_function:Optional[Callable[[npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike], npt.ArrayLike]]=None, calculate_custom_transform_linear_predictor_to_predictions_function:Optional[Callable[[npt.ArrayLike], npt.ArrayLike]]=None, calculate_custom_differentiate_predictions_wrt_linear_predictor_function:Optional[Callable[[npt.ArrayLike], npt.ArrayLike]]=None, boosting_steps_before_interactions_are_allowed: int = 0, monotonic_constraints_ignore_interactions: bool = False, group_mse_by_prediction_bins: int = 10, group_mse_cycle_min_obs_in_bin: int = 30, early_stopping_rounds: int = 500, num_first_steps_with_linear_effects_only: int = 0)
3+
## class aplr.APLRRegressor(m:int=3000, v:float=0.1, random_state:int=0, loss_function:str="mse", link_function:str="identity", n_jobs:int=0, cv_folds:int=5, bins:int=300, max_interaction_level:int=1, max_interactions:int=100000, min_observations_in_split:int=20, ineligible_boosting_steps_added:int=10, max_eligible_terms:int=5, verbosity:int=0, dispersion_parameter:float=1.5, validation_tuning_metric:str="default", quantile:float=0.5, calculate_custom_validation_error_function:Optional[Callable[[npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike], float]]=None, calculate_custom_loss_function:Optional[Callable[[npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike], float]]=None, calculate_custom_negative_gradient_function:Optional[Callable[[npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike], npt.ArrayLike]]=None, calculate_custom_transform_linear_predictor_to_predictions_function:Optional[Callable[[npt.ArrayLike], npt.ArrayLike]]=None, calculate_custom_differentiate_predictions_wrt_linear_predictor_function:Optional[Callable[[npt.ArrayLike], npt.ArrayLike]]=None, boosting_steps_before_interactions_are_allowed: int = 0, monotonic_constraints_ignore_interactions: bool = False, group_mse_by_prediction_bins: int = 10, group_mse_cycle_min_obs_in_bin: int = 30, early_stopping_rounds: int = 500, num_first_steps_with_linear_effects_only: int = 0, penalty_for_non_linearity: float = 0.0, penalty_for_interactions: float = 0.0)
44

55
### Constructor parameters
66

@@ -120,6 +120,12 @@ If validation loss does not improve during the last ***early_stopping_rounds***
120120
#### num_first_steps_with_linear_effects_only (default = 0)
121121
Specifies the number of initial boosting steps that are reserved only for linear effects. 0 means that non-linear effects are allowed from the first boosting step. Reasons for setting this parameter to a higher value than 0 could be to 1) build a more interpretable model with more emphasis on linear effects or 2) build a linear only model by setting ***num_first_steps_with_linear_effects_only*** to no less than ***m***.
122122

123+
#### penalty_for_non_linearity (default = 0.0)
124+
Specifies a penalty in the range [0.0, 1.0] on terms that are not linear effects. A higher value increases model interpretability but can hurt predictiveness.
125+
126+
#### penalty_for_interactions (default = 0.0)
127+
Specifies a penalty in the range [0.0, 1.0] on interaction terms. A higher value increases model interpretability but can hurt predictiveness.
128+
123129

124130
## Method: fit(X:npt.ArrayLike, y:npt.ArrayLike, sample_weight:npt.ArrayLike = np.empty(0), X_names:List[str]=[], cv_observations: npt.ArrayLike = np.empty([0, 0]), prioritized_predictors_indexes:List[int]=[], monotonic_constraints:List[int]=[], group:npt.ArrayLike = np.empty(0), interaction_constraints:List[List[int]]=[], other_data: npt.ArrayLike = np.empty([0, 0]))
125131

aplr/aplr.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ def __init__(
6666
group_mse_cycle_min_obs_in_bin: int = 30,
6767
early_stopping_rounds: int = 500,
6868
num_first_steps_with_linear_effects_only: int = 0,
69+
penalty_for_non_linearity: float = 0.0,
70+
penalty_for_interactions: float = 0.0,
6971
):
7072
self.m = m
7173
self.v = v
@@ -109,6 +111,8 @@ def __init__(
109111
self.num_first_steps_with_linear_effects_only = (
110112
num_first_steps_with_linear_effects_only
111113
)
114+
self.penalty_for_non_linearity = penalty_for_non_linearity
115+
self.penalty_for_interactions = penalty_for_interactions
112116

113117
# Creating aplr_cpp and setting parameters
114118
self.APLRRegressor = aplr_cpp.APLRRegressor()
@@ -166,6 +170,8 @@ def __set_params_cpp(self):
166170
self.APLRRegressor.num_first_steps_with_linear_effects_only = (
167171
self.num_first_steps_with_linear_effects_only
168172
)
173+
self.APLRRegressor.penalty_for_non_linearity = self.penalty_for_non_linearity
174+
self.APLRRegressor.penalty_for_interactions = self.penalty_for_interactions
169175

170176
def fit(
171177
self,
@@ -294,6 +300,8 @@ def get_params(self, deep=True):
294300
"group_mse_cycle_min_obs_in_bin": self.group_mse_cycle_min_obs_in_bin,
295301
"early_stopping_rounds": self.early_stopping_rounds,
296302
"num_first_steps_with_linear_effects_only": self.num_first_steps_with_linear_effects_only,
303+
"penalty_for_non_linearity": self.penalty_for_non_linearity,
304+
"penalty_for_interactions": self.penalty_for_interactions,
297305
}
298306

299307
# For sklearn
@@ -323,6 +331,8 @@ def __init__(
323331
monotonic_constraints_ignore_interactions: bool = False,
324332
early_stopping_rounds: int = 500,
325333
num_first_steps_with_linear_effects_only: int = 0,
334+
penalty_for_non_linearity: float = 0.0,
335+
penalty_for_interactions: float = 0.0,
326336
):
327337
self.m = m
328338
self.v = v
@@ -346,6 +356,8 @@ def __init__(
346356
self.num_first_steps_with_linear_effects_only = (
347357
num_first_steps_with_linear_effects_only
348358
)
359+
self.penalty_for_non_linearity = penalty_for_non_linearity
360+
self.penalty_for_interactions = penalty_for_interactions
349361

350362
# Creating aplr_cpp and setting parameters
351363
self.APLRClassifier = aplr_cpp.APLRClassifier()
@@ -377,6 +389,8 @@ def __set_params_cpp(self):
377389
self.APLRClassifier.num_first_steps_with_linear_effects_only = (
378390
self.num_first_steps_with_linear_effects_only
379391
)
392+
self.APLRClassifier.penalty_for_non_linearity = self.penalty_for_non_linearity
393+
self.APLRClassifier.penalty_for_interactions = self.penalty_for_interactions
380394

381395
def fit(
382396
self,
@@ -450,6 +464,8 @@ def get_params(self, deep=True):
450464
"monotonic_constraints_ignore_interactions": self.monotonic_constraints_ignore_interactions,
451465
"early_stopping_rounds": self.early_stopping_rounds,
452466
"num_first_steps_with_linear_effects_only": self.num_first_steps_with_linear_effects_only,
467+
"penalty_for_non_linearity": self.penalty_for_non_linearity,
468+
"penalty_for_interactions": self.penalty_for_interactions,
453469
}
454470

455471
# For sklearn

cpp/APLRClassifier.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,15 @@ class APLRClassifier
4646
bool monotonic_constraints_ignore_interactions;
4747
size_t early_stopping_rounds;
4848
size_t num_first_steps_with_linear_effects_only;
49+
double penalty_for_non_linearity;
50+
double penalty_for_interactions;
4951

5052
APLRClassifier(size_t m = 3000, double v = 0.1, uint_fast32_t random_state = std::numeric_limits<uint_fast32_t>::lowest(), size_t n_jobs = 0,
5153
size_t cv_folds = 5, size_t reserved_terms_times_num_x = 100, size_t bins = 300, size_t verbosity = 0, size_t max_interaction_level = 1,
5254
size_t max_interactions = 100000, size_t min_observations_in_split = 20, size_t ineligible_boosting_steps_added = 10, size_t max_eligible_terms = 5,
5355
size_t boosting_steps_before_interactions_are_allowed = 0, bool monotonic_constraints_ignore_interactions = false,
54-
size_t early_stopping_rounds = 500, size_t num_first_steps_with_linear_effects_only = 0);
56+
size_t early_stopping_rounds = 500, size_t num_first_steps_with_linear_effects_only = 0,
57+
double penalty_for_non_linearity = 0.0, double penalty_for_interactions = 0.0);
5558
APLRClassifier(const APLRClassifier &other);
5659
~APLRClassifier();
5760
void fit(const MatrixXd &X, const std::vector<std::string> &y, const VectorXd &sample_weight = VectorXd(0),
@@ -72,14 +75,16 @@ APLRClassifier::APLRClassifier(size_t m, double v, uint_fast32_t random_state, s
7275
size_t reserved_terms_times_num_x, size_t bins, size_t verbosity, size_t max_interaction_level, size_t max_interactions,
7376
size_t min_observations_in_split, size_t ineligible_boosting_steps_added, size_t max_eligible_terms,
7477
size_t boosting_steps_before_interactions_are_allowed, bool monotonic_constraints_ignore_interactions,
75-
size_t early_stopping_rounds, size_t num_first_steps_with_linear_effects_only)
78+
size_t early_stopping_rounds, size_t num_first_steps_with_linear_effects_only,
79+
double penalty_for_non_linearity, double penalty_for_interactions)
7680
: m{m}, v{v}, random_state{random_state}, n_jobs{n_jobs}, cv_folds{cv_folds},
7781
reserved_terms_times_num_x{reserved_terms_times_num_x}, bins{bins}, verbosity{verbosity}, max_interaction_level{max_interaction_level},
7882
max_interactions{max_interactions}, min_observations_in_split{min_observations_in_split},
7983
ineligible_boosting_steps_added{ineligible_boosting_steps_added}, max_eligible_terms{max_eligible_terms},
8084
boosting_steps_before_interactions_are_allowed{boosting_steps_before_interactions_are_allowed},
8185
monotonic_constraints_ignore_interactions{monotonic_constraints_ignore_interactions}, early_stopping_rounds{early_stopping_rounds},
82-
num_first_steps_with_linear_effects_only{num_first_steps_with_linear_effects_only}
86+
num_first_steps_with_linear_effects_only{num_first_steps_with_linear_effects_only}, penalty_for_non_linearity{penalty_for_non_linearity},
87+
penalty_for_interactions{penalty_for_interactions}
8388
{
8489
}
8590

@@ -94,7 +99,8 @@ APLRClassifier::APLRClassifier(const APLRClassifier &other)
9499
boosting_steps_before_interactions_are_allowed{other.boosting_steps_before_interactions_are_allowed},
95100
monotonic_constraints_ignore_interactions{other.monotonic_constraints_ignore_interactions},
96101
early_stopping_rounds{other.early_stopping_rounds},
97-
num_first_steps_with_linear_effects_only{other.num_first_steps_with_linear_effects_only}
102+
num_first_steps_with_linear_effects_only{other.num_first_steps_with_linear_effects_only},
103+
penalty_for_non_linearity{other.penalty_for_non_linearity}, penalty_for_interactions{other.penalty_for_interactions}
98104
{
99105
}
100106

@@ -121,6 +127,8 @@ void APLRClassifier::fit(const MatrixXd &X, const std::vector<std::string> &y, c
121127
logit_models[categories[0]].monotonic_constraints_ignore_interactions = monotonic_constraints_ignore_interactions;
122128
logit_models[categories[0]].early_stopping_rounds = early_stopping_rounds;
123129
logit_models[categories[0]].num_first_steps_with_linear_effects_only = num_first_steps_with_linear_effects_only;
130+
logit_models[categories[0]].penalty_for_non_linearity = penalty_for_non_linearity;
131+
logit_models[categories[0]].penalty_for_interactions = penalty_for_interactions;
124132
logit_models[categories[0]].fit(X, response_values[categories[0]], sample_weight, X_names, cv_observations, prioritized_predictors_indexes,
125133
monotonic_constraints, VectorXi(0), interaction_constraints);
126134

@@ -138,6 +146,8 @@ void APLRClassifier::fit(const MatrixXd &X, const std::vector<std::string> &y, c
138146
logit_models[category].monotonic_constraints_ignore_interactions = monotonic_constraints_ignore_interactions;
139147
logit_models[category].early_stopping_rounds = early_stopping_rounds;
140148
logit_models[category].num_first_steps_with_linear_effects_only = num_first_steps_with_linear_effects_only;
149+
logit_models[category].penalty_for_non_linearity = penalty_for_non_linearity;
150+
logit_models[category].penalty_for_interactions = penalty_for_interactions;
141151
logit_models[category].fit(X, response_values[category], sample_weight, X_names, cv_observations, prioritized_predictors_indexes,
142152
monotonic_constraints, VectorXi(0), interaction_constraints);
143153
}

cpp/APLRRegressor.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ class APLRRegressor
212212
VectorXi term_interaction_levels;
213213
size_t early_stopping_rounds;
214214
size_t num_first_steps_with_linear_effects_only;
215+
double penalty_for_non_linearity;
216+
double penalty_for_interactions;
215217

216218
APLRRegressor(size_t m = 3000, double v = 0.1, uint_fast32_t random_state = std::numeric_limits<uint_fast32_t>::lowest(), std::string loss_function = "mse",
217219
std::string link_function = "identity", size_t n_jobs = 0, size_t cv_folds = 5,
@@ -225,7 +227,8 @@ class APLRRegressor
225227
const std::function<VectorXd(VectorXd)> &calculate_custom_differentiate_predictions_wrt_linear_predictor_function = {},
226228
size_t boosting_steps_before_interactions_are_allowed = 0, bool monotonic_constraints_ignore_interactions = false,
227229
size_t group_mse_by_prediction_bins = 10, size_t group_mse_cycle_min_obs_in_bin = 30, size_t early_stopping_rounds = 500,
228-
size_t num_first_steps_with_linear_effects_only = 0);
230+
size_t num_first_steps_with_linear_effects_only = 0, double penalty_for_non_linearity = 0.0,
231+
double penalty_for_interactions = 0.0);
229232
APLRRegressor(const APLRRegressor &other);
230233
~APLRRegressor();
231234
void fit(const MatrixXd &X, const VectorXd &y, const VectorXd &sample_weight = VectorXd(0), const std::vector<std::string> &X_names = {},
@@ -266,7 +269,7 @@ APLRRegressor::APLRRegressor(size_t m, double v, uint_fast32_t random_state, std
266269
const std::function<VectorXd(VectorXd)> &calculate_custom_differentiate_predictions_wrt_linear_predictor_function,
267270
size_t boosting_steps_before_interactions_are_allowed, bool monotonic_constraints_ignore_interactions,
268271
size_t group_mse_by_prediction_bins, size_t group_mse_cycle_min_obs_in_bin, size_t early_stopping_rounds,
269-
size_t num_first_steps_with_linear_effects_only)
272+
size_t num_first_steps_with_linear_effects_only, double penalty_for_non_linearity, double penalty_for_interactions)
270273
: reserved_terms_times_num_x{reserved_terms_times_num_x}, intercept{NAN_DOUBLE}, m{m}, v{v},
271274
loss_function{loss_function}, link_function{link_function}, cv_folds{cv_folds}, n_jobs{n_jobs}, random_state{random_state},
272275
bins{bins}, verbosity{verbosity}, max_interaction_level{max_interaction_level},
@@ -281,7 +284,8 @@ APLRRegressor::APLRRegressor(size_t m, double v, uint_fast32_t random_state, std
281284
boosting_steps_before_interactions_are_allowed{boosting_steps_before_interactions_are_allowed},
282285
monotonic_constraints_ignore_interactions{monotonic_constraints_ignore_interactions}, group_mse_by_prediction_bins{group_mse_by_prediction_bins},
283286
group_mse_cycle_min_obs_in_bin{group_mse_cycle_min_obs_in_bin}, cv_error{NAN_DOUBLE}, early_stopping_rounds{early_stopping_rounds},
284-
num_first_steps_with_linear_effects_only{num_first_steps_with_linear_effects_only}
287+
num_first_steps_with_linear_effects_only{num_first_steps_with_linear_effects_only}, penalty_for_non_linearity{penalty_for_non_linearity},
288+
penalty_for_interactions{penalty_for_interactions}
285289
{
286290
}
287291

@@ -307,7 +311,8 @@ APLRRegressor::APLRRegressor(const APLRRegressor &other)
307311
group_mse_cycle_min_obs_in_bin{other.group_mse_cycle_min_obs_in_bin}, cv_error{other.cv_error},
308312
term_main_predictor_indexes{other.term_main_predictor_indexes}, term_interaction_levels{other.term_interaction_levels},
309313
early_stopping_rounds{other.early_stopping_rounds},
310-
num_first_steps_with_linear_effects_only{other.num_first_steps_with_linear_effects_only}
314+
num_first_steps_with_linear_effects_only{other.num_first_steps_with_linear_effects_only},
315+
penalty_for_non_linearity{other.penalty_for_non_linearity}, penalty_for_interactions{other.penalty_for_interactions}
311316
{
312317
}
313318

@@ -1145,7 +1150,7 @@ void APLRRegressor::estimate_split_point_for_each_term(std::vector<Term> &terms,
11451150
for (size_t i = 0; i < terms_indexes.size(); ++i)
11461151
{
11471152
terms[terms_indexes[i]].estimate_split_point(X_train, neg_gradient_current, sample_weight_train, bins, v, min_observations_in_split,
1148-
linear_effects_only_in_this_boosting_step);
1153+
linear_effects_only_in_this_boosting_step, penalty_for_non_linearity, penalty_for_interactions);
11491154
}
11501155
}
11511156

0 commit comments

Comments
 (0)