aplr 10.12.1__cp39-cp39-macosx_11_0_x86_64.whl → 10.14.0__cp39-cp39-macosx_11_0_x86_64.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
@@ -315,6 +315,115 @@ class APLRRegressor:
315
315
  def set_intercept(self, value: float):
316
316
  self.APLRRegressor.set_intercept(value)
317
317
 
318
+ def plot_affiliation_shape(
319
+ self,
320
+ affiliation: str,
321
+ plot: bool = True,
322
+ save: bool = False,
323
+ path: str = "",
324
+ ):
325
+ """
326
+ Plots or saves the shape of a given unique term affiliation.
327
+
328
+ For main effects, it produces a line plot. For two-way interactions, it produces a heatmap.
329
+ Plotting for higher-order interactions is not supported.
330
+
331
+ :param affiliation: A string specifying which unique_term_affiliation to use.
332
+ :param plot: If True, displays the plot.
333
+ :param save: If True, saves the plot to a file.
334
+ :param path: The file path to save the plot. If empty and save is True, a default path will be used.
335
+ """
336
+ try:
337
+ import matplotlib.pyplot as plt
338
+ except ImportError:
339
+ raise ImportError("matplotlib is required for plotting. Please install it.")
340
+
341
+ all_affiliations = self.get_unique_term_affiliations()
342
+ if affiliation not in all_affiliations:
343
+ raise ValueError(
344
+ f"Affiliation '{affiliation}' not found in model. "
345
+ f"Available affiliations are: {all_affiliations}"
346
+ )
347
+
348
+ affiliation_index = all_affiliations.index(affiliation)
349
+
350
+ predictors_in_each_affiliation = (
351
+ self.get_base_predictors_in_each_unique_term_affiliation()
352
+ )
353
+ predictor_indexes_used = predictors_in_each_affiliation[affiliation_index]
354
+
355
+ shape = self.get_unique_term_affiliation_shape(affiliation)
356
+ if shape.shape[0] == 0:
357
+ print(f"No shape data available for affiliation '{affiliation}'.")
358
+ return
359
+
360
+ predictor_names = affiliation.split(" & ")
361
+
362
+ is_main_effect: bool = len(predictor_indexes_used) == 1
363
+ is_two_way_interaction: bool = len(predictor_indexes_used) == 2
364
+
365
+ if is_main_effect:
366
+ fig = plt.figure()
367
+ # Sort by predictor value for a clean line plot
368
+ sorted_indices = np.argsort(shape[:, 0])
369
+ plt.plot(shape[sorted_indices, 0], shape[sorted_indices, 1])
370
+ plt.xlabel(predictor_names[0])
371
+ plt.ylabel("Contribution to linear predictor")
372
+ plt.title(f"Main effect of {predictor_names[0]}")
373
+ plt.grid(True)
374
+ elif is_two_way_interaction:
375
+ fig = plt.figure(figsize=(8, 6))
376
+
377
+ # Get unique coordinates and their inverse mapping
378
+ y_unique, y_inv = np.unique(shape[:, 0], return_inverse=True)
379
+ x_unique, x_inv = np.unique(shape[:, 1], return_inverse=True)
380
+
381
+ # Create grid for sums and counts
382
+ grid_sums = np.zeros((len(y_unique), len(x_unique)))
383
+ grid_counts = np.zeros((len(y_unique), len(x_unique)))
384
+
385
+ # Populate sums and counts to later calculate the mean
386
+ np.add.at(grid_sums, (y_inv, x_inv), shape[:, 2])
387
+ np.add.at(grid_counts, (y_inv, x_inv), 1)
388
+
389
+ # Calculate mean, avoiding division by zero
390
+ with np.errstate(divide="ignore", invalid="ignore"):
391
+ pivot_table_values = np.true_divide(grid_sums, grid_counts)
392
+ # Where there's no data, pivot_table_values will be nan, which is fine for imshow.
393
+
394
+ plt.imshow(
395
+ pivot_table_values,
396
+ aspect="auto",
397
+ origin="lower",
398
+ extent=[
399
+ x_unique.min(),
400
+ x_unique.max(),
401
+ y_unique.min(),
402
+ y_unique.max(),
403
+ ],
404
+ cmap="Blues_r",
405
+ )
406
+ plt.colorbar(label="Contribution to the linear predictor")
407
+ plt.xlabel(predictor_names[1])
408
+ plt.ylabel(predictor_names[0])
409
+ plt.title(
410
+ f"Interaction between {predictor_names[0]} and {predictor_names[1]}"
411
+ )
412
+ else:
413
+ print(
414
+ f"Plotting for interaction level > 2 is not supported. Affiliation: {affiliation}"
415
+ )
416
+ return
417
+
418
+ if save:
419
+ save_path = path or f"shape_of_{affiliation.replace(' & ', '_')}.png"
420
+ plt.savefig(save_path)
421
+
422
+ if plot:
423
+ plt.show()
424
+
425
+ plt.close(fig)
426
+
318
427
  def remove_provided_custom_functions(self):
319
428
  self.APLRRegressor.remove_provided_custom_functions()
320
429
  self.calculate_custom_validation_error_function = None
@@ -504,7 +613,36 @@ class APLRClassifier:
504
613
  return self.APLRClassifier.get_categories()
505
614
 
506
615
  def get_logit_model(self, category: str) -> APLRRegressor:
