Skip to content

Commit 9a8290e

Browse files
added get_coefficient_shape_function, different option regarding monotonicity
1 parent 9a9042f commit 9a8290e

13 files changed

+320
-32
lines changed

API_REFERENCE_FOR_CLASSIFICATION.md

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

3-
## class aplr.APLRClassifier(m:int=9000, v:float=0.1, random_state:int=0, n_jobs:int=0, validation_ratio:float=0.2, 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_pruning_is_done:int = 0, boosting_steps_before_interactions_are_allowed: int = 0)
3+
## class aplr.APLRClassifier(m:int=9000, v:float=0.1, random_state:int=0, n_jobs:int=0, validation_ratio:float=0.2, 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_pruning_is_done:int = 0, boosting_steps_before_interactions_are_allowed: int = 0, monotonic_constraints_ignore_interactions: bool = False)
44

55
### Constructor parameters
66

@@ -46,6 +46,9 @@ Specifies how many boosting steps to wait before pruning the model. If 0 (defaul
4646
#### boosting_steps_before_interactions_are_allowed (default = 0)
4747
Specifies how many boosting steps to wait before searching for interactions. If for example 800, then the algorithm will be forced to only fit main effects in the first 800 boosting steps, after which it is allowed to search for interactions (given that other hyperparameters that control interactions also allow this). The motivation for fitting main effects first may be 1) to get a cleaner looking model that puts more emphasis on main effects and 2) to speed up the algorithm since looking for interactions is computationally more demanding.
4848

49+
#### monotonic_constraints_ignore_interactions (default = False)
50+
See ***monotonic_constraints*** in the ***fit*** method.
51+
4952

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

@@ -72,7 +75,7 @@ An optional list of integers specifying the indexes of observations to be used f
7275
An optional list of integers specifying the indexes of predictors (columns) in ***X*** that should be prioritized. Terms of the prioritized predictors will enter the model as long as they reduce the training error and do not contain too few effective observations. They will also be updated more often.
7376

7477
#### monotonic_constraints
75-
An optional list of integers specifying monotonic constraints on model terms. For example, if there are three predictors in ***X***, then monotonic_constraints = [1,0,-1] means that 1) the first predictor in ***X*** cannot be used in interaction terms as a secondary effect and all terms using the first predictor in ***X*** as a main effect must have positive regression coefficients, 2) there are no monotonic constraints on terms using the second predictor in ***X***, and 3) the third predictor in ***X*** cannot be used in interaction terms as a secondary effect and all terms using the third predictor in ***X*** as a main effect must have negative regression coefficients.
78+
An optional list of integers specifying monotonic constraints on model terms. For example, if there are three predictors in ***X***, then monotonic_constraints = [1,0,-1] means that 1) all terms using the first predictor in ***X*** as a main effect must have positive regression coefficients, 2) there are no monotonic constraints on terms using the second predictor in ***X***, and 3) all terms using the third predictor in ***X*** as a main effect must have negative regression coefficients. In the above example, if ***monotonic_constraints_ignore_interactions*** is ***False*** (default) then the first and the third predictors in ***X*** cannot be used in interaction terms as secondary effects. The latter guarantees monotonicity but can degrade predictiveness especially if a large proportion of predictors have monotonic constraints (in this case significantly fewer interaction terms can be formed).
7679

7780
#### interaction_constraints
7881
An optional list containing lists of integers. Specifies interaction constraints on model terms. For example, interaction_constraints = [[0,1], [1,2,3]] means that 1) the first and second predictors may interact with each other, and that 2) the second, third and fourth predictors may interact with each other. There are no interaction constraints on predictors not mentioned in interaction_constraints.

API_REFERENCE_FOR_REGRESSION.md

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

3-
## class aplr.APLRRegressor(m:int=1000, v:float=0.1, random_state:int=0, loss_function:str="mse", link_function:str="identity", n_jobs:int=0, validation_ratio:float=0.2, 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_pruning_is_done: int = 0, boosting_steps_before_interactions_are_allowed: int = 0)
3+
## class aplr.APLRRegressor(m:int=1000, v:float=0.1, random_state:int=0, loss_function:str="mse", link_function:str="identity", n_jobs:int=0, validation_ratio:float=0.2, 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_pruning_is_done: int = 0, boosting_steps_before_interactions_are_allowed: int = 0, monotonic_constraints_ignore_interactions: bool = False)
44

