aplr 10.17.1__cp313-cp313-win_amd64.whl → 10.18.1__cp313-cp313-win_amd64.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 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 APLRRegressor:
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
- X,
385
+ X_transformed,
213
386
  y,
214
387
  sample_weight,
215
- X_names,
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, X: FloatMatrix, cap_predictions_to_minmax_in_training: bool = True
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
- return self.APLRRegressor.predict(X, cap_predictions_to_minmax_in_training)
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, X: FloatMatrix, sample_weight: FloatVector = np.empty(0)
419
+ self,
420
+ X: Union[pd.DataFrame, FloatMatrix],
421
+ sample_weight: FloatVector = np.empty(0),
242
422
  ) -> FloatVector:
243
- return self.APLRRegressor.calculate_feature_importance(X, sample_weight)
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, X: FloatMatrix, sample_weight: FloatVector = np.empty(0)
429
+ self,
430
+ X: Union[pd.DataFrame, FloatMatrix],
431
+ sample_weight: FloatVector = np.empty(0),
247
432
  ) -> FloatVector:
248
- return self.APLRRegressor.calculate_term_importance(X, sample_weight)
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(self, X: FloatMatrix) -> FloatMatrix:
251
- return self.APLRRegressor.calculate_local_feature_contribution(X)
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(self, X: FloatMatrix) -> FloatMatrix:
254
- return self.APLRRegressor.calculate_local_term_contribution(X)
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
- X, predictor_indexes
455
+ X_transformed, predictor_indexes
261
456
  )
262
457
 
263
- def calculate_terms(self, X: FloatMatrix) -> FloatMatrix:
264
- return self.APLRRegressor.calculate_terms(X)
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
- X,
803
+ X_transformed,
590
804
  y,
591
805
  sample_weight,
592
- X_names,
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, X: FloatMatrix, cap_predictions_to_minmax_in_training: bool = False
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
- X, cap_predictions_to_minmax_in_training
826
+ X_transformed, cap_predictions_to_minmax_in_training
610
827
  )
611
828
 
612
829
  def predict(
613
- self, X: FloatMatrix, cap_predictions_to_minmax_in_training: bool = False
830
+ self,
831
+ X: Union[pd.DataFrame, FloatMatrix],
832
+ cap_predictions_to_minmax_in_training: bool = False,
614
833
  ) -> List[str]:
615
- return self.APLRClassifier.predict(X, cap_predictions_to_minmax_in_training)
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(self, X: FloatMatrix) -> FloatMatrix:
618
- return self.APLRClassifier.calculate_local_feature_contribution(X)
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(self, X: FloatMatrix, **kwargs) -> Union[FloatVector, List[str]]:
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(self, X: FloatMatrix, **kwargs) -> FloatMatrix:
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(self, X: FloatMatrix, **kwargs) -> FloatMatrix:
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.cp313-win_amd64.pyd,sha256=sf6nqn9xXvYNdlpsGTqnIX-uMDToOsPqnyKiFjwX5Tc,664576
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=qV0EIPljj1XC_vuSatRWjn02nZIz3N1t8jsZz7HBr2U,101
7
+ aplr-10.18.1.dist-info/top_level.txt,sha256=DXVC0RIFGpzVnPeKWAZTXQdJheOEZL51Wip6Fx7zbR4,14
8
+ aplr-10.18.1.dist-info/RECORD,,
Binary file
@@ -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)
@@ -1,8 +0,0 @@
1
- aplr_cpp.cp313-win_amd64.pyd,sha256=aL0sK0RwjzqObtqhHLkWuSBEF5q1dUmzBN061zo60SQ,664576
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=qV0EIPljj1XC_vuSatRWjn02nZIz3N1t8jsZz7HBr2U,101
7
- aplr-10.17.1.dist-info/top_level.txt,sha256=DXVC0RIFGpzVnPeKWAZTXQdJheOEZL51Wip6Fx7zbR4,14
8
- aplr-10.17.1.dist-info/RECORD,,
File without changes