507
- return self.APLRClassifier.get_logit_model(category)
616
+ logit_model_cpp = self.APLRClassifier.get_logit_model(category)
617
+
618
+ logit_model_py = APLRRegressor(
619
+ m=self.m,
620
+ v=self.v,
621
+ random_state=self.random_state,
622
+ loss_function="binomial",
623
+ link_function="logit",
624
+ n_jobs=self.n_jobs,
625
+ cv_folds=self.cv_folds,
626
+ bins=self.bins,
627
+ max_interaction_level=self.max_interaction_level,
628
+ max_interactions=self.max_interactions,
629
+ min_observations_in_split=self.min_observations_in_split,
630
+ ineligible_boosting_steps_added=self.ineligible_boosting_steps_added,
631
+ max_eligible_terms=self.max_eligible_terms,
632
+ verbosity=self.verbosity,
633
+ boosting_steps_before_interactions_are_allowed=self.boosting_steps_before_interactions_are_allowed,
634
+ monotonic_constraints_ignore_interactions=self.monotonic_constraints_ignore_interactions,
635
+ early_stopping_rounds=self.early_stopping_rounds,
636
+ num_first_steps_with_linear_effects_only=self.num_first_steps_with_linear_effects_only,
637
+ penalty_for_non_linearity=self.penalty_for_non_linearity,
638
+ penalty_for_interactions=self.penalty_for_interactions,
639
+ max_terms=self.max_terms,
640
+ ridge_penalty=self.ridge_penalty,
641
+ )
642
+
643
+ logit_model_py.APLRRegressor = logit_model_cpp
644
+
645
+ return logit_model_py
508
646
 
509
647
  def get_validation_error_steps(self) -> FloatMatrix:
510
648
  return self.APLRClassifier.get_validation_error_steps()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aplr
3
- Version: 10.12.1
3
+ Version: 10.14.0
4
4
  Summary: Automatic Piecewise Linear Regression
5
5
  Home-page: https://github.com/ottenbreit-data-science/aplr
6
6
  Author: Mathias von Ottenbreit
@@ -14,6 +14,8 @@ Requires-Python: >=3.8
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: numpy>=1.11
17
+ Provides-Extra: plots
18
+ Requires-Dist: matplotlib>=3.0; extra == "plots"
17
19
  Dynamic: author
18
20
  Dynamic: author-email
19
21
  Dynamic: classifier
@@ -23,6 +25,7 @@ Dynamic: home-page
23
25
  Dynamic: license
24
26
  Dynamic: license-file
25
27
  Dynamic: platform
28
+ Dynamic: provides-extra
26
29
  Dynamic: requires-dist
27
30
  Dynamic: requires-python
28
31
  Dynamic: summary
@@ -42,6 +45,12 @@ To install APLR, use the following command:
42
45
  pip install aplr
43
46
  ```
44
47
 
48
+ To include dependencies for plotting, use this command instead:
49
+
50
+ ```bash
51
+ pip install aplr[plots]
52
+ ```
53
+
45
54
  ## Availability
46
55
  APLR is available for Windows, most Linux distributions, and macOS.
47
56
 
@@ -0,0 +1,8 @@
1
+ aplr_cpp.cpython-39-darwin.so,sha256=ma1gEx5NiOUp4-tHtv8evNIJgJdJck6wKmeDKm3yut4,1335264
2
+ aplr/__init__.py,sha256=rRfTgNWnYZlFatyA920lWqBcjwmQUI7FcvEPFUTJgzE,20
3
+ aplr/aplr.py,sha256=ZID8qOCi4UoE6sm9vSIUZvX1W1mrRsnzMacSOAhfl4Q,32828
4
+ aplr-10.14.0.dist-info/RECORD,,
5
+ aplr-10.14.0.dist-info/WHEEL,sha256=Bz4joUCrUXLbSisvhJbegejJxGDaJE_s3lwyOhPe_FY,108
6
+ aplr-10.14.0.dist-info/top_level.txt,sha256=DXVC0RIFGpzVnPeKWAZTXQdJheOEZL51Wip6Fx7zbR4,14
7
+ aplr-10.14.0.dist-info/METADATA,sha256=mQHAdFrGE447S4f98ECp8T8VXyY2mPkMRbO8DvPxbWU,2559
8
+ aplr-10.14.0.dist-info/licenses/LICENSE,sha256=g4qcQtkSVPHtGRi3T93DoFCrssvW6ij_emU-2fj_xfY,1113
Binary file
@@ -1,8 +0,0 @@
1
- aplr_cpp.cpython-39-darwin.so,sha256=ZANe0Ity9BnsPfaOFG8HIhJ7XKuBlzXLMii3i45Jyg8,1335264
2
- aplr/__init__.py,sha256=rRfTgNWnYZlFatyA920lWqBcjwmQUI7FcvEPFUTJgzE,20
3
- aplr/aplr.py,sha256=Sgpwe0h22J_B8aZGK1uexgb1MVS_Pq4Ygr7YNj3kE_Q,27090
4
- aplr-10.12.1.dist-info/RECORD,,
5
- aplr-10.12.1.dist-info/WHEEL,sha256=Bz4joUCrUXLbSisvhJbegejJxGDaJE_s3lwyOhPe_FY,108
6
- aplr-10.12.1.dist-info/top_level.txt,sha256=DXVC0RIFGpzVnPeKWAZTXQdJheOEZL51Wip6Fx7zbR4,14
7
- aplr-10.12.1.dist-info/METADATA,sha256=W8PrVP-Gjop24f06L2ml5guAd0bHhP48y7uhIBErFi8,2362
8
- aplr-10.12.1.dist-info/licenses/LICENSE,sha256=g4qcQtkSVPHtGRi3T93DoFCrssvW6ij_emU-2fj_xfY,1113
File without changes