55
### Constructor parameters
66

@@ -108,6 +108,9 @@ Specifies how many boosting steps to wait before pruning the model. If 0 (defaul
108108
#### boosting_steps_before_interactions_are_allowed (default = 0)
109109
Specifies how many boosting steps to wait before searching for interactions. If for example 800, then the algorithm will be forced to only fit main effects in the first 800 boosting steps, after which it is allowed to search for interactions (given that other hyperparameters that control interactions also allow this). The motivation for fitting main effects first may be 1) to get a cleaner looking model that puts more emphasis on main effects and 2) to speed up the algorithm since looking for interactions is computationally more demanding.
110110

111+
#### monotonic_constraints_ignore_interactions (default = False)
112+
See ***monotonic_constraints*** in the ***fit*** method.
113+
111114
## Method: fit(X:npt.ArrayLike, y:npt.ArrayLike, sample_weight:npt.ArrayLike = np.empty(0), X_names:List[str]=[], validation_set_indexes:List[int]=[], 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]))
112115

113116
***This method fits the model to data.***
@@ -133,7 +136,7 @@ An optional list of integers specifying the indexes of observations to be used f
133136
An optional list of integers specifying the indexes of predictors (columns) in ***X*** that should be prioritized. Terms of the prioritized predictors will enter the model as long as they reduce the training error and do not contain too few effective observations. They will also be updated more often.
134137

135138
#### monotonic_constraints
136-
An optional list of integers specifying monotonic constraints on model terms. For example, if there are three predictors in ***X***, then monotonic_constraints = [1,0,-1] means that 1) the first predictor in ***X*** cannot be used in interaction terms as a secondary effect and all terms using the first predictor in ***X*** as a main effect must have positive regression coefficients, 2) there are no monotonic constraints on terms using the second predictor in ***X***, and 3) the third predictor in ***X*** cannot be used in interaction terms as a secondary effect and all terms using the third predictor in ***X*** as a main effect must have negative regression coefficients.
139+
An optional list of integers specifying monotonic constraints on model terms. For example, if there are three predictors in ***X***, then monotonic_constraints = [1,0,-1] means that 1) all terms using the first predictor in ***X*** as a main effect must have positive regression coefficients, 2) there are no monotonic constraints on terms using the second predictor in ***X***, and 3) all terms using the third predictor in ***X*** as a main effect must have negative regression coefficients. In the above example, if ***monotonic_constraints_ignore_interactions*** is ***False*** (default) then the first and the third predictors in ***X*** cannot be used in interaction terms as secondary effects. The latter guarantees monotonicity but can degrade predictiveness especially if a large proportion of predictors have monotonic constraints (in this case significantly fewer interaction terms can be formed).
137140

138141
#### group
139142
A numpy vector of integers that is used when ***loss_function*** is "group_mse". For example, ***group*** may represent year (could be useful in a time series model).
@@ -249,4 +252,13 @@ The index of the term selected. So ***0*** is the first term, ***1*** is the sec
249252

250253
## Method: get_validation_indexes()
251254

252-
***Returns a list of integers containing the indexes of the training data observations used for validation and not training.***
255+
***Returns a list of integers containing the indexes of the training data observations used for validation and not training.***
256+
257+
## Method: get_coefficient_shape_function(predictor_index:int)
258+
259+
***For the predictor in X specified by predictor_index, get_coefficient_shape_function returns a dictionary with keys equal to predictor values and values equal to coefficient. For each predictor value, the coefficient is the sum of coefficients for relevant terms using only the predictor (interactions with other predictors are ignored). This function makes it easier to interpret APLR models as one can quickly see how the main effects work across relevant values of the predictor. If the predictor is only used as a linear effect in the model then the predictor value is set to 0 even though the coefficient is valid for all values of the predictor.***
260+
261+
### Parameters
262+
263+
#### predictor_index
264+
The index of the predictor. So if ***predictor_index*** is ***1*** then the second predictor in ***X*** is used.

