aplr 10.17.1__cp310-cp310-win32.whl → 10.18.1__cp310-cp310-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aplr might be problematic. Click here for more details.
- aplr/aplr.py +264 -33
- aplr-10.18.1.dist-info/METADATA +34 -0
- aplr-10.18.1.dist-info/RECORD +8 -0
- aplr_cpp.cp310-win32.pyd +0 -0
- aplr-10.17.1.dist-info/METADATA +0 -68
- aplr-10.17.1.dist-info/RECORD +0 -8
- {aplr-10.17.1.dist-info → aplr-10.18.1.dist-info}/WHEEL +0 -0
- {aplr-10.17.1.dist-info → aplr-10.18.1.dist-info}/licenses/LICENSE +0 -0
- {aplr-10.17.1.dist-info → aplr-10.18.1.dist-info}/top_level.txt +0 -0
aplr/aplr.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import List, Callable, Optional, Dict, Union
|
|
2
2
|
import numpy as np
|
|
3
|
+
import pandas as pd
|
|
3
4
|
import aplr_cpp
|
|
4
5
|
import itertools
|
|
5
6
|
|
|
@@ -9,7 +10,167 @@ IntVector = np.ndarray
|
|
|
9
10
|
IntMatrix = np.ndarray
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
class
|
|
13
|
+
class BaseAPLR:
|
|
14
|
+
def _validate_X_fit_rows(self, X):
|
|
15
|
+
"""Checks if X has enough rows to be fitted."""
|
|
16
|
+
if (isinstance(X, np.ndarray) and X.shape[0] < 2) or (
|
|
17
|
+
isinstance(X, pd.DataFrame) and len(X) < 2
|
|
18
|
+
):
|
|
19
|
+
raise ValueError("Input X must have at least 2 rows to be fitted.")
|
|
20
|
+
|
|
21
|
+
def _common_X_preprocessing(self, X, is_fitting: bool, X_names=None):
|
|
22
|
+
"""Common preprocessing for fit and predict."""
|
|
23
|
+
is_dataframe_input = isinstance(X, pd.DataFrame)
|
|
24
|
+
|
|
25
|
+
if X_names is not None:
|
|
26
|
+
X_names = list(X_names)
|
|
27
|
+
|
|
28
|
+
if not is_dataframe_input:
|
|
29
|
+
try:
|
|
30
|
+
X_numeric = np.array(X, dtype=np.float64)
|
|
31
|
+
except (ValueError, TypeError) as e:
|
|
32
|
+
raise TypeError(
|
|
33
|
+
"Input X must be numeric if not a pandas DataFrame."
|
|
34
|
+
) from e
|
|
35
|
+
X = pd.DataFrame(X_numeric)
|
|
36
|
+
if is_fitting:
|
|
37
|
+
if X_names:
|
|
38
|
+
X.columns = X_names
|
|
39
|
+
else:
|
|
40
|
+
X.columns = [f"X{i}" for i in range(X.shape[1])]
|
|
41
|
+
elif self.X_names_ and len(self.X_names_) == X.shape[1]:
|
|
42
|
+
X.columns = self.X_names_
|
|
43
|
+
else: # X is already a DataFrame
|
|
44
|
+
X = X.copy() # Always copy to avoid modifying original
|
|
45
|
+
if not is_fitting and self.X_names_:
|
|
46
|
+
# Check if input columns for prediction match training columns (before OHE)
|
|
47
|
+
if set(X.columns) != set(self.X_names_):
|
|
48
|
+
raise ValueError(
|
|
49
|
+
"Input columns for prediction do not match training columns."
|
|
50
|
+
)
|
|
51
|
+
X = X[self.X_names_] # Ensure order of original columns
|
|
52
|
+
|
|
53
|
+
if is_fitting:
|
|
54
|
+
self.X_names_ = list(X.columns)
|
|
55
|
+
self.categorical_features_ = list(
|
|
56
|
+
X.select_dtypes(include=["category", "object"]).columns
|
|
57
|
+
)
|
|
58
|
+
# Ensure it's an empty list if no categorical features, not None
|
|
59
|
+
if not self.categorical_features_:
|
|
60
|
+
self.categorical_features_ = []
|
|
61
|
+
|
|
62
|
+
# Apply OHE if categorical_features_ were found during fitting.
|
|
63
|
+
if self.categorical_features_:
|
|
64
|
+
X = pd.get_dummies(X, columns=self.categorical_features_, dummy_na=False)
|
|
65
|
+
if is_fitting:
|
|
66
|
+
self.ohe_columns_ = list(X.columns)
|
|
67
|
+
# Ensure it's an empty list if no OHE columns, not None
|
|
68
|
+
if not self.ohe_columns_:
|
|
69
|
+
self.ohe_columns_ = []
|
|
70
|
+
else:
|
|
71
|
+
missing_cols = set(self.ohe_columns_) - set(X.columns)
|
|
72
|
+
for c in missing_cols:
|
|
73
|
+
X[c] = 0
|
|
74
|
+
X = X[self.ohe_columns_] # Enforce column order
|
|
75
|
+
|
|
76
|
+
if is_fitting:
|
|
77
|
+
self.na_imputed_cols_ = [col for col in X.columns if X[col].isnull().any()]
|
|
78
|
+
# Ensure it's an empty list if no NA imputed columns, not None
|
|
79
|
+
if not self.na_imputed_cols_:
|
|
80
|
+
self.na_imputed_cols_ = []
|
|
81
|
+
|
|
82
|
+
# Apply NA indicator if na_imputed_cols_ were found during fitting.
|
|
83
|
+
if self.na_imputed_cols_:
|
|
84
|
+
for col in self.na_imputed_cols_:
|
|
85
|
+
X[col + "_missing"] = X[col].isnull().astype(int)
|
|
86
|
+
|
|
87
|
+
if not is_fitting and self.median_values_:
|
|
88
|
+
for col in self.median_values_: # Iterate over keys if it's a dict
|
|
89
|
+
if col in X.columns:
|
|
90
|
+
X[col] = X[col].fillna(self.median_values_[col])
|
|
91
|
+
|
|
92
|
+
return X
|
|
93
|
+
|
|
94
|
+
def _preprocess_X_fit(self, X, X_names, sample_weight):
|
|
95
|
+
if sample_weight.size > 0:
|
|
96
|
+
if sample_weight.ndim != 1:
|
|
97
|
+
raise ValueError("sample_weight must be a 1D array.")
|
|
98
|
+
if len(sample_weight) != X.shape[0]:
|
|
99
|
+
raise ValueError(
|
|
100
|
+
"sample_weight must have the same number of rows as X."
|
|
101
|
+
)
|
|
102
|
+
if np.any(np.isnan(sample_weight)) or np.any(np.isinf(sample_weight)):
|
|
103
|
+
raise ValueError("sample_weight cannot contain nan or infinite values.")
|
|
104
|
+
if np.any(sample_weight < 0):
|
|
105
|
+
raise ValueError("sample_weight cannot contain negative values.")
|
|
106
|
+
X = self._common_X_preprocessing(X, is_fitting=True, X_names=X_names)
|
|
107
|
+
self.median_values_ = {}
|
|
108
|
+
numeric_cols_for_median = [col for col in X.columns if "_missing" not in col]
|
|
109
|
+
for col in numeric_cols_for_median:
|
|
110
|
+
missing_mask = X[col].isnull()
|
|
111
|
+
|
|
112
|
+
if sample_weight.size > 0:
|
|
113
|
+
valid_indices = ~missing_mask
|
|
114
|
+
col_data = X.loc[valid_indices, col]
|
|
115
|
+
col_weights = sample_weight[valid_indices]
|
|
116
|
+
if col_data.empty:
|
|
117
|
+
median_val = 0
|
|
118
|
+
else:
|
|
119
|
+
col_data_np = col_data.to_numpy()
|
|
120
|
+
sort_indices = np.argsort(col_data_np, kind="stable")
|
|
121
|
+
sorted_data = col_data_np[sort_indices]
|
|
122
|
+
sorted_weights = col_weights[sort_indices]
|
|
123
|
+
|
|
124
|
+
cumulative_weights = np.cumsum(sorted_weights)
|
|
125
|
+
total_weight = cumulative_weights[-1]
|
|
126
|
+
|
|
127
|
+
median_weight_index = np.searchsorted(
|
|
128
|
+
cumulative_weights, total_weight / 2.0
|
|
129
|
+
)
|
|
130
|
+
if median_weight_index >= len(sorted_data):
|
|
131
|
+
median_weight_index = len(sorted_data) - 1
|
|
132
|
+
median_val = sorted_data[median_weight_index]
|
|
133
|
+
else:
|
|
134
|
+
median_val = X[col].median()
|
|
135
|
+
|
|
136
|
+
if pd.isna(median_val):
|
|
137
|
+
median_val = 0
|
|
138
|
+
|
|
139
|
+
self.median_values_[col] = median_val
|
|
140
|
+
X[col] = X[col].fillna(median_val)
|
|
141
|
+
|
|
142
|
+
self.final_training_columns_ = list(X.columns)
|
|
143
|
+
return X.values.astype(np.float64), list(X.columns)
|
|
144
|
+
|
|
145
|
+
def _preprocess_X_predict(self, X):
|
|
146
|
+
X = self._common_X_preprocessing(X, is_fitting=False)
|
|
147
|
+
|
|
148
|
+
# Enforce column order from training if it was set.
|
|
149
|
+
if self.final_training_columns_:
|
|
150
|
+
X = X[self.final_training_columns_]
|
|
151
|
+
|
|
152
|
+
return X.values.astype(np.float64)
|
|
153
|
+
|
|
154
|
+
def __setstate__(self, state):
|
|
155
|
+
"""Handles unpickling for backward compatibility."""
|
|
156
|
+
self.__dict__.update(state)
|
|
157
|
+
|
|
158
|
+
# For backward compatibility, initialize new attributes to None if they don't exist,
|
|
159
|
+
# indicating the model was trained before these features were introduced.
|
|
160
|
+
new_attributes = [
|
|
161
|
+
"X_names_",
|
|
162
|
+
"categorical_features_",
|
|
163
|
+
"ohe_columns_",
|
|
164
|
+
"na_imputed_cols_",
|
|
165
|
+
"median_values_",
|
|
166
|
+
"final_training_columns_",
|
|
167
|
+
]
|
|
168
|
+
for attr in new_attributes:
|
|
169
|
+
if not hasattr(self, attr):
|
|
170
|
+
setattr(self, attr, None)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class APLRRegressor(BaseAPLR):
|
|
13
174
|
def __init__(
|
|
14
175
|
self,
|
|
15
176
|
m: int = 3000,
|
|
@@ -127,6 +288,14 @@ class APLRRegressor:
|
|
|
127
288
|
self.mean_bias_correction = mean_bias_correction
|
|
128
289
|
self.faster_convergence = faster_convergence
|
|
129
290
|
|
|
291
|
+
# Data transformations
|
|
292
|
+
self.median_values_ = {}
|
|
293
|
+
self.categorical_features_ = []
|
|
294
|
+
self.ohe_columns_ = []
|
|
295
|
+
self.na_imputed_cols_ = []
|
|
296
|
+
self.X_names_ = []
|
|
297
|
+
self.final_training_columns_ = []
|
|
298
|
+
|
|
130
299
|
# Creating aplr_cpp and setting parameters
|
|
131
300
|
self.APLRRegressor = aplr_cpp.APLRRegressor()
|
|
132
301
|
self.__set_params_cpp()
|
|
@@ -192,7 +361,7 @@ class APLRRegressor:
|
|
|
192
361
|
|
|
193
362
|
def fit(
|
|
194
363
|
self,
|
|
195
|
-
X: FloatMatrix,
|
|
364
|
+
X: Union[pd.DataFrame, FloatMatrix],
|
|
196
365
|
y: FloatVector,
|
|
197
366
|
sample_weight: FloatVector = np.empty(0),
|
|
198
367
|
X_names: List[str] = [],
|
|
@@ -207,12 +376,16 @@ class APLRRegressor:
|
|
|
207
376
|
predictor_penalties_for_interactions: List[float] = [],
|
|
208
377
|
predictor_min_observations_in_split: List[int] = [],
|
|
209
378
|
):
|
|
379
|
+
self._validate_X_fit_rows(X)
|
|
210
380
|
self.__set_params_cpp()
|
|
381
|
+
X_transformed, X_names_transformed = self._preprocess_X_fit(
|
|
382
|
+
X, X_names, sample_weight
|
|
383
|
+
)
|
|
211
384
|
self.APLRRegressor.fit(
|
|
212
|
-
|
|
385
|
+
X_transformed,
|
|
213
386
|
y,
|
|
214
387
|
sample_weight,
|
|
215
|
-
|
|
388
|
+
X_names_transformed,
|
|
216
389
|
cv_observations,
|
|
217
390
|
prioritized_predictors_indexes,
|
|
218
391
|
monotonic_constraints,
|
|
@@ -226,42 +399,65 @@ class APLRRegressor:
|
|
|
226
399
|
)
|
|
227
400
|
|
|
228
401
|
def predict(
|
|
229
|
-
self,
|
|
402
|
+
self,
|
|
403
|
+
X: Union[pd.DataFrame, FloatMatrix],
|
|
404
|
+
cap_predictions_to_minmax_in_training: bool = True,
|
|
230
405
|
) -> FloatVector:
|
|
231
406
|
if self.link_function == "custom_function":
|
|
232
407
|
self.APLRRegressor.calculate_custom_transform_linear_predictor_to_predictions_function = (
|
|
233
408
|
self.calculate_custom_transform_linear_predictor_to_predictions_function
|
|
234
409
|
)
|
|
235
|
-
|
|
410
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
411
|
+
return self.APLRRegressor.predict(
|
|
412
|
+
X_transformed, cap_predictions_to_minmax_in_training
|
|
413
|
+
)
|
|
236
414
|
|
|
237
415
|
def set_term_names(self, X_names: List[str]):
|
|
238
416
|
self.APLRRegressor.set_term_names(X_names)
|
|
239
417
|
|
|
240
418
|
def calculate_feature_importance(
|
|
241
|
-
self,
|
|
419
|
+
self,
|
|
420
|
+
X: Union[pd.DataFrame, FloatMatrix],
|
|
421
|
+
sample_weight: FloatVector = np.empty(0),
|
|
242
422
|
) -> FloatVector:
|
|
243
|
-
|
|
423
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
424
|
+
return self.APLRRegressor.calculate_feature_importance(
|
|
425
|
+
X_transformed, sample_weight
|
|
426
|
+
)
|
|
244
427
|
|
|
245
428
|
def calculate_term_importance(
|
|
246
|
-
self,
|
|
429
|
+
self,
|
|
430
|
+
X: Union[pd.DataFrame, FloatMatrix],
|
|
431
|
+
sample_weight: FloatVector = np.empty(0),
|
|
247
432
|
) -> FloatVector:
|
|
248
|
-
|
|
433
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
434
|
+
return self.APLRRegressor.calculate_term_importance(
|
|
435
|
+
X_transformed, sample_weight
|
|
436
|
+
)
|
|
249
437
|
|
|
250
|
-
def calculate_local_feature_contribution(
|
|
251
|
-
|
|
438
|
+
def calculate_local_feature_contribution(
|
|
439
|
+
self, X: Union[pd.DataFrame, FloatMatrix]
|
|
440
|
+
) -> FloatMatrix:
|
|
441
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
442
|
+
return self.APLRRegressor.calculate_local_feature_contribution(X_transformed)
|
|
252
443
|
|
|
253
|
-
def calculate_local_term_contribution(
|
|
254
|
-
|
|
444
|
+
def calculate_local_term_contribution(
|
|
445
|
+
self, X: Union[pd.DataFrame, FloatMatrix]
|
|
446
|
+
) -> FloatMatrix:
|
|
447
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
448
|
+
return self.APLRRegressor.calculate_local_term_contribution(X_transformed)
|
|
255
449
|
|
|
256
450
|
def calculate_local_contribution_from_selected_terms(
|
|
257
|
-
self, X: FloatMatrix, predictor_indexes: List[int]
|
|
451
|
+
self, X: Union[pd.DataFrame, FloatMatrix], predictor_indexes: List[int]
|
|
258
452
|
) -> FloatVector:
|
|
453
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
259
454
|
return self.APLRRegressor.calculate_local_contribution_from_selected_terms(
|
|
260
|
-
|
|
455
|
+
X_transformed, predictor_indexes
|
|
261
456
|
)
|
|
262
457
|
|
|
263
|
-
def calculate_terms(self, X: FloatMatrix) -> FloatMatrix:
|
|
264
|
-
|
|
458
|
+
def calculate_terms(self, X: Union[pd.DataFrame, FloatMatrix]) -> FloatMatrix:
|
|
459
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
460
|
+
return self.APLRRegressor.calculate_terms(X_transformed)
|
|
265
461
|
|
|
266
462
|
def get_term_names(self) -> List[str]:
|
|
267
463
|
return self.APLRRegressor.get_term_names()
|
|
@@ -483,7 +679,7 @@ class APLRRegressor:
|
|
|
483
679
|
return self
|
|
484
680
|
|
|
485
681
|
|
|
486
|
-
class APLRClassifier:
|
|
682
|
+
class APLRClassifier(BaseAPLR):
|
|
487
683
|
def __init__(
|
|
488
684
|
self,
|
|
489
685
|
m: int = 3000,
|
|
@@ -534,6 +730,14 @@ class APLRClassifier:
|
|
|
534
730
|
self.max_terms = max_terms
|
|
535
731
|
self.ridge_penalty = ridge_penalty
|
|
536
732
|
|
|
733
|
+
# Data transformations
|
|
734
|
+
self.median_values_ = {}
|
|
735
|
+
self.categorical_features_ = []
|
|
736
|
+
self.ohe_columns_ = []
|
|
737
|
+
self.na_imputed_cols_ = []
|
|
738
|
+
self.X_names_ = []
|
|
739
|
+
self.final_training_columns_ = []
|
|
740
|
+
|
|
537
741
|
# Creating aplr_cpp and setting parameters
|
|
538
742
|
self.APLRClassifier = aplr_cpp.APLRClassifier()
|
|
539
743
|
self.__set_params_cpp()
|
|
@@ -571,8 +775,8 @@ class APLRClassifier:
|
|
|
571
775
|
|
|
572
776
|
def fit(
|
|
573
777
|
self,
|
|
574
|
-
X: FloatMatrix,
|
|
575
|
-
y: List[str],
|
|
778
|
+
X: Union[pd.DataFrame, FloatMatrix],
|
|
779
|
+
y: Union[FloatVector, List[str]],
|
|
576
780
|
sample_weight: FloatVector = np.empty(0),
|
|
577
781
|
X_names: List[str] = [],
|
|
578
782
|
cv_observations: IntMatrix = np.empty([0, 0]),
|
|
@@ -584,12 +788,22 @@ class APLRClassifier:
|
|
|
584
788
|
predictor_penalties_for_interactions: List[float] = [],
|
|
585
789
|
predictor_min_observations_in_split: List[int] = [],
|
|
586
790
|
):
|
|
791
|
+
self._validate_X_fit_rows(X)
|
|
587
792
|
self.__set_params_cpp()
|
|
793
|
+
X_transformed, X_names_transformed = self._preprocess_X_fit(
|
|
794
|
+
X, X_names, sample_weight
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
if isinstance(y, np.ndarray):
|
|
798
|
+
y = y.astype(str).tolist()
|
|
799
|
+
elif isinstance(y, list) and y and not isinstance(y[0], str):
|
|
800
|
+
y = [str(val) for val in y]
|
|
801
|
+
|
|
588
802
|
self.APLRClassifier.fit(
|
|
589
|
-
|
|
803
|
+
X_transformed,
|
|
590
804
|
y,
|
|
591
805
|
sample_weight,
|
|
592
|
-
|
|
806
|
+
X_names_transformed,
|
|
593
807
|
cv_observations,
|
|
594
808
|
prioritized_predictors_indexes,
|
|
595
809
|
monotonic_constraints,
|
|
@@ -603,19 +817,30 @@ class APLRClassifier:
|
|
|
603
817
|
self.classes_ = np.arange(len(self.APLRClassifier.get_categories()))
|
|
604
818
|
|
|
605
819
|
def predict_class_probabilities(
|
|
606
|
-
self,
|
|
820
|
+
self,
|
|
821
|
+
X: Union[pd.DataFrame, FloatMatrix],
|
|
822
|
+
cap_predictions_to_minmax_in_training: bool = False,
|
|
607
823
|
) -> FloatMatrix:
|
|
824
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
608
825
|
return self.APLRClassifier.predict_class_probabilities(
|
|
609
|
-
|
|
826
|
+
X_transformed, cap_predictions_to_minmax_in_training
|
|
610
827
|
)
|
|
611
828
|
|
|
612
829
|
def predict(
|
|
613
|
-
self,
|
|
830
|
+
self,
|
|
831
|
+
X: Union[pd.DataFrame, FloatMatrix],
|
|
832
|
+
cap_predictions_to_minmax_in_training: bool = False,
|
|
614
833
|
) -> List[str]:
|
|
615
|
-
|
|
834
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
835
|
+
return self.APLRClassifier.predict(
|
|
836
|
+
X_transformed, cap_predictions_to_minmax_in_training
|
|
837
|
+
)
|
|
616
838
|
|
|
617
|
-
def calculate_local_feature_contribution(
|
|
618
|
-
|
|
839
|
+
def calculate_local_feature_contribution(
|
|
840
|
+
self, X: Union[pd.DataFrame, FloatMatrix]
|
|
841
|
+
) -> FloatMatrix:
|
|
842
|
+
X_transformed = self._preprocess_X_predict(X)
|
|
843
|
+
return self.APLRClassifier.calculate_local_feature_contribution(X_transformed)
|
|
619
844
|
|
|
620
845
|
def get_categories(self) -> List[str]:
|
|
621
846
|
return self.APLRClassifier.get_categories()
|
|
@@ -724,7 +949,7 @@ class APLRTuner:
|
|
|
724
949
|
grid = [dict(zip(keys, combination)) for combination in combinations]
|
|
725
950
|
return grid
|
|
726
951
|
|
|
727
|
-
def fit(self, X: FloatMatrix, y: FloatVector, **kwargs):
|
|
952
|
+
def fit(self, X: Union[pd.DataFrame, FloatMatrix], y: FloatVector, **kwargs):
|
|
728
953
|
self.cv_results: List[Dict[str, float]] = []
|
|
729
954
|
best_validation_result = np.inf
|
|
730
955
|
for params in self.parameter_grid:
|
|
@@ -742,10 +967,14 @@ class APLRTuner:
|
|
|
742
967
|
self.best_model = model
|
|
743
968
|
self.cv_results = sorted(self.cv_results, key=lambda x: x["cv_error"])
|
|
744
969
|
|
|
745
|
-
def predict(
|
|
970
|
+
def predict(
|
|
971
|
+
self, X: Union[pd.DataFrame, FloatMatrix], **kwargs
|
|
972
|
+
) -> Union[FloatVector, List[str]]:
|
|
746
973
|
return self.best_model.predict(X, **kwargs)
|
|
747
974
|
|
|
748
|
-
def predict_class_probabilities(
|
|
975
|
+
def predict_class_probabilities(
|
|
976
|
+
self, X: Union[pd.DataFrame, FloatMatrix], **kwargs
|
|
977
|
+
) -> FloatMatrix:
|
|
749
978
|
if self.is_regressor == False:
|
|
750
979
|
return self.best_model.predict_class_probabilities(X, **kwargs)
|
|
751
980
|
else:
|
|
@@ -753,7 +982,9 @@ class APLRTuner:
|
|
|
753
982
|
"predict_class_probabilities is only possible when is_regressor is False"
|
|
754
983
|
)
|
|
755
984
|
|
|
756
|
-
def predict_proba(
|
|
985
|
+
def predict_proba(
|
|
986
|
+
self, X: Union[pd.DataFrame, FloatMatrix], **kwargs
|
|
987
|
+
) -> FloatMatrix:
|
|
757
988
|
return self.predict_class_probabilities(X, **kwargs)
|
|
758
989
|
|
|
759
990
|
def get_best_estimator(self) -> Union[APLRClassifier, APLRRegressor]:
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aplr
|
|
3
|
+
Version: 10.18.1
|
|
4
|
+
Summary: Automatic Piecewise Linear Regression
|
|
5
|
+
Home-page: https://github.com/ottenbreit-data-science/aplr
|
|
6
|
+
Author: Mathias von Ottenbreit
|
|
7
|
+
Author-email: ottenbreitdatascience@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Platform: Windows
|
|
10
|
+
Platform: Linux
|
|
11
|
+
Platform: MacOS
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: numpy>=1.11
|
|
17
|
+
Requires-Dist: pandas>=1.0.0
|
|
18
|
+
Provides-Extra: plots
|
|
19
|
+
Requires-Dist: matplotlib>=3.0; extra == "plots"
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: platform
|
|
29
|
+
Dynamic: provides-extra
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
The documentation for Automatic Piecewise Linear Regression is available at [https://github.com/ottenbreit-data-science/aplr](https://github.com/ottenbreit-data-science/aplr).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
aplr_cpp.cp310-win32.pyd,sha256=rmLQxuwwX35W_v6uEoYl4PnnwAre5K4-VCIkVkmW1TQ,596992
|
|
2
|
+
aplr/__init__.py,sha256=oDFSgVytP_qQ8ilun6oHxKr-DYEeqjEQp5FciX45lls,21
|
|
3
|
+
aplr/aplr.py,sha256=YOXF2a5CpC6kYoLGaDOaYIXMSRrWtSwvrbxpjYzPyA0,42653
|
|
4
|
+
aplr-10.18.1.dist-info/licenses/LICENSE,sha256=YOMo-RaL4P7edMZGD96-NskKpxyMZdP3-WiiMMmihNk,1134
|
|
5
|
+
aplr-10.18.1.dist-info/METADATA,sha256=lj9HjkVuCgcD7cKxWOpRMXrocW4r-Zzpa4HQm3UkdkA,1048
|
|
6
|
+
aplr-10.18.1.dist-info/WHEEL,sha256=GWZF0cboiU4MhsG0baPl8rrtCaXFSLW25384gp3vddM,97
|
|
7
|
+
aplr-10.18.1.dist-info/top_level.txt,sha256=DXVC0RIFGpzVnPeKWAZTXQdJheOEZL51Wip6Fx7zbR4,14
|
|
8
|
+
aplr-10.18.1.dist-info/RECORD,,
|
aplr_cpp.cp310-win32.pyd
CHANGED
|
Binary file
|
aplr-10.17.1.dist-info/METADATA
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: aplr
|
|
3
|
-
Version: 10.17.1
|
|
4
|
-
Summary: Automatic Piecewise Linear Regression
|
|
5
|
-
Home-page: https://github.com/ottenbreit-data-science/aplr
|
|
6
|
-
Author: Mathias von Ottenbreit
|
|
7
|
-
Author-email: ottenbreitdatascience@gmail.com
|
|
8
|
-
License: MIT
|
|
9
|
-
Platform: Windows
|
|
10
|
-
Platform: Linux
|
|
11
|
-
Platform: MacOS
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Requires-Python: >=3.8
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist: numpy>=1.11
|
|
17
|
-
Provides-Extra: plots
|
|
18
|
-
Requires-Dist: matplotlib>=3.0; extra == "plots"
|
|
19
|
-
Dynamic: author
|
|
20
|
-
Dynamic: author-email
|
|
21
|
-
Dynamic: classifier
|
|
22
|
-
Dynamic: description
|
|
23
|
-
Dynamic: description-content-type
|
|
24
|
-
Dynamic: home-page
|
|
25
|
-
Dynamic: license
|
|
26
|
-
Dynamic: license-file
|
|
27
|
-
Dynamic: platform
|
|
28
|
-
Dynamic: provides-extra
|
|
29
|
-
Dynamic: requires-dist
|
|
30
|
-
Dynamic: requires-python
|
|
31
|
-
Dynamic: summary
|
|
32
|
-
|
|
33
|
-
# APLR
|
|
34
|
-
**Automatic Piecewise Linear Regression**
|
|
35
|
-
|
|
36
|
-
## About
|
|
37
|
-
APLR allows you to build predictive and interpretable regression or classification machine learning models in Python, using the Automatic Piecewise Linear Regression (APLR) methodology developed by Mathias von Ottenbreit. APLR often rivals tree-based methods in predictive accuracy, while offering smoother, more interpretable predictions.
|
|
38
|
-
|
|
39
|
-
For further details, see the [documentation](https://github.com/ottenbreit-data-science/aplr/tree/main/documentation). You may also read the published article for additional insights: [Link 1](https://link.springer.com/article/10.1007/s00180-024-01475-4) and [Link 2](https://rdcu.be/dz7bF). Additional functionality has been added since the article was published.
|
|
40
|
-
|
|
41
|
-
## Installation
|
|
42
|
-
To install APLR, use the following command:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
pip install aplr
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
To include dependencies for plotting, use this command instead:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
pip install aplr[plots]
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Availability
|
|
55
|
-
APLR is available for Windows, most Linux distributions, and macOS.
|
|
56
|
-
|
|
57
|
-
## Usage
|
|
58
|
-
Example Python scripts are available [here](https://github.com/ottenbreit-data-science/aplr/tree/main/examples).
|
|
59
|
-
|
|
60
|
-
## Sponsorship
|
|
61
|
-
Consider sponsoring Von Ottenbreit Data Science by clicking the **Sponsor** button on the repository. Sufficient funding will help maintain and further develop APLR.
|
|
62
|
-
|
|
63
|
-
## API Reference
|
|
64
|
-
- [API reference for regression](https://github.com/ottenbreit-data-science/aplr/blob/main/API_REFERENCE_FOR_REGRESSION.md)
|
|
65
|
-
- [API reference for classification](https://github.com/ottenbreit-data-science/aplr/blob/main/API_REFERENCE_FOR_CLASSIFICATION.md)
|
|
66
|
-
|
|
67
|
-
## Contact Information
|
|
68
|
-
For inquiries, please email: [ottenbreitdatascience@gmail.com](mailto:ottenbreitdatascience@gmail.com)
|
aplr-10.17.1.dist-info/RECORD
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
aplr_cpp.cp310-win32.pyd,sha256=c_nkUTh9KaMBtfBuC22-JDGfEx3LMpvPd9qUr2l0ZaY,596480
|
|
2
|
-
aplr/__init__.py,sha256=oDFSgVytP_qQ8ilun6oHxKr-DYEeqjEQp5FciX45lls,21
|
|
3
|
-
aplr/aplr.py,sha256=obmpNNppOrnzQxhYzShYzNe02lQv17-YRWUklf8IXds,33302
|
|
4
|
-
aplr-10.17.1.dist-info/licenses/LICENSE,sha256=YOMo-RaL4P7edMZGD96-NskKpxyMZdP3-WiiMMmihNk,1134
|
|
5
|
-
aplr-10.17.1.dist-info/METADATA,sha256=crEeFMmcUldMHf6eZnAi2zAbnQIWcQBOLKZeVZdej58,2627
|
|
6
|
-
aplr-10.17.1.dist-info/WHEEL,sha256=GWZF0cboiU4MhsG0baPl8rrtCaXFSLW25384gp3vddM,97
|
|
7
|
-
aplr-10.17.1.dist-info/top_level.txt,sha256=DXVC0RIFGpzVnPeKWAZTXQdJheOEZL51Wip6Fx7zbR4,14
|
|
8
|
-
aplr-10.17.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|