ins-pricing 0.4.5__py3-none-any.whl → 0.5.0__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 (84) hide show
  1. ins_pricing/README.md +48 -22
  2. ins_pricing/__init__.py +142 -90
  3. ins_pricing/cli/BayesOpt_entry.py +52 -50
  4. ins_pricing/cli/BayesOpt_incremental.py +39 -105
  5. ins_pricing/cli/Explain_Run.py +31 -23
  6. ins_pricing/cli/Explain_entry.py +532 -579
  7. ins_pricing/cli/Pricing_Run.py +31 -23
  8. ins_pricing/cli/bayesopt_entry_runner.py +11 -9
  9. ins_pricing/cli/utils/cli_common.py +256 -256
  10. ins_pricing/cli/utils/cli_config.py +375 -375
  11. ins_pricing/cli/utils/import_resolver.py +382 -365
  12. ins_pricing/cli/utils/notebook_utils.py +340 -340
  13. ins_pricing/cli/watchdog_run.py +209 -201
  14. ins_pricing/frontend/__init__.py +10 -10
  15. ins_pricing/frontend/example_workflows.py +1 -1
  16. ins_pricing/governance/__init__.py +20 -20
  17. ins_pricing/governance/release.py +159 -159
  18. ins_pricing/modelling/__init__.py +147 -92
  19. ins_pricing/modelling/{core/bayesopt → bayesopt}/README.md +2 -2
  20. ins_pricing/modelling/{core/bayesopt → bayesopt}/__init__.py +64 -102
  21. ins_pricing/modelling/{core/bayesopt → bayesopt}/config_preprocess.py +562 -562
  22. ins_pricing/modelling/{core/bayesopt → bayesopt}/core.py +965 -964
  23. ins_pricing/modelling/{core/bayesopt → bayesopt}/model_explain_mixin.py +296 -296
  24. ins_pricing/modelling/{core/bayesopt → bayesopt}/model_plotting_mixin.py +482 -548
  25. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/__init__.py +27 -27
  26. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_ft_trainer.py +915 -913
  27. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_gnn.py +788 -785
  28. ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_resn.py +448 -446
  29. ins_pricing/modelling/bayesopt/trainers/__init__.py +19 -0
  30. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_base.py +1308 -1308
  31. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_ft.py +3 -3
  32. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_glm.py +197 -198
  33. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_gnn.py +344 -344
  34. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_resn.py +283 -283
  35. ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_xgb.py +346 -347
  36. ins_pricing/modelling/bayesopt/utils/__init__.py +67 -0
  37. ins_pricing/modelling/bayesopt/utils/constants.py +21 -0
  38. ins_pricing/modelling/bayesopt/utils/io_utils.py +7 -0
  39. ins_pricing/modelling/bayesopt/utils/losses.py +27 -0
  40. ins_pricing/modelling/bayesopt/utils/metrics_and_devices.py +17 -0
  41. ins_pricing/modelling/{core/bayesopt → bayesopt}/utils/torch_trainer_mixin.py +623 -623
  42. ins_pricing/modelling/{core/evaluation.py → evaluation.py} +113 -104
  43. ins_pricing/modelling/explain/__init__.py +55 -55
  44. ins_pricing/modelling/explain/metrics.py +27 -174
  45. ins_pricing/modelling/explain/permutation.py +237 -237
  46. ins_pricing/modelling/plotting/__init__.py +40 -36
  47. ins_pricing/modelling/plotting/compat.py +228 -0
  48. ins_pricing/modelling/plotting/curves.py +572 -572
  49. ins_pricing/modelling/plotting/diagnostics.py +163 -163
  50. ins_pricing/modelling/plotting/geo.py +362 -362
  51. ins_pricing/modelling/plotting/importance.py +121 -121
  52. ins_pricing/pricing/__init__.py +27 -27
  53. ins_pricing/production/__init__.py +35 -25
  54. ins_pricing/production/{predict.py → inference.py} +140 -57
  55. ins_pricing/production/monitoring.py +8 -21
  56. ins_pricing/reporting/__init__.py +11 -11
  57. ins_pricing/setup.py +1 -1
  58. ins_pricing/tests/production/test_inference.py +90 -0
  59. ins_pricing/utils/__init__.py +116 -83
  60. ins_pricing/utils/device.py +255 -255
  61. ins_pricing/utils/features.py +53 -0
  62. ins_pricing/utils/io.py +72 -0
  63. ins_pricing/{modelling/core/bayesopt/utils → utils}/losses.py +125 -129
  64. ins_pricing/utils/metrics.py +158 -24
  65. ins_pricing/utils/numerics.py +76 -0
  66. ins_pricing/utils/paths.py +9 -1
  67. {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.0.dist-info}/METADATA +182 -182
  68. ins_pricing-0.5.0.dist-info/RECORD +131 -0
  69. ins_pricing/modelling/core/BayesOpt.py +0 -146
  70. ins_pricing/modelling/core/__init__.py +0 -1
  71. ins_pricing/modelling/core/bayesopt/trainers/__init__.py +0 -19
  72. ins_pricing/modelling/core/bayesopt/utils/__init__.py +0 -86
  73. ins_pricing/modelling/core/bayesopt/utils/constants.py +0 -183
  74. ins_pricing/modelling/core/bayesopt/utils/io_utils.py +0 -126
  75. ins_pricing/modelling/core/bayesopt/utils/metrics_and_devices.py +0 -555
  76. ins_pricing/modelling/core/bayesopt/utils.py +0 -105
  77. ins_pricing/modelling/core/bayesopt/utils_backup.py +0 -1503
  78. ins_pricing/tests/production/test_predict.py +0 -233
  79. ins_pricing-0.4.5.dist-info/RECORD +0 -130
  80. /ins_pricing/modelling/{core/bayesopt → bayesopt}/config_components.py +0 -0
  81. /ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_ft_components.py +0 -0
  82. /ins_pricing/modelling/{core/bayesopt → bayesopt}/utils/distributed_utils.py +0 -0
  83. {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.0.dist-info}/WHEEL +0 -0
  84. {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.0.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