aplr/aplr.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import numpy as np
22
import numpy.typing as npt
3-
from typing import List, Callable, Optional
3+
from typing import List, Callable, Optional, Dict
44
import aplr_cpp
55

66

@@ -62,6 +62,7 @@ def __init__(
6262
] = None,
6363
boosting_steps_before_pruning_is_done: int = 0,
6464
boosting_steps_before_interactions_are_allowed: int = 0,
65+
monotonic_constraints_ignore_interactions: bool = False,
6566
):
6667
self.m = m
6768
self.v = v
@@ -99,6 +100,9 @@ def __init__(
99100
self.boosting_steps_before_interactions_are_allowed = (
100101
boosting_steps_before_interactions_are_allowed
101102
)
103+
self.monotonic_constraints_ignore_interactions = (
104+
monotonic_constraints_ignore_interactions
105+
)
102106

103107
# Creating aplr_cpp and setting parameters
104108
self.APLRRegressor = aplr_cpp.APLRRegressor()
@@ -146,6 +150,9 @@ def __set_params_cpp(self):
146150
self.APLRRegressor.boosting_steps_before_interactions_are_allowed = (
147151
self.boosting_steps_before_interactions_are_allowed
148152
)
153+
self.APLRRegressor.monotonic_constraints_ignore_interactions = (
154+
self.monotonic_constraints_ignore_interactions
155+
)
149156

150157
def fit(
151158
self,
@@ -227,6 +234,11 @@ def get_validation_tuning_metric(self) -> str:
227234
def get_validation_indexes(self) -> List[int]:
228235
return self.APLRRegressor.get_validation_indexes()
229236

237+
def get_coefficient_shape_function(
238+
self, predictor_index: int
239+
) -> Dict[float, float]:
240+
return self.APLRRegressor.get_coefficient_shape_function(predictor_index)
241+
230242
# For sklearn
231243
def get_params(self, deep=True):
232244
return {
@@ -254,6 +266,7 @@ def get_params(self, deep=True):
254266
"calculate_custom_differentiate_predictions_wrt_linear_predictor_function": self.calculate_custom_differentiate_predictions_wrt_linear_predictor_function,
255267
"boosting_steps_before_pruning_is_done": self.boosting_steps_before_pruning_is_done,
256268
"boosting_steps_before_interactions_are_allowed": self.boosting_steps_before_interactions_are_allowed,
269+
"monotonic_constraints_ignore_interactions": self.monotonic_constraints_ignore_interactions,
257270
}
258271

259272
# For sklearn
@@ -281,6 +294,7 @@ def __init__(
281294
max_eligible_terms: int = 5,
282295
boosting_steps_before_pruning_is_done: int = 0,
283296
boosting_steps_before_interactions_are_allowed: int = 0,
297+
monotonic_constraints_ignore_interactions: bool = False,
284298
):
285299
self.m = m
286300
self.v = v
@@ -300,6 +314,9 @@ def __init__(
300314
self.boosting_steps_before_interactions_are_allowed = (
301315
boosting_steps_before_interactions_are_allowed
302316
)
317+
self.monotonic_constraints_ignore_interactions = (
318+
monotonic_constraints_ignore_interactions
319+
)
303320

304321
# Creating aplr_cpp and setting parameters
305322
self.APLRClassifier = aplr_cpp.APLRClassifier()
@@ -327,6 +344,9 @@ def __set_params_cpp(self):
327344
self.APLRClassifier.boosting_steps_before_interactions_are_allowed = (
328345
self.boosting_steps_before_interactions_are_allowed
329346
)
347+
self.APLRClassifier.monotonic_constraints_ignore_interactions = (
348+
self.monotonic_constraints_ignore_interactions
349+
)
330350

331351
def fit(
332352
self,
@@ -401,6 +421,7 @@ def get_params(self, deep=True):
401421
"max_eligible_terms": self.max_eligible_terms,
402422
"boosting_steps_before_pruning_is_done": self.boosting_steps_before_pruning_is_done,
403423
"boosting_steps_before_interactions_are_allowed": self.boosting_steps_before_interactions_are_allowed,
424+
"monotonic_constraints_ignore_interactions": self.monotonic_constraints_ignore_interactions,
404425
}
405426

406427
# For sklearn

0 commit comments

Comments
 (0)