ins-pricing 0.4.5__py3-none-any.whl → 0.5.1__py3-none-any.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.
Files changed (93) hide show
  1. ins_pricing/README.md +48 -22
  2. ins_pricing/__init__.py +142 -90
  3. ins_pricing/cli/BayesOpt_entry.py +58 -46
  4. ins_pricing/cli/BayesOpt_incremental.py +77 -110
  5. ins_pricing/cli/Explain_Run.py +42 -23
  6. ins_pricing/cli/Explain_entry.py +551 -577
  7. ins_pricing/cli/Pricing_Run.py +42 -23
  8. ins_pricing/cli/bayesopt_entry_runner.py +51 -16
  9. ins_pricing/cli/utils/bootstrap.py +23 -0
  10. ins_pricing/cli/utils/cli_common.py +256 -256
  11. ins_pricing/cli/utils/cli_config.py +379 -360
  12. ins_pricing/cli/utils/import_resolver.py +375 -358
  13. ins_pricing/cli/utils/notebook_utils.py +256 -242
  14. ins_pricing/cli/watchdog_run.py +216 -198
  15. ins_pricing/frontend/__init__.py +10 -10
  16. ins_pricing/frontend/app.py +132 -61
  17. ins_pricing/frontend/config_builder.py +33 -0
  18. ins_pricing/frontend/example_config.json +11 -0
  19. ins_pricing/frontend/example_workflows.py +1 -1
  20. ins_pricing/frontend/runner.py +340 -388
  21. ins_pricing/governance/__init__.py +20 -20
  22. ins_pricing/governance/release.py +159 -159
  23. ins_pricing/modelling/README.md +1 -1
  24. ins_pricing/modelling/__init__.py +147 -92
  25. ins_pricing/modelling/{core/bayesopt → bayesopt}/README.md +31 -13
  26. ins_pricing/modelling/{core/bayesopt → bayesopt}/__init__.py +64 -102
  27. ins_pricing/modelling/{core/bayesopt → bayesopt}/config_components.py +12 -0
  28. ins_pricing/modelling/{core/bayesopt → bayesopt}/config_preprocess.py +589 -552
  29. ins_pricing/modelling/{core/bayesopt → bayesopt}/core.py +987 -958
  30. ins_pricing/modelling/{core/bayesopt → bayesopt}/model_explain_mixin.py +296 -296
  31. ins_pricing/modelling/{core/bayesopt → bayesopt}/model_plotting_mixin.py +488 -548
  32. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/__init__.py +27 -27
  33. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_ft_components.py +349 -342
  34. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_ft_trainer.py +921 -913
  35. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_gnn.py +794 -785
  36. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_resn.py +454 -446
  37. ins_pricing/modelling/bayesopt/trainers/__init__.py +19 -0
  38. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_base.py +1294 -1282
  39. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_ft.py +64 -56
  40. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_glm.py +203 -198
  41. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_gnn.py +333 -325
  42. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_resn.py +279 -267
  43. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_xgb.py +515 -313
  44. ins_pricing/modelling/bayesopt/utils/__init__.py +67 -0
  45. ins_pricing/modelling/bayesopt/utils/constants.py +21 -0
  46. ins_pricing/modelling/{core/bayesopt → bayesopt}/utils/distributed_utils.py +193 -186
  47. ins_pricing/modelling/bayesopt/utils/io_utils.py +7 -0
  48. ins_pricing/modelling/bayesopt/utils/losses.py +27 -0
  49. ins_pricing/modelling/bayesopt/utils/metrics_and_devices.py +17 -0
  50. ins_pricing/modelling/{core/bayesopt → bayesopt}/utils/torch_trainer_mixin.py +636 -623
  51. ins_pricing/modelling/{core/evaluation.py → evaluation.py} +113 -104
  52. ins_pricing/modelling/explain/__init__.py +55 -55
  53. ins_pricing/modelling/explain/metrics.py +27 -174
  54. ins_pricing/modelling/explain/permutation.py +237 -237
  55. ins_pricing/modelling/plotting/__init__.py +40 -36
  56. ins_pricing/modelling/plotting/compat.py +228 -0
  57. ins_pricing/modelling/plotting/curves.py +572 -572
  58. ins_pricing/modelling/plotting/diagnostics.py +163 -163
  59. ins_pricing/modelling/plotting/geo.py +362 -362
  60. ins_pricing/modelling/plotting/importance.py +121 -121
  61. ins_pricing/pricing/__init__.py +27 -27
  62. ins_pricing/pricing/factors.py +67 -56
  63. ins_pricing/production/__init__.py +35 -25
  64. ins_pricing/production/{predict.py → inference.py} +140 -57
  65. ins_pricing/production/monitoring.py +8 -21
  66. ins_pricing/reporting/__init__.py +11 -11
  67. ins_pricing/setup.py +1 -1
  68. ins_pricing/tests/production/test_inference.py +90 -0
  69. ins_pricing/utils/__init__.py +112 -78
  70. ins_pricing/utils/device.py +258 -237
  71. ins_pricing/utils/features.py +53 -0
  72. ins_pricing/utils/io.py +72 -0
  73. ins_pricing/utils/logging.py +34 -1
  74. ins_pricing/{modelling/core/bayesopt/utils → utils}/losses.py +125 -129
  75. ins_pricing/utils/metrics.py +158 -24
  76. ins_pricing/utils/numerics.py +76 -0
  77. ins_pricing/utils/paths.py +9 -1
  78. ins_pricing/utils/profiling.py +8 -4
  79. {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.1.dist-info}/METADATA +1 -1
  80. ins_pricing-0.5.1.dist-info/RECORD +132 -0
  81. ins_pricing/modelling/core/BayesOpt.py +0 -146
  82. ins_pricing/modelling/core/__init__.py +0 -1
  83. ins_pricing/modelling/core/bayesopt/trainers/__init__.py +0 -19
  84. ins_pricing/modelling/core/bayesopt/utils/__init__.py +0 -86
  85. ins_pricing/modelling/core/bayesopt/utils/constants.py +0 -183
  86. ins_pricing/modelling/core/bayesopt/utils/io_utils.py +0 -126
  87. ins_pricing/modelling/core/bayesopt/utils/metrics_and_devices.py +0 -555
  88. ins_pricing/modelling/core/bayesopt/utils.py +0 -105
  89. ins_pricing/modelling/core/bayesopt/utils_backup.py +0 -1503
  90. ins_pricing/tests/production/test_predict.py +0 -233
  91. ins_pricing-0.4.5.dist-info/RECORD +0 -130
  92. {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.1.dist-info}/WHEEL +0 -0
  93. {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.1.dist-info}/top_level.txt +0 -0
