superglm 0.12.0__tar.gz

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.
Files changed (212) hide show
  1. superglm-0.12.0/.gitignore +73 -0
  2. superglm-0.12.0/LICENSE +21 -0
  3. superglm-0.12.0/PKG-INFO +345 -0
  4. superglm-0.12.0/README.md +295 -0
  5. superglm-0.12.0/pyproject.toml +150 -0
  6. superglm-0.12.0/src/superglm/__init__.py +227 -0
  7. superglm-0.12.0/src/superglm/_debug.py +18 -0
  8. superglm-0.12.0/src/superglm/_fit_trace.py +296 -0
  9. superglm-0.12.0/src/superglm/_group_matrix/__init__.py +1 -0
  10. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_algebra.py +1025 -0
  11. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_bin_space.py +374 -0
  12. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_bins.py +28 -0
  13. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_centered.py +990 -0
  14. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_core.py +288 -0
  15. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_discretized.py +429 -0
  16. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_execution.py +415 -0
  17. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_kernels.py +172 -0
  18. superglm-0.12.0/src/superglm/_group_matrix/_group_matrix_tabmat.py +286 -0
  19. superglm-0.12.0/src/superglm/_tweedie_profile_kernel.py +491 -0
  20. superglm-0.12.0/src/superglm/_tweedie_series.py +207 -0
  21. superglm-0.12.0/src/superglm/_utils.py +46 -0
  22. superglm-0.12.0/src/superglm/constraints.py +659 -0
  23. superglm-0.12.0/src/superglm/debug_weights.py +272 -0
  24. superglm-0.12.0/src/superglm/diagnostics/__init__.py +27 -0
  25. superglm-0.12.0/src/superglm/diagnostics/discretize.py +288 -0
  26. superglm-0.12.0/src/superglm/diagnostics/spline_checks.py +108 -0
  27. superglm-0.12.0/src/superglm/diagnostics/term_diagnostics.py +226 -0
  28. superglm-0.12.0/src/superglm/distributions.py +418 -0
  29. superglm-0.12.0/src/superglm/dm_builder.py +1270 -0
  30. superglm-0.12.0/src/superglm/editor/__init__.py +5 -0
  31. superglm-0.12.0/src/superglm/editor/_types.py +63 -0
  32. superglm-0.12.0/src/superglm/editor/app/__init__.py +1 -0
  33. superglm-0.12.0/src/superglm/editor/app/api/client.js +105 -0
  34. superglm-0.12.0/src/superglm/editor/app/api/contracts.js +157 -0
  35. superglm-0.12.0/src/superglm/editor/app/api.js +7 -0
  36. superglm-0.12.0/src/superglm/editor/app/chart/geometry.js +293 -0
  37. superglm-0.12.0/src/superglm/editor/app/chart.js +1137 -0
  38. superglm-0.12.0/src/superglm/editor/app/format.js +40 -0
  39. superglm-0.12.0/src/superglm/editor/app/history.js +42 -0
  40. superglm-0.12.0/src/superglm/editor/app/index.html +458 -0
  41. superglm-0.12.0/src/superglm/editor/app/interactions.js +764 -0
  42. superglm-0.12.0/src/superglm/editor/app/main.js +1492 -0
  43. superglm-0.12.0/src/superglm/editor/app/metrics.js +45 -0
  44. superglm-0.12.0/src/superglm/editor/app/reports.js +163 -0
  45. superglm-0.12.0/src/superglm/editor/app/state/actions.js +603 -0
  46. superglm-0.12.0/src/superglm/editor/app/state/selectors.js +90 -0
  47. superglm-0.12.0/src/superglm/editor/app/state/store.js +348 -0
  48. superglm-0.12.0/src/superglm/editor/app/state/timing.js +70 -0
  49. superglm-0.12.0/src/superglm/editor/app/styles/chart.css +51 -0
  50. superglm-0.12.0/src/superglm/editor/app/styles/dialogs.css +456 -0
  51. superglm-0.12.0/src/superglm/editor/app/styles/panels.css +177 -0
  52. superglm-0.12.0/src/superglm/editor/app/styles/shell.css +233 -0
  53. superglm-0.12.0/src/superglm/editor/app/styles/tokens.css +82 -0
  54. superglm-0.12.0/src/superglm/editor/app/styles.css +768 -0
  55. superglm-0.12.0/src/superglm/editor/app/summary.js +781 -0
  56. superglm-0.12.0/src/superglm/editor/app/views/app_bar.js +102 -0
  57. superglm-0.12.0/src/superglm/editor/app/views/context_bar.js +24 -0
  58. superglm-0.12.0/src/superglm/editor/app/views/export_dialog.js +229 -0
  59. superglm-0.12.0/src/superglm/editor/app/views/help_content.js +176 -0
  60. superglm-0.12.0/src/superglm/editor/app/views/help_drawer.js +40 -0
  61. superglm-0.12.0/src/superglm/editor/app/views/inspector.js +165 -0
  62. superglm-0.12.0/src/superglm/editor/app/views/popover.js +239 -0
  63. superglm-0.12.0/src/superglm/editor/app/views/structural_confirm.js +128 -0
  64. superglm-0.12.0/src/superglm/editor/app/views/tool_rail.js +139 -0
  65. superglm-0.12.0/src/superglm/editor/apply.py +540 -0
  66. superglm-0.12.0/src/superglm/editor/assets.py +37 -0
  67. superglm-0.12.0/src/superglm/editor/collapse.py +492 -0
  68. superglm-0.12.0/src/superglm/editor/controls.py +226 -0
  69. superglm-0.12.0/src/superglm/editor/evaluation.py +158 -0
  70. superglm-0.12.0/src/superglm/editor/evaluation_cache.py +113 -0
  71. superglm-0.12.0/src/superglm/editor/evidence.py +149 -0
  72. superglm-0.12.0/src/superglm/editor/group_display.py +127 -0
  73. superglm-0.12.0/src/superglm/editor/io.py +106 -0
  74. superglm-0.12.0/src/superglm/editor/level_order.py +52 -0
  75. superglm-0.12.0/src/superglm/editor/metrics.py +187 -0
  76. superglm-0.12.0/src/superglm/editor/native_dialogs.py +108 -0
  77. superglm-0.12.0/src/superglm/editor/operations.py +237 -0
  78. superglm-0.12.0/src/superglm/editor/payloads.py +351 -0
  79. superglm-0.12.0/src/superglm/editor/persistence.py +249 -0
  80. superglm-0.12.0/src/superglm/editor/refit.py +42 -0
  81. superglm-0.12.0/src/superglm/editor/reports.py +165 -0
  82. superglm-0.12.0/src/superglm/editor/server.py +474 -0
  83. superglm-0.12.0/src/superglm/editor/session.py +1438 -0
  84. superglm-0.12.0/src/superglm/editor/summaries.py +378 -0
  85. superglm-0.12.0/src/superglm/editor/terms.py +182 -0
  86. superglm-0.12.0/src/superglm/editor/widget.py +1169 -0
  87. superglm-0.12.0/src/superglm/export/__init__.py +5 -0
  88. superglm-0.12.0/src/superglm/export/excel.py +221 -0
  89. superglm-0.12.0/src/superglm/export/rating_tables.py +670 -0
  90. superglm-0.12.0/src/superglm/export/summary.py +380 -0
  91. superglm-0.12.0/src/superglm/families.py +67 -0
  92. superglm-0.12.0/src/superglm/features/__init__.py +41 -0
  93. superglm-0.12.0/src/superglm/features/_spline_build.py +245 -0
  94. superglm-0.12.0/src/superglm/features/_spline_cardinal.py +120 -0
  95. superglm-0.12.0/src/superglm/features/_spline_cardinal_spec.py +100 -0
  96. superglm-0.12.0/src/superglm/features/_spline_config.py +178 -0
  97. superglm-0.12.0/src/superglm/features/_spline_constraints.py +54 -0
  98. superglm-0.12.0/src/superglm/features/_spline_extrapolation.py +75 -0
  99. superglm-0.12.0/src/superglm/features/_spline_factory.py +165 -0
  100. superglm-0.12.0/src/superglm/features/_spline_identifiability.py +96 -0
  101. superglm-0.12.0/src/superglm/features/_spline_knots.py +57 -0
  102. superglm-0.12.0/src/superglm/features/_spline_multi_penalty.py +31 -0
  103. superglm-0.12.0/src/superglm/features/_spline_penalties.py +52 -0
  104. superglm-0.12.0/src/superglm/features/_spline_runtime.py +192 -0
  105. superglm-0.12.0/src/superglm/features/_spline_select.py +164 -0
  106. superglm-0.12.0/src/superglm/features/_spline_subclass_ops.py +77 -0
  107. superglm-0.12.0/src/superglm/features/categorical.py +193 -0
  108. superglm-0.12.0/src/superglm/features/constraint.py +28 -0
  109. superglm-0.12.0/src/superglm/features/grouping.py +184 -0
  110. superglm-0.12.0/src/superglm/features/interaction.py +1290 -0
  111. superglm-0.12.0/src/superglm/features/numeric.py +48 -0
  112. superglm-0.12.0/src/superglm/features/ordered_categorical.py +563 -0
  113. superglm-0.12.0/src/superglm/features/polynomial.py +90 -0
  114. superglm-0.12.0/src/superglm/features/spline.py +1015 -0
  115. superglm-0.12.0/src/superglm/group_matrix.py +441 -0
  116. superglm-0.12.0/src/superglm/inference/__init__.py +71 -0
  117. superglm-0.12.0/src/superglm/inference/_metrics_design.py +289 -0
  118. superglm-0.12.0/src/superglm/inference/_ordered_reference.py +85 -0
  119. superglm-0.12.0/src/superglm/inference/_term_covariance.py +248 -0
  120. superglm-0.12.0/src/superglm/inference/_term_helpers.py +358 -0
  121. superglm-0.12.0/src/superglm/inference/_term_interactions.py +79 -0
  122. superglm-0.12.0/src/superglm/inference/_term_model_ops.py +340 -0
  123. superglm-0.12.0/src/superglm/inference/_term_ops.py +493 -0
  124. superglm-0.12.0/src/superglm/inference/_term_types.py +186 -0
  125. superglm-0.12.0/src/superglm/inference/coef_tables.py +968 -0
  126. superglm-0.12.0/src/superglm/inference/covariance.py +358 -0
  127. superglm-0.12.0/src/superglm/inference/metrics.py +1320 -0
  128. superglm-0.12.0/src/superglm/inference/summary.py +886 -0
  129. superglm-0.12.0/src/superglm/inference/term.py +53 -0
  130. superglm-0.12.0/src/superglm/links.py +466 -0
  131. superglm-0.12.0/src/superglm/model/__init__.py +8 -0
  132. superglm-0.12.0/src/superglm/model/api.py +1557 -0
  133. superglm-0.12.0/src/superglm/model/base.py +753 -0
  134. superglm-0.12.0/src/superglm/model/explain_ops.py +254 -0
  135. superglm-0.12.0/src/superglm/model/fit_data_guard.py +123 -0
  136. superglm-0.12.0/src/superglm/model/fit_ops.py +1332 -0
  137. superglm-0.12.0/src/superglm/model/fit_state.py +697 -0
  138. superglm-0.12.0/src/superglm/model/fit_workspace.py +97 -0
  139. superglm-0.12.0/src/superglm/model/input_validation.py +110 -0
  140. superglm-0.12.0/src/superglm/model/monotone_ops.py +29 -0
  141. superglm-0.12.0/src/superglm/model/path_ops.py +113 -0
  142. superglm-0.12.0/src/superglm/model/plot_ops.py +308 -0
  143. superglm-0.12.0/src/superglm/model/profile_ops.py +430 -0
  144. superglm-0.12.0/src/superglm/model/reml_debug.py +392 -0
  145. superglm-0.12.0/src/superglm/model/reml_execute.py +372 -0
  146. superglm-0.12.0/src/superglm/model/reml_finalize.py +472 -0
  147. superglm-0.12.0/src/superglm/model/reml_ops.py +333 -0
  148. superglm-0.12.0/src/superglm/model/reml_setup.py +162 -0
  149. superglm-0.12.0/src/superglm/model/reml_state.py +79 -0
  150. superglm-0.12.0/src/superglm/model/report_ops.py +523 -0
  151. superglm-0.12.0/src/superglm/model/runtime_canonicalize.py +454 -0
  152. superglm-0.12.0/src/superglm/model/shape_ops.py +764 -0
  153. superglm-0.12.0/src/superglm/model/state_ops.py +492 -0
  154. superglm-0.12.0/src/superglm/model/telemetry_ops.py +363 -0
  155. superglm-0.12.0/src/superglm/model_selection.py +433 -0
  156. superglm-0.12.0/src/superglm/penalties/__init__.py +16 -0
  157. superglm-0.12.0/src/superglm/penalties/base.py +154 -0
  158. superglm-0.12.0/src/superglm/penalties/flavors.py +68 -0
  159. superglm-0.12.0/src/superglm/penalties/group_elastic_net.py +80 -0
  160. superglm-0.12.0/src/superglm/penalties/group_lasso.py +61 -0
  161. superglm-0.12.0/src/superglm/penalties/ridge.py +50 -0
  162. superglm-0.12.0/src/superglm/penalties/sparse_group_lasso.py +73 -0
  163. superglm-0.12.0/src/superglm/plotting/__init__.py +14 -0
  164. superglm-0.12.0/src/superglm/plotting/common.py +261 -0
  165. superglm-0.12.0/src/superglm/plotting/comparison.py +267 -0
  166. superglm-0.12.0/src/superglm/plotting/comparison_plotly.py +313 -0
  167. superglm-0.12.0/src/superglm/plotting/curve_similarity.py +152 -0
  168. superglm-0.12.0/src/superglm/plotting/data.py +428 -0
  169. superglm-0.12.0/src/superglm/plotting/diagnostics.py +544 -0
  170. superglm-0.12.0/src/superglm/plotting/group_display.py +180 -0
  171. superglm-0.12.0/src/superglm/plotting/interactions.py +1026 -0
  172. superglm-0.12.0/src/superglm/plotting/main_effects.py +922 -0
  173. superglm-0.12.0/src/superglm/plotting/main_effects_plotly.py +1744 -0
  174. superglm-0.12.0/src/superglm/profiling/__init__.py +34 -0
  175. superglm-0.12.0/src/superglm/profiling/_reporting.py +154 -0
  176. superglm-0.12.0/src/superglm/profiling/harness.py +281 -0
  177. superglm-0.12.0/src/superglm/profiling/nb.py +583 -0
  178. superglm-0.12.0/src/superglm/profiling/tweedie.py +5976 -0
  179. superglm-0.12.0/src/superglm/reml/__init__.py +56 -0
  180. superglm-0.12.0/src/superglm/reml/direct.py +868 -0
  181. superglm-0.12.0/src/superglm/reml/discrete.py +1160 -0
  182. superglm-0.12.0/src/superglm/reml/efs.py +418 -0
  183. superglm-0.12.0/src/superglm/reml/gradient.py +281 -0
  184. superglm-0.12.0/src/superglm/reml/multi_penalty.py +356 -0
  185. superglm-0.12.0/src/superglm/reml/objective.py +293 -0
  186. superglm-0.12.0/src/superglm/reml/observed_geometry.py +900 -0
  187. superglm-0.12.0/src/superglm/reml/penalty_algebra.py +902 -0
  188. superglm-0.12.0/src/superglm/reml/result.py +94 -0
  189. superglm-0.12.0/src/superglm/reml/runner.py +414 -0
  190. superglm-0.12.0/src/superglm/reml/scale.py +311 -0
  191. superglm-0.12.0/src/superglm/reml/scop_efs.py +1851 -0
  192. superglm-0.12.0/src/superglm/reml/scop_geometry.py +904 -0
  193. superglm-0.12.0/src/superglm/reml/w_derivatives.py +471 -0
  194. superglm-0.12.0/src/superglm/sklearn.py +796 -0
  195. superglm-0.12.0/src/superglm/solvers/__init__.py +6 -0
  196. superglm-0.12.0/src/superglm/solvers/centered_system.py +347 -0
  197. superglm-0.12.0/src/superglm/solvers/constrained_qp.py +199 -0
  198. superglm-0.12.0/src/superglm/solvers/dispersion.py +35 -0
  199. superglm-0.12.0/src/superglm/solvers/irls_direct.py +2242 -0
  200. superglm-0.12.0/src/superglm/solvers/irls_state.py +195 -0
  201. superglm-0.12.0/src/superglm/solvers/pirls.py +1495 -0
  202. superglm-0.12.0/src/superglm/solvers/rank.py +895 -0
  203. superglm-0.12.0/src/superglm/solvers/scop.py +299 -0
  204. superglm-0.12.0/src/superglm/solvers/scop_exact_support.py +31 -0
  205. superglm-0.12.0/src/superglm/solvers/scop_newton.py +1091 -0
  206. superglm-0.12.0/src/superglm/solvers/working_rows.py +125 -0
  207. superglm-0.12.0/src/superglm/stats/__init__.py +31 -0
  208. superglm-0.12.0/src/superglm/stats/davies.py +183 -0
  209. superglm-0.12.0/src/superglm/stats/model_tests.py +473 -0
  210. superglm-0.12.0/src/superglm/stats/wood_pvalue.py +250 -0
  211. superglm-0.12.0/src/superglm/types.py +316 -0
  212. superglm-0.12.0/src/superglm/validation.py +789 -0