@@ -1,163 +1,163 @@
1
- from __future__ import annotations
2
-
3
- from typing import Mapping, Optional, Sequence
4
-
5
- import numpy as np
6
- import pandas as pd
7
-
8
- from .common import EPS, PlotStyle, finalize_figure, plt
9
-
10
-
11
- def plot_loss_curve(
12
- *,
13
- history: Optional[Mapping[str, Sequence[float]]] = None,
14
- train: Optional[Sequence[float]] = None,
15
- val: Optional[Sequence[float]] = None,
16
- title: str = "Loss vs. Epoch",
17
- ax: Optional[plt.Axes] = None,
18
- show: bool = False,
19
- save_path: Optional[str] = None,
20
- style: Optional[PlotStyle] = None,
21
- ) -> Optional[plt.Figure]:
22
- style = style or PlotStyle()
23
- if history is not None:
24
- if train is None:
25
- train = history.get("train")
26
- if val is None:
27
- val = history.get("val")
28
-
29
- train_hist = list(train or [])
30
- val_hist = list(val or [])
31
- if not train_hist and not val_hist:
32
- return None
33
-
34
- created_fig = ax is None
35
- if created_fig:
36
- fig, ax = plt.subplots(figsize=style.figsize)
37
- else:
38
- fig = ax.figure
39
-
40
- if train_hist:
41
- ax.plot(
42
- range(1, len(train_hist) + 1),
43
- train_hist,
44
- label="Train Loss",
45
- color="tab:blue",
46
- )
47
- if val_hist:
48
- ax.plot(
49
- range(1, len(val_hist) + 1),
50
- val_hist,
51
- label="Validation Loss",
52
- color="tab:orange",
53
- )
54
-
55
- ax.set_xlabel("Epoch", fontsize=style.label_size)
56
- ax.set_ylabel("Weighted Loss", fontsize=style.label_size)
57
- ax.set_title(title, fontsize=style.title_size)
58
- ax.tick_params(axis="both", labelsize=style.tick_size)
59
- if style.grid:
60
- ax.grid(True, linestyle=style.grid_style, alpha=style.grid_alpha)
61
- ax.legend(loc="best", fontsize=style.legend_size, frameon=False)
62
-
63
- if created_fig:
64
- finalize_figure(fig, save_path=save_path, show=show, style=style)
65
-
66
- return fig
67
-
68
-
69
- def plot_oneway(
70
- df: pd.DataFrame,
71
- *,
72
- feature: str,
73
- weight_col: str,
74
- target_col: str,
75
- pred_col: Optional[str] = None,
76
- pred_weighted: bool = False,
77
- pred_label: Optional[str] = None,
78
- n_bins: int = 10,
79
- is_categorical: bool = False,
80
- title: Optional[str] = None,
81
- ax: Optional[plt.Axes] = None,
82
- show: bool = False,
83
- save_path: Optional[str] = None,
84
- style: Optional[PlotStyle] = None,
85
- ) -> Optional[plt.Figure]:
86
- if feature not in df.columns:
87
- raise KeyError(f"feature '{feature}' not found in data.")
88
- if weight_col not in df.columns:
89
- raise KeyError(f"weight_col '{weight_col}' not found in data.")
90
- if target_col not in df.columns:
91
- raise KeyError(f"target_col '{target_col}' not found in data.")
92
- if pred_col is not None and pred_col not in df.columns:
93
- raise KeyError(f"pred_col '{pred_col}' not found in data.")
94
-
95
- style = style or PlotStyle()
96
- title = title or f"Analysis of {feature}"
97
-
98
- if is_categorical:
99
- group_col = feature
100
- plot_source = df
101
- else:
102
- group_col = f"{feature}_bins"
103
- series = pd.to_numeric(df[feature], errors="coerce")
104
- try:
105
- bins = pd.qcut(series, n_bins, duplicates="drop")
106
- except ValueError:
107
- bins = pd.cut(series, bins=max(1, int(n_bins)), duplicates="drop")
108
- plot_source = df.assign(**{group_col: bins})
109
-
110
- if pred_col is not None:
111
- if pred_weighted:
112
- plot_source = plot_source.assign(_pred_w=plot_source[pred_col])
113
- else:
114
- plot_source = plot_source.assign(
115
- _pred_w=plot_source[pred_col] * plot_source[weight_col]
116
- )
117
-
118
- plot_data = plot_source.groupby([group_col], observed=True).sum(numeric_only=True)
119
- plot_data.reset_index(inplace=True)
120
-
121
- denom = np.maximum(plot_data[weight_col].to_numpy(dtype=float), EPS)
122
- plot_data["act_v"] = plot_data[target_col].to_numpy(dtype=float) / denom
123
- if pred_col is not None:
124
- plot_data["pred_v"] = plot_data["_pred_w"].to_numpy(dtype=float) / denom
125
-
126
- created_fig = ax is None
127
- if created_fig:
128
- fig, ax = plt.subplots(figsize=style.figsize)
129
- else:
130
- fig = ax.figure
131
-
132
- ax.plot(plot_data.index, plot_data["act_v"], label="Actual", color="red")
133
- if pred_col is not None:
134
- ax.plot(
135
- plot_data.index,
136
- plot_data["pred_v"],
137
- label=pred_label or "Predicted",
138
- color=style.palette[0],
139
- )
140
- ax.set_title(title, fontsize=style.title_size)
141
- ax.set_xticks(plot_data.index)
142
- labels = plot_data[group_col].astype(str).tolist()
143
- tick_size = 3 if len(labels) > 50 else style.tick_size
144
- ax.set_xticklabels(labels, rotation=90, fontsize=tick_size)
145
- ax.tick_params(axis="y", labelsize=style.tick_size)
146
- if style.grid:
147
- ax.grid(True, linestyle=style.grid_style, alpha=style.grid_alpha)
148
- if pred_col is not None:
149
- ax.legend(fontsize=style.legend_size)
150
-
151
- ax2 = ax.twinx()
152
- ax2.bar(
153
- plot_data.index,
154
- plot_data[weight_col],
155
- alpha=0.5,
156
- color=style.weight_color,
157
- )
158
- ax2.tick_params(axis="y", labelsize=style.tick_size)
159
-
160
- if created_fig:
161
- finalize_figure(fig, save_path=save_path, show=show, style=style)
162
-
163
- return fig
1
+ from __future__ import annotations
2
+
3
+ from typing import Mapping, Optional, Sequence
4
+
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+ from ins_pricing.modelling.plotting.common import EPS, PlotStyle, finalize_figure, plt
9
+
10
+
11
+ def plot_loss_curve(
12
+ *,
13
+ history: Optional[Mapping[str, Sequence[float]]] = None,
14
+ train: Optional[Sequence[float]] = None,
15
+ val: Optional[Sequence[float]] = None,
16
+ title: str = "Loss vs. Epoch",
17
+ ax: Optional[plt.Axes] = None,
18
+ show: bool = False,
19
+ save_path: Optional[str] = None,
20
+ style: Optional[PlotStyle] = None,
21
+ ) -> Optional[plt.Figure]:
22
+ style = style or PlotStyle()
23
+ if history is not None:
24
+ if train is None:
25
+ train = history.get("train")
26
+ if val is None:
27
+ val = history.get("val")
28
+
29
+ train_hist = list(train or [])
30
+ val_hist = list(val or [])
31
+ if not train_hist and not val_hist:
32
+ return None
33
+
34
+ created_fig = ax is None
35
+ if created_fig:
36
+ fig, ax = plt.subplots(figsize=style.figsize)
37
+ else:
38
+ fig = ax.figure
39
+
40
+ if train_hist:
41
+ ax.plot(
42
+ range(1, len(train_hist) + 1),
43
+ train_hist,
44
+ label="Train Loss",
45
+ color="tab:blue",
46
+ )
47
+ if val_hist:
48
+ ax.plot(
49
+ range(1, len(val_hist) + 1),
50
+ val_hist,
51
+ label="Validation Loss",
52
+ color="tab:orange",
53
+ )
54
+
55
+ ax.set_xlabel("Epoch", fontsize=style.label_size)
56
+ ax.set_ylabel("Weighted Loss", fontsize=style.label_size)
57
+ ax.set_title(title, fontsize=style.title_size)
58
+ ax.tick_params(axis="both", labelsize=style.tick_size)
59
+ if style.grid:
60
+ ax.grid(True, linestyle=style.grid_style, alpha=style.grid_alpha)
61
+ ax.legend(loc="best", fontsize=style.legend_size, frameon=False)
62
+
63
+ if created_fig:
64
+ finalize_figure(fig, save_path=save_path, show=show, style=style)
65
+
66
+ return fig
67
+
68
+
69
+ def plot_oneway(
70
+ df: pd.DataFrame,
71
+ *,
72
+ feature: str,
73
+ weight_col: str,
74
+ target_col: str,
75
+ pred_col: Optional[str] = None,
76
+ pred_weighted: bool = False,
77
+ pred_label: Optional[str] = None,
78
+ n_bins: int = 10,
79
+ is_categorical: bool = False,
80
+ title: Optional[str] = None,
81
+ ax: Optional[plt.Axes] = None,
82
+ show: bool = False,
83
+ save_path: Optional[str] = None,
84
+ style: Optional[PlotStyle] = None,
85
+ ) -> Optional[plt.Figure]:
86
+ if feature not in df.columns:
87
+ raise KeyError(f"feature '{feature}' not found in data.")
88
+ if weight_col not in df.columns:
89
+ raise KeyError(f"weight_col '{weight_col}' not found in data.")
90
+ if target_col not in df.columns:
91
+ raise KeyError(f"target_col '{target_col}' not found in data.")
92
+ if pred_col is not None and pred_col not in df.columns:
93
+ raise KeyError(f"pred_col '{pred_col}' not found in data.")
94
+
95
+ style = style or PlotStyle()
96
+ title = title or f"Analysis of {feature}"
97
+
98
+ if is_categorical:
99
+ group_col = feature
100
+ plot_source = df
101
+ else:
102
+ group_col = f"{feature}_bins"
103
+ series = pd.to_numeric(df[feature], errors="coerce")
104
+ try:
105
+ bins = pd.qcut(series, n_bins, duplicates="drop")
106
+ except ValueError:
107
+ bins = pd.cut(series, bins=max(1, int(n_bins)), duplicates="drop")
108
+ plot_source = df.assign(**{group_col: bins})
109
+
110
+ if pred_col is not None:
111
+ if pred_weighted:
112
+ plot_source = plot_source.assign(_pred_w=plot_source[pred_col])
113
+ else:
114
+ plot_source = plot_source.assign(
115
+ _pred_w=plot_source[pred_col] * plot_source[weight_col]
116
+ )
117
+
118
+ plot_data = plot_source.groupby([group_col], observed=True).sum(numeric_only=True)
119
+ plot_data.reset_index(inplace=True)
120
+
121
+ denom = np.maximum(plot_data[weight_col].to_numpy(dtype=float), EPS)
122
+ plot_data["act_v"] = plot_data[target_col].to_numpy(dtype=float) / denom
123
+ if pred_col is not None:
124
+ plot_data["pred_v"] = plot_data["_pred_w"].to_numpy(dtype=float) / denom
125
+
126
+ created_fig = ax is None
127
+ if created_fig:
128
+ fig, ax = plt.subplots(figsize=style.figsize)
129
+ else:
130
+ fig = ax.figure
131
+
132
+ ax.plot(plot_data.index, plot_data["act_v"], label="Actual", color="red")
133
+ if pred_col is not None:
134
+ ax.plot(
135
+ plot_data.index,
136
+ plot_data["pred_v"],
137
+ label=pred_label or "Predicted",
138
+ color=style.palette[0],
139
+ )
140
+ ax.set_title(title, fontsize=style.title_size)
141
+ ax.set_xticks(plot_data.index)
142
+ labels = plot_data[group_col].astype(str).tolist()
143
+ tick_size = 3 if len(labels) > 50 else style.tick_size
144
+ ax.set_xticklabels(labels, rotation=90, fontsize=tick_size)
145
+ ax.tick_params(axis="y", labelsize=style.tick_size)
146
+ if style.grid:
147
+ ax.grid(True, linestyle=style.grid_style, alpha=style.grid_alpha)
148
+ if pred_col is not None:
149
+ ax.legend(fontsize=style.legend_size)
150
+
151
+ ax2 = ax.twinx()
152
+ ax2.bar(
153
+ plot_data.index,
154
+ plot_data[weight_col],
155
+ alpha=0.5,
156
+ color=style.weight_color,
157
+ )
158
+ ax2.tick_params(axis="y", labelsize=style.tick_size)
159
+
160
+ if created_fig:
161
+ finalize_figure(fig, save_path=save_path, show=show, style=style)
162
+
163
+ return fig