@@ -0,0 +1,73 @@
1
+ # Virtual environment
2
+ .venv/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ dist/
10
+ build/
11
+
12
+ # Coverage
13
+ .coverage
14
+ coverage.xml
15
+ htmlcov/
16
+
17
+ # IDE
18
+ .idea/
19
+ .vscode/
20
+ *.swp
21
+
22
+ # OS
23
+ .DS_Store
24
+
25
+ # Data
26
+ data/
27
+
28
+ # Other
29
+ .claude/
30
+ .ruff_cahce/
31
+ scratch/
32
+
33
+ # Benchmark outputs (generated, not tracked)
34
+ benchmarks/results/
35
+
36
+ # Generated parity/reference CSVs (keep local, do not track)
37
+ tests/fixtures/mgcv_gamma_mtpl2sev_fitted.csv
38
+ tests/fixtures/mgcv_nb2_mtpl2_fitted.csv
39
+ tests/fixtures/mtpl2_freq_50k.csv
40
+ tests/fixtures/mtpl2_sev_merged.csv
41
+
42
+ # MkDocs build output
43
+ site/
44
+
45
+ AGENTS.md
46
+ ROADMAP.md
47
+ TESTING_AUDIT_PLAN.md
48
+ ISSUE_WORKING_WEIGHTS.md
49
+ REML_IMPLEMENTATION_PLAN.md
50
+
51
+ # scratch/ is a playground for local dev only — not for public release.
52
+ # Benchmarks, experiments, R comparisons, and throwaway scripts live here.
53
+ scratch/
54
+ docs/notebooks/spline_diagnostics/
55
+ .superglm-debug/
56
+
57
+ # Superpowers skill artifacts
58
+ docs/superpowers/
59
+ docs/reml_freml_paper_checklist.md
60
+
61
+ # Agentic harness artifacts
62
+ .harness/
63
+ PLAN.md
64
+ REVIEW.md
65
+ PROGRESS.md
66
+ GENERATOR_STATUS.md
67
+ REML_BAD_BEHAVIOUR.txt
68
+ .omx/
69
+
70
+ # Frontend development
71
+ node_modules/
72
+ playwright-report/
73
+ test-results/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Max Hicks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,345 @@
1
+ Metadata-Version: 2.4
2
+ Name: superglm
3
+ Version: 0.12.0
4
+ Summary: Penalised GLMs for insurance pricing: group lasso, P-splines, Tweedie
5
+ Project-URL: Documentation, https://strudeldoodles.github.io/superglm/
6
+ Project-URL: Homepage, https://github.com/StrudelDoodleS/superglm
7
+ Project-URL: Issues, https://github.com/StrudelDoodleS/superglm/issues
8
+ Project-URL: Repository, https://github.com/StrudelDoodleS/superglm
9
+ Author: Max Hicks
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: actuarial,generalized-additive-models,generalized-linear-models,insurance-pricing,splines
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Scientific/Engineering
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: fastapi>=0.115
27
+ Requires-Dist: matplotlib>=3.7
28
+ Requires-Dist: numba>=0.57
29
+ Requires-Dist: numpy>=1.24
30
+ Requires-Dist: openpyxl>=3.1
31
+ Requires-Dist: pandas>=2.0
32
+ Requires-Dist: scikit-learn>=1.3
33
+ Requires-Dist: scipy>=1.10
34
+ Requires-Dist: tabmat>=4.2.1
35
+ Requires-Dist: uvicorn>=0.30
36
+ Provides-Extra: bench
37
+ Requires-Dist: glum>=3.4.1; extra == 'bench'
38
+ Requires-Dist: pyarrow>=10.0; extra == 'bench'
39
+ Requires-Dist: statsmodels>=0.14; extra == 'bench'
40
+ Provides-Extra: dev
41
+ Requires-Dist: playwright>=1.55; extra == 'dev'
42
+ Requires-Dist: pre-commit; extra == 'dev'
43
+ Requires-Dist: pytest-cov; extra == 'dev'
44
+ Requires-Dist: pytest>=7.0; extra == 'dev'
45
+ Requires-Dist: ruff; extra == 'dev'
46
+ Requires-Dist: ty==0.0.61; extra == 'dev'
47
+ Provides-Extra: plotting
48
+ Requires-Dist: plotly>=5.24; extra == 'plotting'
49
+ Description-Content-Type: text/markdown
50
+
51
+ <p align="center">
52
+ <img src="https://raw.githubusercontent.com/StrudelDoodleS/superglm/master/docs/images/logo.png" alt="SuperGLM" width="300">
53
+ </p>
54
+
55
+ [![CI](https://github.com/StrudelDoodleS/superglm/actions/workflows/ci.yml/badge.svg)](https://github.com/StrudelDoodleS/superglm/actions/workflows/ci.yml)
56
+ [![codecov](https://codecov.io/github/StrudelDoodleS/superglm/graph/badge.svg?token=2HO71TA2ZY)](https://codecov.io/github/StrudelDoodleS/superglm)
57
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://github.com/StrudelDoodleS/superglm/actions/workflows/ci.yml)
58
+
59
+ Penalised GLMs and GAM-style pricing models for insurance. SuperGLM combines
60
+ explicit feature specs, exact REML, large-`n` discrete REML, solver-backed
61
+ monotone splines, actuarial validation tooling, and deployable fitted
62
+ estimators for Poisson, Gamma, NB2, Tweedie, Binomial, and Gaussian models.
63
+
64
+ ## Installation
65
+
66
+ Install SuperGLM from PyPI:
67
+
68
+ ```bash
69
+ pip install superglm
70
+ ```
71
+
72
+ Plotly-based interactive charts are optional:
73
+
74
+ ```bash
75
+ pip install "superglm[plotting]"
76
+ ```
77
+
78
+ The local model editor is included in the normal installation.
79
+
80
+ ## Recommended Workflow
81
+
82
+ For spline-based pricing models, the default path is:
83
+
84
+ 1. define explicit feature specs
85
+ 2. fit with `fit_reml()` and `selection_penalty=0`
86
+ 3. compare candidates with `cross_validate(..., fit_mode="fit_reml")`
87
+ 4. refit on all training data
88
+ 5. evaluate holdout Lorenz and double-lift charts
89
+ 6. serialize the fitted estimator for scoring
90
+
91
+ ```python
92
+ from superglm import Categorical, Numeric, Spline, SuperGLM
93
+
94
+ features = {
95
+ "DrivAge": Spline(kind="ps", k=14, knot_strategy="quantile_rows"),
96
+ "VehAge": Spline(kind="cr", k=10, knot_strategy="quantile_rows"),
97
+ "BonusMalus": Spline(kind="cr", k=12, knot_strategy="quantile_tempered"),
98
+ "Area": Categorical(base="most_exposed"),
99
+ "LogDensity": Numeric(),
100
+ }
101
+
102
+ model = SuperGLM(
103
+ family="poisson",
104
+ selection_penalty=0.0,
105
+ features=features,
106
+ )
107
+ model.fit_reml(train_df, y_train, sample_weight=exposure_train, max_reml_iter=30)
108
+
109
+ mu_holdout = model.predict(holdout_df)
110
+ print(model.summary())
111
+ ```
112
+
113
+ ## Choosing A Fit Path
114
+
115
+ ### `fit_reml()` with `selection_penalty=0`
116
+
117
+ This is the recommended path for spline-heavy GAM-style pricing models. Use it
118
+ when you want automatic smoothness selection, interpretable smooth terms, and
119
+ mgcv-style modeling rather than sparse screening.
120
+
121
+ ```python
122
+ model = SuperGLM(
123
+ family="poisson",
124
+ selection_penalty=0.0,
125
+ features=features,
126
+ )
127
+ model.fit_reml(df, y, sample_weight=exposure)
128
+ ```
129
+
130
+ ### `fit_reml(discrete=True)`
131
+
132
+ Use this when the model is still a REML pricing model, but the data is large
133
+ enough that exact REML becomes expensive. This is the production-scale path for
134
+ large frequency models.
135
+
136
+ ```python
137
+ model = SuperGLM(
138
+ family="poisson",
139
+ selection_penalty=0.0,
140
+ discrete=True,
141
+ n_bins=256,
142
+ features=features,
143
+ )
144
+ model.fit_reml(df, y, sample_weight=exposure)
145
+ ```
146
+
147
+ ### `fit()` with `selection_penalty > 0`
148
+
149
+ Use this when you want sparse screening, compression, or fixed-penalty
150
+ regularisation. This is a different modeling story from REML smoothness
151
+ selection.
152
+
153
+ ```python
154
+ model = SuperGLM(
155
+ family="poisson",
156
+ penalty="group_elastic_net",
157
+ selection_penalty=0.01,
158
+ spline_penalty=0.1,
159
+ features=features,
160
+ )
161
+ model.fit(df, y, sample_weight=exposure)
162
+ ```
163
+
164
+ ### `select=True`
165
+
166
+ `select=True` on spline terms adds mgcv-style double-penalty shrinkage. This is
167
+ the REML-native way to let smooth terms shrink toward linear or zero while
168
+ staying in the `fit_reml()` workflow.
169
+
170
+ ```python
171
+ features = {
172
+ "DrivAge": Spline(kind="ps", k=14, select=True),
173
+ "VehAge": Spline(kind="cr", k=10, select=True),
174
+ "Area": Categorical(base="most_exposed"),
175
+ }
176
+ model = SuperGLM(family="poisson", selection_penalty=0.0, features=features)
177
+ model.fit_reml(df, y, sample_weight=exposure)
178
+ ```
179
+
180
+ ## Validation And Model Comparison
181
+
182
+ `cross_validate()` should be part of the standard pricing workflow, not an
183
+ afterthought. It gives fold-level metrics, timing, convergence information, and
184
+ out-of-fold predictions for challenger comparisons.
185
+
186
+ ```python
187
+ from sklearn.model_selection import KFold
188
+ from superglm import cross_validate
189
+ from superglm.validation import double_lift_chart, lorenz_curve
190
+
191
+ cv = cross_validate(
192
+ model,
193
+ train_df,
194
+ y_train,
195
+ cv=KFold(n_splits=5, shuffle=True, random_state=42),
196
+ sample_weight=exposure_train,
197
+ fit_mode="fit_reml",
198
+ scoring=("deviance", "nll", "gini"),
199
+ return_oof=True,
200
+ )
201
+
202
+ gini = lorenz_curve(y_holdout, mu_holdout, exposure=exposure_holdout)
203
+ lift = double_lift_chart(
204
+ y_obs=y_holdout,
205
+ y_pred_model=mu_holdout,
206
+ y_pred_current=mu_baseline,
207
+ exposure=exposure_holdout,
208
+ )
209
+ ```
210
+
211
+ Key outputs:
212
+
213
+ - `cv.fold_scores`: per-fold metrics, fit time, convergence, and EDF
214
+ - `cv.mean_scores` / `cv.std_scores`: summary comparisons
215
+ - `cv.oof_predictions`: out-of-fold predictions for the training rows
216
+ - `lorenz_curve(...)`: ranking power via Gini
217
+ - `double_lift_chart(...)`: business-facing champion/challenger evidence
218
+
219
+ ## Monotone Splines
220
+
221
+ SuperGLM supports solver-backed monotone spline fitting. This is the preferred
222
+ way to enforce business shape constraints inside the model itself.
223
+
224
+ - `BSplineSmooth(..., monotone="increasing", monotone_mode="fit")`:
225
+ constrained QP path
226
+ - `CubicRegressionSpline(..., monotone="decreasing", monotone_mode="fit")`:
227
+ constrained QP path
228
+ - `PSpline(..., monotone="increasing", monotone_mode="fit")`:
229
+ SCOP path
230
+
231
+ ```python
232
+ from superglm import BSplineSmooth, PSpline, SuperGLM
233
+
234
+ qp_model = SuperGLM(
235
+ family="gaussian",
236
+ selection_penalty=0.0,
237
+ features={
238
+ "x": BSplineSmooth(n_knots=8, monotone="increasing", monotone_mode="fit"),
239
+ },
240
+ )
241
+
242
+ scop_model = SuperGLM(
243
+ family="gaussian",
244
+ selection_penalty=0.0,
245
+ features={
246
+ "x": PSpline(n_knots=10, monotone="increasing", monotone_mode="fit"),
247
+ },
248
+ )
249
+ ```
250
+
251
+ Post-fit isotonic repair still exists, but it should be treated as a manual
252
+ fallback rather than the main monotone workflow.
253
+
254
+ ## Feature Highlights
255
+
256
+ - `Spline(kind="ps")`, `Spline(kind="cr")`, and `Spline(kind="ns")` cover the
257
+ main spline basis choices.
258
+ - `OrderedCategorical(...)` smooths ordered factor levels without forcing a
259
+ plain one-hot representation and reports one whole-smooth test rather than
260
+ separate p-values at arbitrary level positions.
261
+ - `collapse_levels(...)` lets you merge sparse categorical levels while still
262
+ expanding back to original levels for inference and plotting.
263
+ - `interactions=[(...)]` supports spline-categorical, numeric-categorical,
264
+ tensor, and other interaction types.
265
+ - `m=(...)` supports multi-order spline penalties with separate REML lambdas.
266
+
267
+ ```python
268
+ from superglm import Categorical, OrderedCategorical, Spline, collapse_levels
269
+
270
+ area_grouping = collapse_levels(train_df["Area"], groups={"Rural": ["E", "F"]})
271
+
272
+ features = {
273
+ "VehAge": Spline(kind="cr", k=10),
274
+ "Area": Categorical(base="most_exposed", grouping=area_grouping),
275
+ "BonusClass": OrderedCategorical(
276
+ order=["A", "B", "C", "D"],
277
+ basis=Spline(kind="ps", k=6),
278
+ ),
279
+ }
280
+ ```
281
+
282
+ ## Weights And Offsets
283
+
284
+ Public fitting examples use `sample_weight=`. In insurance settings this means
285
+ exposure / frequency weight, not inverse-variance weight.
286
+
287
+ ```python
288
+ import numpy as np
289
+
290
+ # Raw count target: offset absorbs exposure, model estimates a rate
291
+ model.fit(df, claim_counts, offset=np.log(exposure))
292
+
293
+ # Rate target: sample_weight carries exposure
294
+ model.fit(df, claim_rate, sample_weight=exposure)
295
+ ```
296
+
297
+ Validation helpers such as `lorenz_curve(...)` and `double_lift_chart(...)`
298
+ still use `exposure=...`, which is correct for that API.
299
+
300
+ ## Deployment
301
+
302
+ A fitted `SuperGLM` is the deployment artifact. It already contains:
303
+
304
+ - registered feature specs
305
+ - learned knot geometry and constraints
306
+ - fitted coefficients and intercept
307
+ - REML smoothing parameters
308
+
309
+ ```python
310
+ import pickle
311
+
312
+ with open("pricing_model.pkl", "wb") as f:
313
+ pickle.dump(model, f)
314
+
315
+ with open("pricing_model.pkl", "rb") as f:
316
+ loaded = pickle.load(f)
317
+
318
+ mu = loaded.predict(score_df)
319
+ ```
320
+
321
+ The loaded model can still score, print summaries, rebuild curves, and produce
322
+ relativity views without refitting.
323
+
324
+ ## Advanced Penalty Objects
325
+
326
+ At the top-level model API, prefer `selection_penalty=` and `spline_penalty=`.
327
+ Low-level penalty objects still expose `lambda1`, for example:
328
+
329
+ ```python
330
+ from superglm import GroupElasticNet
331
+
332
+ penalty = GroupElasticNet(lambda1=0.01, alpha=0.5)
333
+ model = SuperGLM(family="poisson", penalty=penalty, features=features)
334
+ ```
335
+
336
+ That is advanced usage. It should not be your default starting point.
337
+
338
+ ## Learn More
339
+
340
+ - [Recommended workflows](docs/guide/workflows.md)
341
+ - [Choosing a fitting path](docs/guide/fitting.md)
342
+ - [Monotone splines](docs/guide/monotone.md)
343
+ - [Validation and model comparison](docs/guide/validation.md)
344
+ - [Deployment](docs/guide/deployment.md)
345
+ - [Optimization and solver internals](docs/guide/optimization.md)