towardsinnovationlab commited on
Commit
b57ed0b
·
verified ·
1 Parent(s): 7d02eff

Delete pages/LLM_Trial_1.py

Browse files
Files changed (1) hide show
  1. pages/LLM_Trial_1.py +0 -1088
pages/LLM_Trial_1.py DELETED
@@ -1,1088 +0,0 @@
1
-
2
- import os
3
- import random
4
- import numpy as np
5
- import pandas as pd
6
- import matplotlib.pyplot as plt
7
- import matplotlib.image as mpimg
8
- import seaborn as sns
9
- from matplotlib.pyplot import subplots
10
- from sklearn.model_selection import train_test_split
11
- from sklearn.model_selection import KFold
12
- from sklearn.metrics import mean_poisson_deviance, mean_gamma_deviance, make_scorer
13
- from scipy.stats import ks_2samp
14
- from sklearn.decomposition import PCA
15
- from sklearn.preprocessing import StandardScaler
16
- from mpl_toolkits.mplot3d import Axes3D
17
- from sklearn.linear_model import TweedieRegressor
18
- import shap
19
- from sklearn.mixture import GaussianMixture
20
- from joblib import dump
21
- from joblib import load
22
- import streamlit as st
23
-
24
- import warnings
25
- warnings.filterwarnings('ignore')
26
-
27
-
28
- DEFAULT_RANDOM_SEED = 0 # Set a random seed for reproducibility throughout Python, NumPy, and TensorFlow operations
29
- random.seed(DEFAULT_RANDOM_SEED)
30
- os.environ['PYTHONHASHSEED'] = str(DEFAULT_RANDOM_SEED)
31
- np.random.seed(DEFAULT_RANDOM_SEED)
32
-
33
- # Title
34
- st.title("Large Language Model GPT-5.1: Synthetic Data Generation Analysis")
35
-
36
-
37
- def compare_real_vs_synthetic(real_df, synthetic_df, columns=None, kind='hist', bins=30, figsize=(15, 10)):
38
- """
39
- Compare distributions between real and synthetic datasets.
40
-
41
- Parameters:
42
- - real_df: pd.DataFrame, the original dataset
43
- - synthetic_df: pd.DataFrame, the synthetic dataset
44
- - columns: list of column names to compare; if None, all columns are used
45
- - kind: str, type of plot: 'hist', 'kde', or 'box'
46
- - bins: int, number of bins for histograms
47
- - figsize: tuple, size of the plot figure
48
-
49
- Returns:
50
- - None (displays plots)
51
- """
52
- if columns is None:
53
- columns = [col for col in real_df.columns if real_df[col].dtype != 'object']
54
-
55
- n_cols = 2
56
- n_rows = (len(columns) + 1) // n_cols
57
-
58
- fig= plt.figure(figsize=figsize)
59
-
60
- for idx, col in enumerate(columns, 1):
61
- plt.subplot(n_rows, n_cols, idx)
62
-
63
- if kind == 'hist':
64
- sns.histplot(real_df[col], color='blue', label='Real', kde=False, stat='density', bins=bins, alpha=0.6)
65
- sns.histplot(synthetic_df[col], color='red', label='Synthetic', kde=False, stat='density', bins=bins, alpha=0.6)
66
-
67
- elif kind == 'kde':
68
- sns.kdeplot(real_df[col], color='blue', label='Real')
69
- sns.kdeplot(synthetic_df[col], color='red', label='Synthetic')
70
-
71
- elif kind == 'box':
72
- sns.boxplot(data=[real_df[col], synthetic_df[col]], palette=['blue', 'red'])
73
- plt.xticks([0, 1], ['Real', 'Synthetic'])
74
-
75
- else:
76
- raise ValueError("Unsupported plot kind. Choose from 'hist', 'kde', or 'box'.")
77
-
78
- plt.title(f"Comparison for '{col}'")
79
- plt.legend()
80
-
81
- plt.tight_layout()
82
- st.pyplot(fig)
83
-
84
-
85
- def run_glm_frequency_analysis(
86
- X_train, X_test, model=None, clip_exposure=False, random_state=0, label="Model", var=None):
87
- """
88
- Run GLM Poisson regression frequency analysis (ClaimNb ~ Features | Exposure).
89
-
90
- Parameters:
91
- - X_train: pd.DataFrame with ['Exposure', 'ClaimNb', ...]
92
- - X_test: pd.DataFrame with ['Exposure', 'ClaimNb', ...]
93
- - model: sklearn regressor, default is TweedieRegressor(power=1, link='log')
94
- - clip_exposure: bool, if True, caps Exposure at 1 in training set
95
- - random_state: int, for reproducibility
96
- - label: str, label for printing/logging
97
-
98
- Returns:
99
- - trained_model: fitted model
100
- - results: dict with CV scores, deviance on train/test, and predictions
101
- """
102
-
103
- np.random.seed(0)
104
-
105
- # Optionally clip exposure in training data
106
- if clip_exposure:
107
- X_train = X_train.copy()
108
- X_train['Exposure'] = np.where(X_train['Exposure'] > 1, 1, X_train['Exposure'])
109
-
110
- # Filter for Exposure > 0
111
- mask_tr = X_train['Exposure'] > 0
112
- mask_te = X_test['Exposure'] > 0
113
- X_train_f = X_train[mask_tr].copy()
114
- X_test_f = X_test[mask_te].copy()
115
-
116
- y_train = X_train_f['ClaimNb']
117
- y_test = X_test_f['ClaimNb']
118
- exposure_train = X_train_f['Exposure']
119
- exposure_test = X_test_f['Exposure']
120
-
121
- X_train_ = X_train_f.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
122
- X_test_ = X_test_f.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
123
-
124
- # Set model if not passed
125
- if model is None:
126
- model = TweedieRegressor(power=1, link='log')
127
-
128
- # Cross-validation
129
- cv = KFold(n_splits=5)
130
- mpd_scores = []
131
-
132
- for fold_idx, (train_idx, val_idx) in enumerate(cv.split(X_train_)):
133
- X_tr, X_val = X_train_.iloc[train_idx], X_train_.iloc[val_idx]
134
- y_tr, y_val = y_train.iloc[train_idx], y_train.iloc[val_idx]
135
- w_tr, w_val = exposure_train.iloc[train_idx], exposure_train.iloc[val_idx]
136
-
137
- model.fit(X_tr, y_tr / w_tr, sample_weight=w_tr)
138
- y_pred = model.predict(X_val)
139
-
140
- score = mean_poisson_deviance(y_val / w_val, y_pred)
141
- #st.write(f"Fold {fold_idx + 1} Poisson Deviance Score: {score:.4f}")
142
- mpd_scores.append(score)
143
-
144
- #st.write(f"Average cross-validation Poisson Deviance Score: {np.mean(mpd_scores):.4f}")
145
- #st.write(f"Standard Deviation of CV Scores: {np.std(mpd_scores):.4f}")
146
-
147
- # Final fit on full training set
148
- model.fit(X_train_, y_train / exposure_train, sample_weight=exposure_train)
149
-
150
- pred_train = model.predict(X_train_)
151
- pred_test = model.predict(X_test_)
152
-
153
- mpd_train = mean_poisson_deviance(y_train / exposure_train, pred_train)
154
- mpd_test = mean_poisson_deviance(y_test / exposure_test, pred_test)
155
-
156
- st.write(f"Train Poisson {var} Deviance: {mpd_train:.4f}")
157
- st.write(f"Test Poisson {var} Deviance: {mpd_test:.4f}")
158
-
159
- return model, {
160
- "cv_scores": mpd_scores,
161
- "mpd_train": mpd_train,
162
- "mpd_test": mpd_test,
163
- "train_predictions": pred_train,
164
- "test_predictions": pred_test
165
- }
166
-
167
-
168
- def run_glm_cost_analysis(X_train, X_test, is_sampled=False, verbose=True, var=None):
169
- """
170
- Perform GLM Cost Analysis using Tweedie Regressor (power=2, link='log').
171
-
172
- Parameters:
173
- - X_train: Training DataFrame (must include 'ClaimAmount', 'ClaimNb', 'Exposure')
174
- - X_test: Testing DataFrame
175
- - is_sampled: If True, cap 'Exposure' at 1 for training data
176
- - verbose: If True, print CV results and scores
177
-
178
- Returns:
179
- - Dictionary containing train/test gamma deviance and predictions
180
- """
181
-
182
- np.random.seed(0)
183
-
184
- # Cap exposure if sampled
185
- if is_sampled:
186
- X_train = X_train.copy()
187
- X_train['Exposure'] = np.where(X_train['Exposure'] > 1, 1, X_train['Exposure'])
188
-
189
- X_train_co = X_train.copy()
190
- X_test_co = X_test.copy()
191
-
192
- # Compute average cost per claim (Acost)
193
- X_train_co['Acost'] = np.where(X_train_co['ClaimNb'] != 0,
194
- X_train_co['ClaimAmount'] / X_train_co['ClaimNb'], 0)
195
- X_test_co['Acost'] = np.where(X_test_co['ClaimNb'] != 0,
196
- X_test_co['ClaimAmount'] / X_test_co['ClaimNb'], 0)
197
-
198
- # Filter rows with non-zero claim amounts
199
- X_train_cost = X_train_co[X_train_co['ClaimAmount'] != 0].copy()
200
- X_test_cost = X_test_co[X_test_co['ClaimAmount'] != 0].copy()
201
-
202
- # Target and weights
203
- y_train = X_train_cost['Acost']
204
- claim_tr = X_train_cost['ClaimNb']
205
- y_test = X_test_cost['Acost']
206
- claim_te = X_test_cost['ClaimNb']
207
-
208
- # Features
209
- drop_cols = ['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb']
210
- X_train_ = X_train_cost.drop(columns=drop_cols)
211
- X_test_ = X_test_cost.drop(columns=drop_cols)
212
-
213
- # Initialize model
214
- glm_cl = TweedieRegressor(power=2, link='log')
215
-
216
- # Cross-validation
217
- cv = KFold(n_splits=5, shuffle=True, random_state=0)
218
- mgd_scores = []
219
-
220
- for fold_idx, (train_idx, val_idx) in enumerate(cv.split(X_train_)):
221
- X_tr, X_val = X_train_.iloc[train_idx], X_train_.iloc[val_idx]
222
- y_tr, y_val = y_train.iloc[train_idx], y_train.iloc[val_idx]
223
- w_tr, w_val = claim_tr.iloc[train_idx], claim_tr.iloc[val_idx]
224
-
225
- glm_cl.fit(X_tr, y_tr, sample_weight=w_tr)
226
- y_pred_val = glm_cl.predict(X_val)
227
- score = mean_gamma_deviance(y_val, y_pred_val)
228
- mgd_scores.append(score)
229
-
230
- #if verbose:
231
- # print(f"Fold {fold_idx + 1} Gamma Deviance Score: {score:.4f}")
232
-
233
- #if verbose:
234
- # print("Average cross-validation Gamma Deviance Score:", np.mean(mgd_scores))
235
- # print("Standard Deviation of CV Scores:", np.std(mgd_scores))
236
-
237
- # Train on full data
238
- glm_cl.fit(X_train_, y_train, sample_weight=claim_tr)
239
-
240
- # Predictions
241
- y_pred_train = glm_cl.predict(X_train_)
242
- y_pred_test = glm_cl.predict(X_test_)
243
-
244
- # Deviance on train and test
245
- mgd_train = mean_gamma_deviance(y_train, y_pred_train)
246
- mgd_test = mean_gamma_deviance(y_test, y_pred_test)
247
-
248
- if verbose:
249
- st.write(f"Train Gamma {var} Deviance: {mgd_train:.4f}")
250
- st.write(f"Test Gamma {var} Deviance: {mgd_test:.4f}")
251
-
252
- return {
253
- "cv_scores": mgd_scores,
254
- 'mgd_train': mgd_train,
255
- 'mgd_test': mgd_test,
256
- 'y_pred_train': y_pred_train,
257
- 'y_pred_test': y_pred_test
258
- }
259
-
260
-
261
- def plot_glm_shap_importance(
262
- X_train, X_test, y_train, sample_weight,
263
- power: int, title: str, max_display: int = 10, figsize: tuple = (5, 5), seed: int = 0):
264
- """
265
- Compute and plot SHAP feature importance for GLMs using SHAP LinearExplainer.
266
-
267
- Parameters:
268
- X_train (pd.DataFrame): Training features
269
- X_test (pd.DataFrame): Test features
270
- y_train (pd.Series or np.array): Training target
271
- sample_weight (pd.Series or np.array): Sample weights
272
- power (int): Tweedie power (1 = Poisson for frequency, 2 = Gamma for severity)
273
- title (str): Title for the plot
274
- max_display (int): Max number of features to display
275
- figsize (tuple): Size of the figure
276
- seed (int): Random seed for reproducibility
277
- """
278
-
279
- np.random.seed(seed)
280
-
281
- model = TweedieRegressor(power=power, link='log')
282
- model.fit(X_train, y_train, sample_weight=sample_weight)
283
-
284
- masker = shap.maskers.Independent(X_train)
285
- explainer = shap.LinearExplainer(model, masker=masker)
286
- shap_values = explainer.shap_values(X_test)
287
-
288
- plt.figure(figsize=figsize)
289
- shap.summary_plot(
290
- shap_values, features=X_test,
291
- feature_names=X_test.columns,
292
- plot_type='bar',
293
- max_display=max_display,
294
- show=False
295
- )
296
- plt.title(title, fontsize=12)
297
- plt.tight_layout()
298
- fig = plt.gcf()
299
- st.pyplot(fig)
300
-
301
-
302
- # ### Upload datasets
303
-
304
- #-------------------
305
- # DATASETS
306
- #-------------------
307
- df1=pd.read_csv('./data/ausprivauto0405.csv')
308
- df2=pd.read_csv('./data/swmotorcycle.csv')
309
- df1_synth=pd.read_csv('./LLM/synthetic_nonlife_53320_D1_80.csv')
310
- #df1_synth = df1_synth.drop(columns=["Unnamed: 0"])
311
- df2_synth=pd.read_csv('./LLM/synthetic_nonlife_51638_D2_80.csv')
312
- #df2_synth = df2_synth.drop(columns=["Unnamed: 0"])
313
-
314
-
315
-
316
- # ### dataset 1 and data handling
317
-
318
- st.header('Dataset 1: ausprivauto0405')
319
-
320
- df1_duplicated_rows=df1[df1.duplicated()]
321
- df1=df1.drop_duplicates()
322
- df1_duplicated_col=df1.columns[df1.columns.duplicated()]
323
-
324
-
325
- # ### Encoding
326
-
327
- df1_encod=df1.copy()
328
- # VehAge
329
- VehAge_group = {'old cars':'1','young cars':'2','oldest cars':'3','youngest cars':'4'}
330
- df1_encod['VehAge'] = df1_encod['VehAge'].map(VehAge_group)
331
- df1_encod['VehAge']= df1_encod['VehAge'].astype(int)
332
- # DrivAge
333
- DrivAge_group = {'young people':'1','older work. people':'2','oldest people':'3','working people':'4','old people':'5','youngest people':'6'}
334
- df1_encod['DrivAge'] = df1_encod['DrivAge'].map(DrivAge_group)
335
- df1_encod['DrivAge']= df1_encod['DrivAge'].astype(int)
336
- # VehBody
337
- VehBody_group = {'Hatchback':'1','Utility':'2','Station wagon':'3','Hardtop':'4','Panel van':'5','Sedan':'6','Truck':'7',\
338
- 'Coupe':'8', 'Minibus':'9', 'Motorized caravan':'10', 'Bus':'11', 'Convertible':'12','Roadster':'13'}
339
- df1_encod['VehBody'] = df1_encod['VehBody'].map(VehBody_group)
340
- df1_encod['VehBody']= df1_encod['VehBody'].astype(int)
341
- # Gender
342
- Gender_group = {'Female':'0','Male':'1'}
343
- df1_encod['Gender'] = df1_encod['Gender'].map(Gender_group)
344
- df1_encod['Gender']= df1_encod['Gender'].astype(int)
345
-
346
-
347
-
348
-
349
- # ### Split dataset
350
- # Split the dataset into train/test split
351
- X_train, X_test = train_test_split(df1_encod, test_size=0.2, random_state=0)
352
- st.markdown(f"**Train shape:** {X_train.shape} \n**Test shape:** {X_test.shape}")
353
-
354
-
355
- # ### Use Generate Samples Dataframe
356
- df1_synth_encod=df1_synth.copy()
357
- # VehAge
358
- VehAge_group = {'old cars':'1','young cars':'2','oldest cars':'3','youngest cars':'4'}
359
- df1_synth_encod['VehAge'] = df1_synth_encod['VehAge'].map(VehAge_group)
360
- df1_synth_encod['VehAge']= df1_synth_encod['VehAge'].astype(int)
361
- # DrivAge
362
- DrivAge_group = {'young people':'1','older work. people':'2','oldest people':'3','working people':'4','old people':'5','youngest people':'6'}
363
- df1_synth_encod['DrivAge'] = df1_synth_encod['DrivAge'].map(DrivAge_group)
364
- df1_synth_encod['DrivAge']= df1_synth_encod['DrivAge'].astype(int)
365
- # VehBody
366
- VehBody_group = {'Hatchback':'1','Utility':'2','Station wagon':'3','Hardtop':'4','Panel van':'5','Sedan':'6','Truck':'7',\
367
- 'Coupe':'8', 'Minibus':'9', 'Motorized caravan':'10', 'Bus':'11', 'Convertible':'12','Roadster':'13'}
368
- df1_synth_encod['VehBody'] = df1_synth_encod['VehBody'].map(VehBody_group)
369
- df1_synth_encod['VehBody']= df1_synth_encod['VehBody'].astype(int)
370
- # Gender
371
- Gender_group = {'Female':'0','Male':'1'}
372
- df1_synth_encod['Gender'] = df1_synth_encod['Gender'].map(Gender_group)
373
- df1_synth_encod['Gender']= df1_synth_encod['Gender'].astype(int)
374
-
375
-
376
- new_samples_df=df1_synth_encod.copy()
377
-
378
- # Check consistency
379
- st.subheader(f"Check consistency")
380
- # Find inconsistencies
381
- inconsistent_records = new_samples_df[
382
- ~(((new_samples_df["ClaimNb"] == 0) & (new_samples_df["ClaimOcc"] == 0) & (new_samples_df["ClaimAmount"] == 0)) |
383
- ((new_samples_df["ClaimNb"] > 0) & (new_samples_df["ClaimOcc"] > 0) & (new_samples_df["ClaimAmount"] > 0)))
384
- ]
385
-
386
- st.write(f"Number of inconsistent records on synthetic data: {len(inconsistent_records)}")
387
- st.write(inconsistent_records.head()) # Show a few inconsistent rows
388
- st.write('Helps assess basic data fidelity by checking structural or logical violations.')
389
-
390
-
391
- # ### Visual Comparison
392
-
393
- # Compare selected variables using histograms
394
- st.subheader(f"Univariate distribution comparison: real vs synthetic")
395
- st.write('Shows how well each individual feature is mimicked by the synthetic data.')
396
-
397
- compare_real_vs_synthetic(
398
- real_df=X_train,
399
- synthetic_df=df1_synth,
400
- columns=['Exposure','VehBody','VehValue','ClaimOcc','ClaimNb', 'ClaimAmount', 'DrivAge', 'VehAge','Gender'],
401
- kind='hist'
402
- )
403
-
404
-
405
- st.subheader(f"Correlation matrix comparison: real vs synthetic")
406
- st.write('Evaluates preservation of feature-to-feature relationships.')
407
-
408
- # Compute correlation matrices
409
- corr_matrix_X_train = X_train.corr()
410
- corr_matrix_new_samples = new_samples_df.corr()
411
-
412
- # Set figure size
413
- fig=plt.figure(figsize=(30,15))
414
-
415
- # a subplot grid
416
- # Parameters (1, 2, 1) implies 1 row, 2 columns, and this plot is the 1st plot.
417
- plt.subplot(1, 2, 1) # Subplot 1
418
- sns.heatmap(corr_matrix_X_train, square=True, annot=True, cmap='coolwarm', fmt='.2f',annot_kws={"size": 15})
419
- plt.title('Correlation Heatmap of X_train', size=15)
420
- plt.yticks(rotation=0,fontsize=15)
421
- plt.xticks(rotation=90,fontsize=15)
422
-
423
- # another subplot for the second heatmap
424
- plt.subplot(1, 2, 2) # Subplot 2
425
- sns.heatmap(corr_matrix_new_samples, square=True, annot=True, cmap='coolwarm', fmt='.2f',annot_kws={"size": 15})
426
- plt.title('Correlation Heatmap of New Samples', size=15)
427
- plt.yticks(rotation=0,fontsize=15)
428
- plt.xticks(rotation=90,fontsize=15)
429
-
430
- # Display the plot
431
- plt.tight_layout()
432
- st.pyplot(fig)
433
-
434
- # ### Statistical Analysis
435
- # Kolmogorov-Smirnov test
436
- st.subheader("Kolmogorov–Smirnov Test Results")
437
- st.write('Quantifies the statistical distance between real and synthetic distributions.')
438
-
439
- results = []
440
-
441
- for column in X_train.columns:
442
- original = X_train[column].values
443
- generated = new_samples_df[column].values
444
- statistic, p_value = ks_2samp(original, generated)
445
-
446
- results.append({
447
- "Feature": column,
448
- "KS Statistic": statistic,
449
- "P-value": p_value
450
- })
451
-
452
- results_df = pd.DataFrame(results)
453
-
454
- def color_pval(val):
455
- color = "red" if val < 0.05 else "green"
456
- return f"color: {color};"
457
-
458
- styled_df = results_df.style.applymap(color_pval, subset=["P-value"]) \
459
- .format({"KS Statistic": "{:.4f}", "P-value": "{:.4f}"})
460
-
461
- st.markdown("""
462
- **Legend:**
463
- - <span style='color:green;'>Green P-value</span>: distributions are **similar** (p ≥ 0.05)
464
- - <span style='color:red;'>Red P-value</span>: distributions are **significantly different** (p < 0.05)
465
- """, unsafe_allow_html=True)
466
- st.dataframe(styled_df)
467
-
468
-
469
- # ### PCA Analysis
470
-
471
- st.subheader('PCA comparison')
472
- st.write('Assesses similarity in global variance structure and major latent components.')
473
- # Load the saved models
474
- img = mpimg.imread('./LLM/pca_d1_80.png')
475
- fig=plt.figure(figsize=(10, 8))
476
- plt.imshow(img)
477
- plt.axis('off')
478
- st.pyplot(fig)
479
-
480
-
481
-
482
- # ### UMAP Analysis
483
-
484
- st.subheader('UMAP comparison')
485
- st.write('Examines nonlinear manifold structure and clustering behavior.')
486
- img = mpimg.imread('./LLM/umap_d1_80.png')
487
- fig=plt.figure(figsize=(10, 8))
488
- plt.imshow(img)
489
- plt.axis('off')
490
- st.pyplot(fig)
491
-
492
-
493
- # ### GLM Frequency Analysis
494
- st.subheader('Frequency GLM Analysis')
495
- st.write('Tests how well synthetic data preserves predictive relationships for claim frequency.')
496
- # Baseline frequency model
497
- results_frequency_1 = run_glm_frequency_analysis(X_train, X_test, label="Baseline", var='Real')
498
- # Using synthetic sample data with exposure clipping
499
- results_frequency_2 = run_glm_frequency_analysis(new_samples_df, X_test, clip_exposure=True, label="Synthetic Clipped",var= 'Synthetic')
500
-
501
-
502
- # ### GLM Cost Analysis
503
- st.subheader('Severity GLM Analysis')
504
- st.write('Evaluates whether severity-related predictors behave similarly on real and synthetic data.')
505
- results_cost_1 = run_glm_cost_analysis(X_train, X_test,var='Real')
506
- results_cost_2 = run_glm_cost_analysis(new_samples_df, X_test, is_sampled=True,var='Synthetic')
507
-
508
-
509
- # ### Feature Importance Analysis
510
- # --- SHAP Feature Importance for Frequency ---
511
- st.subheader('SHAP Feature Importance for Frequency Model')
512
- st.write('Shows whether drivers of frequency predictions remain consistent across datasets.')
513
- # Prepare data for frequency model SHAP
514
- X_train_freq = X_train.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
515
- y_train_freq = X_train['ClaimNb']
516
- sample_weight_freq = X_train['Exposure']
517
-
518
- X_test_freq = X_test.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
519
-
520
- # Filter out rows with Exposure = 0 for frequency model training and SHAP explanation
521
- mask_train_freq = sample_weight_freq > 0
522
- X_train_freq_filtered = X_train_freq[mask_train_freq]
523
- y_train_freq_filtered = y_train_freq[mask_train_freq]
524
- sample_weight_freq_filtered = sample_weight_freq[mask_train_freq]
525
-
526
- # Ensure X_test_freq also only contains rows where Exposure > 0
527
- mask_test_freq = X_test['Exposure'] > 0
528
- X_test_freq_filtered = X_test_freq[mask_test_freq]
529
-
530
-
531
- # Plot SHAP for Frequency
532
- plot_glm_shap_importance(
533
- X_train=X_train_freq_filtered,
534
- X_test=X_test_freq_filtered,
535
- y_train=y_train_freq_filtered / sample_weight_freq_filtered, # Target is rate (ClaimNb / Exposure)
536
- sample_weight=sample_weight_freq_filtered,
537
- power=1, # Power=1 for Poisson (frequency)
538
- title="SHAP Feature Importance for Frequency Model (Real Data)",
539
- max_display=10
540
- )
541
-
542
- # --- SHAP Feature Importance for Frequency (Synthetic Data) ---
543
- # Prepare data for frequency model SHAP using synthetic data
544
- X_train_freq_synth = new_samples_df.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
545
- y_train_freq_synth = new_samples_df['ClaimNb']
546
- sample_weight_freq_synth = new_samples_df['Exposure']
547
-
548
- # X_test_freq is the same as before (real test data)
549
- X_test_freq = X_test.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
550
-
551
- # Filter out rows with Exposure = 0 for frequency model training and SHAP explanation
552
- mask_train_freq_synth = sample_weight_freq_synth > 0
553
- X_train_freq_synth_filtered = X_train_freq_synth[mask_train_freq_synth]
554
- y_train_freq_synth_filtered = y_train_freq_synth[mask_train_freq_synth]
555
- sample_weight_freq_synth_filtered = sample_weight_freq_synth[mask_train_freq_synth]
556
-
557
- # Ensure X_test_freq also only contains rows where Exposure > 0
558
- mask_test_freq = X_test['Exposure'] > 0
559
- X_test_freq_filtered = X_test_freq[mask_test_freq]
560
-
561
- # Plot SHAP for Frequency (Synthetic Data)
562
- plot_glm_shap_importance(
563
- X_train=X_train_freq_synth_filtered,
564
- X_test=X_test_freq_filtered,
565
- y_train=y_train_freq_synth_filtered / sample_weight_freq_synth_filtered, # Target is rate
566
- sample_weight=sample_weight_freq_synth_filtered,
567
- power=1, # Power=1 for Poisson (frequency)
568
- title="SHAP Feature Importance for Frequency Model (Synthetic Data)",
569
- max_display=10
570
- )
571
-
572
- # --- SHAP Feature Importance for Severity ---
573
- st.subheader('SHAP Feature Importance for Severity Model')
574
- st.write('Assesses stability of model explanations for severity outcomes.')
575
-
576
- # Prepare data for severity model SHAP
577
- X_train_cost_prep = X_train[X_train['ClaimAmount'] != 0].copy()
578
- X_test_cost_prep = X_test[X_test['ClaimAmount'] != 0].copy()
579
-
580
- X_train_sev = X_train_cost_prep.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
581
- y_train_sev = X_train_cost_prep['ClaimAmount'] / X_train_cost_prep['ClaimNb']
582
- sample_weight_sev = X_train_cost_prep['ClaimNb'] # Number of claims is the weight for severity
583
-
584
- X_test_sev = X_test_cost_prep.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
585
-
586
- # Plot SHAP for Severity
587
- plot_glm_shap_importance(
588
- X_train=X_train_sev,
589
- X_test=X_test_sev,
590
- y_train=y_train_sev,
591
- sample_weight=sample_weight_sev,
592
- power=2, # Power=2 for Gamma (severity)
593
- title="SHAP Feature Importance for Severity Model (Real Data)",
594
- max_display=10
595
- )
596
-
597
-
598
- # --- SHAP Feature Importance for Severity (Synthetic Data) ---
599
- # Prepare data for severity model SHAP using synthetic data
600
- X_train_cost_prep_synth = new_samples_df[new_samples_df['ClaimAmount'] != 0].copy()
601
- X_test_cost_prep_synth = X_test[X_test['ClaimAmount'] != 0].copy() # Keep using real test data for explanation
602
-
603
- X_train_sev_synth = X_train_cost_prep_synth.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
604
- y_train_sev_synth = X_train_cost_prep_synth['ClaimAmount'] / X_train_cost_prep_synth['ClaimNb']
605
- sample_weight_sev_synth = X_train_cost_prep_synth['ClaimNb'] # Number of claims is the weight for severity
606
-
607
- X_test_sev_synth = X_test_cost_prep_synth.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
608
-
609
-
610
- # Plot SHAP for Severity (Synthetic Data)
611
- plot_glm_shap_importance(
612
- X_train=X_train_sev_synth,
613
- X_test=X_test_sev_synth,
614
- y_train=y_train_sev_synth,
615
- sample_weight=sample_weight_sev_synth,
616
- power=2, # Power=2 for Gamma (severity)
617
- title="SHAP Feature Importance for Severity Model (Synthetic Data)",
618
- max_display=10
619
- )
620
-
621
-
622
- # ### dataset 2 and data handling
623
- st.header('Dataset 2: swmotorcycle')
624
-
625
- df2_duplicated_rows=df2[df2.duplicated()]
626
- df2=df2.drop_duplicates()
627
- df2_duplicated_col=df2.columns[df2.columns.duplicated()]
628
-
629
-
630
- # add ClaimOcc feature
631
- df_2 = df2.copy()
632
- df_2['ClaimOcc'] = np.where(df_2['ClaimNb'] > 0, 1, 0)
633
- # Feature transformation
634
- df_2['Exposure'] = df_2['Exposure'].clip(upper=1)
635
- df_2['VehAge'] = df_2['VehAge'].clip(upper=20)
636
-
637
-
638
- # ### Encoding
639
- df2_encod=df_2.copy()
640
- # RiskClass
641
- RiskClass_group = {'EV ratio 13-15':'1','EV ratio 20-24':'2','EV ratio 9-12':'3','EV ratio <5':'4','EV ratio 6-8':'5',\
642
- 'EV ratio 16-19':'6','EV ratio >25':'7'}
643
- df2_encod['RiskClass'] = df2_encod['RiskClass'].map(RiskClass_group)
644
- df2_encod['RiskClass']= df2_encod['RiskClass'].astype(int)
645
- # BonusClass
646
- BonusClass_group = {'BM1':'1','BM2':'2','BM3':'3','BM4':'4','BM5':'5','BM6':'6','BM7':'7'}
647
- df2_encod['BonusClass'] = df2_encod['BonusClass'].map(BonusClass_group)
648
- df2_encod['BonusClass']= df2_encod['BonusClass'].astype(int)
649
- # Area
650
- Area_group = {"Central parts of Sweden's three largest cities":'1','Lesser towns except Gotland; Northern towns':'2',\
651
- 'Small towns; countryside except Gotland; Northern towns':'3','Suburbs; middle-sized cities':'4',\
652
- 'Northern countryside':'5','Northern towns':'6',"Gotland (Sweden's largest island)":'7'}
653
- df2_encod['Area'] = df2_encod['Area'].map(Area_group)
654
- df2_encod['Area']= df2_encod['Area'].astype(int)
655
- # Gender
656
- Gender_group = {'Female':'0','Male':'1'}
657
- df2_encod['Gender'] = df2_encod['Gender'].map(Gender_group)
658
- df2_encod['Gender']= df2_encod['Gender'].astype(int)
659
-
660
-
661
-
662
-
663
- # ### Split dataset
664
- # Split the dataset into train/test split
665
- X_train, X_test = train_test_split(df2_encod, test_size=0.2, random_state=0)
666
- st.markdown(f"**Train shape:** {X_train.shape} \n**Test shape:** {X_test.shape}")
667
-
668
-
669
- # ### Use Generate Samples Dataframe
670
- df2_synth_encod=df2_synth.copy()
671
- # RiskClass
672
- RiskClass_group = {'EV ratio 13-15':'1','EV ratio 20-24':'2','EV ratio 9-12':'3','EV ratio <5':'4','EV ratio 6-8':'5',\
673
- 'EV ratio 16-19':'6','EV ratio >25':'7'}
674
- df2_synth_encod['RiskClass'] = df2_synth_encod['RiskClass'].map(RiskClass_group)
675
- df2_synth_encod['RiskClass']= df2_synth_encod['RiskClass'].astype(int)
676
- # BonusClass
677
- BonusClass_group = {'BM1':'1','BM2':'2','BM3':'3','BM4':'4','BM5':'5','BM6':'6','BM7':'7'}
678
- df2_synth_encod['BonusClass'] = df2_synth_encod['BonusClass'].map(BonusClass_group)
679
- df2_synth_encod['BonusClass']= df2_synth_encod['BonusClass'].astype(int)
680
- # Area
681
- Area_group = {"Central parts of Sweden's three largest cities":'1','Lesser towns except Gotland; Northern towns':'2',\
682
- 'Small towns; countryside except Gotland; Northern towns':'3','Suburbs; middle-sized cities':'4',\
683
- 'Northern countryside':'5','Northern towns':'6',"Gotland (Sweden's largest island)":'7'}
684
- df2_synth_encod['Area'] = df2_synth_encod['Area'].map(Area_group)
685
- df2_synth_encod['Area']= df2_synth_encod['Area'].astype(int)
686
- # Gender
687
- Gender_group = {'Female':'0','Male':'1'}
688
- df2_synth_encod['Gender'] = df2_synth_encod['Gender'].map(Gender_group)
689
- df2_synth_encod['Gender']= df2_synth_encod['Gender'].astype(int)
690
-
691
- new_samples_df=df2_synth_encod.copy()
692
-
693
- # Check consistency
694
- st.subheader(f"Check consistency")
695
- # Find inconsistencies
696
- inconsistent_records = new_samples_df[
697
- ~(((new_samples_df["ClaimNb"] == 0) & (new_samples_df["ClaimOcc"] == 0) & (new_samples_df["ClaimAmount"] == 0)) |
698
- ((new_samples_df["ClaimNb"] > 0) & (new_samples_df["ClaimOcc"] > 0) & (new_samples_df["ClaimAmount"] > 0)))
699
- ]
700
-
701
- st.write(f"Number of inconsistent records on synthetic data: {len(inconsistent_records)}")
702
- st.write(inconsistent_records.head()) # Show a few inconsistent rows
703
- st.write('Helps assess basic data fidelity by checking structural or logical violations.')
704
-
705
-
706
- # ### Visual Comparison
707
- st.subheader('Univariate distribution comparison: real vs synthetic')
708
- st.write('Shows how well each individual feature is mimicked by the synthetic data.')
709
-
710
- # Compare selected variables using histograms
711
- compare_real_vs_synthetic(
712
- real_df=X_train,
713
- synthetic_df=df2_synth,
714
- columns=['Exposure','VehAge','ClaimOcc','ClaimNb', 'ClaimAmount', 'RiskClass', 'Area','BonusClass','Gender'],
715
- kind='hist'
716
- )
717
-
718
- st.subheader('Correlation matrix comparison: real vs synthetic')
719
- st.write('Evaluates preservation of feature-to-feature relationships.')
720
-
721
- # Compute correlation matrices
722
- corr_matrix_X_train = X_train.corr()
723
- corr_matrix_new_samples = new_samples_df.corr()
724
-
725
- # Set figure size
726
- fig=plt.figure(figsize=(30,15))
727
-
728
- # a subplot grid
729
- # Parameters (1, 2, 1) implies 1 row, 2 columns, and this plot is the 1st plot.
730
- plt.subplot(1, 2, 1) # Subplot 1
731
- sns.heatmap(corr_matrix_X_train, square=True, annot=True, cmap='coolwarm', fmt='.2f',annot_kws={"size": 15})
732
- plt.title('Correlation Heatmap of X_train', size=15)
733
- plt.yticks(rotation=0,fontsize=15)
734
- plt.xticks(rotation=90,fontsize=15)
735
-
736
- # another subplot for the second heatmap
737
- plt.subplot(1, 2, 2) # Subplot 2
738
- sns.heatmap(corr_matrix_new_samples, square=True, annot=True, cmap='coolwarm', fmt='.2f',annot_kws={"size": 15})
739
- plt.title('Correlation Heatmap of New Samples', size=15)
740
- plt.yticks(rotation=0,fontsize=15)
741
- plt.xticks(rotation=90,fontsize=15)
742
-
743
- # Display the plot
744
- plt.tight_layout()
745
- st.pyplot(fig)
746
-
747
-
748
- # ### Statistical Analysis
749
- # Kolmogorov-Smirnov test
750
- st.subheader('Kolmogorov–Smirnov Test Results')
751
- st.write('Quantifies the statistical distance between real and synthetic distributions.')
752
-
753
-
754
- results = []
755
-
756
- for column in X_train.columns:
757
- original = X_train[column].values
758
- generated = new_samples_df[column].values
759
- statistic, p_value = ks_2samp(original, generated)
760
-
761
- results.append({
762
- "Feature": column,
763
- "KS Statistic": statistic,
764
- "P-value": p_value
765
- })
766
-
767
- results_df = pd.DataFrame(results)
768
-
769
- def color_pval(val):
770
- color = "red" if val < 0.05 else "green"
771
- return f"color: {color};"
772
-
773
- styled_df = results_df.style.applymap(color_pval, subset=["P-value"]) \
774
- .format({"KS Statistic": "{:.4f}", "P-value": "{:.4f}"})
775
-
776
- st.markdown("""
777
- **Legend:**
778
- - <span style='color:green;'>Green P-value</span>: distributions are **similar** (p ≥ 0.05)
779
- - <span style='color:red;'>Red P-value</span>: distributions are **significantly different** (p < 0.05)
780
- """, unsafe_allow_html=True)
781
- st.dataframe(styled_df)
782
-
783
-
784
- # ### PCA Analysis
785
- st.subheader('PCA comparison')
786
- st.write('Assesses similarity in global variance structure and major latent components.')
787
-
788
- img = mpimg.imread('./LLM/pca_d2_80.png')
789
- fig=plt.figure(figsize=(10, 8))
790
- plt.imshow(img)
791
- plt.axis('off')
792
- st.pyplot(fig)
793
-
794
-
795
- # ### UMAP Analysis
796
- st.subheader('UMAP comparison')
797
- st.write('Examines nonlinear manifold structure and clustering behavior.')
798
- img = mpimg.imread('./LLM/umap_d2_80.png')
799
- fig=plt.figure(figsize=(10, 8))
800
- plt.imshow(img)
801
- plt.axis('off')
802
- st.pyplot(fig)
803
-
804
-
805
- # ### GLM Frequency Analysis
806
- st.subheader('Frequency GLM Analysis')
807
- st.write('Tests how well synthetic data preserves predictive relationships for claim frequency.')
808
- # Baseline frequency model
809
- results_frequency_3 = run_glm_frequency_analysis(X_train, X_test, label="Baseline", var='Real')
810
- # Using synthetic sample data with exposure clipping
811
- results_frequency_4 = run_glm_frequency_analysis(new_samples_df, X_test, clip_exposure=True, label="Synthetic Clipped", var='Synthetic')
812
-
813
-
814
- # ### GLM Cost Analysis
815
- st.subheader('Severity GLM Analysis')
816
- st.write('Evaluates whether severity-related predictors behave similarly on real and synthetic data.')
817
- results_cost_3 = run_glm_cost_analysis(X_train, X_test, var='Real')
818
- results_cost_4 = run_glm_cost_analysis(new_samples_df, X_test, is_sampled=True, var= 'Synthetic')
819
-
820
-
821
- # ### Feature Importance Analysis
822
-
823
- # --- SHAP Feature Importance for Frequency ---
824
- st.subheader('SHAP Feature Importance for Frequency Model')
825
- st.write('Shows whether drivers of frequency predictions remain consistent across datasets.')
826
-
827
- # Prepare data for frequency model SHAP
828
- X_train_freq = X_train.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
829
- y_train_freq = X_train['ClaimNb']
830
- sample_weight_freq = X_train['Exposure']
831
-
832
- X_test_freq = X_test.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
833
-
834
- # Filter out rows with Exposure = 0 for frequency model training and SHAP explanation
835
- mask_train_freq = sample_weight_freq > 0
836
- X_train_freq_filtered = X_train_freq[mask_train_freq]
837
- y_train_freq_filtered = y_train_freq[mask_train_freq]
838
- sample_weight_freq_filtered = sample_weight_freq[mask_train_freq]
839
-
840
- # Ensure X_test_freq also only contains rows where Exposure > 0
841
- mask_test_freq = X_test['Exposure'] > 0
842
- X_test_freq_filtered = X_test_freq[mask_test_freq]
843
-
844
-
845
- # Plot SHAP for Frequency
846
- plot_glm_shap_importance(
847
- X_train=X_train_freq_filtered,
848
- X_test=X_test_freq_filtered,
849
- y_train=y_train_freq_filtered / sample_weight_freq_filtered, # Target is rate (ClaimNb / Exposure)
850
- sample_weight=sample_weight_freq_filtered,
851
- power=1, # Power=1 for Poisson (frequency)
852
- title="SHAP Feature Importance for Frequency Model (Real Data)",
853
- max_display=10
854
- )
855
-
856
- # --- SHAP Feature Importance for Frequency (Synthetic Data) ---
857
- # Prepare data for frequency model SHAP using synthetic data
858
- X_train_freq_synth = new_samples_df.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
859
- y_train_freq_synth = new_samples_df['ClaimNb']
860
- sample_weight_freq_synth = new_samples_df['Exposure']
861
-
862
- # X_test_freq is the same as before (real test data)
863
- X_test_freq = X_test.drop(['Exposure', 'ClaimNb', 'ClaimAmount'], axis=1, errors='ignore')
864
-
865
- # Filter out rows with Exposure = 0 for frequency model training and SHAP explanation
866
- mask_train_freq_synth = sample_weight_freq_synth > 0
867
- X_train_freq_synth_filtered = X_train_freq_synth[mask_train_freq_synth]
868
- y_train_freq_synth_filtered = y_train_freq_synth[mask_train_freq_synth]
869
- sample_weight_freq_synth_filtered = sample_weight_freq_synth[mask_train_freq_synth]
870
-
871
- # Ensure X_test_freq also only contains rows where Exposure > 0
872
- mask_test_freq = X_test['Exposure'] > 0
873
- X_test_freq_filtered = X_test_freq[mask_test_freq]
874
-
875
- # Plot SHAP for Frequency (Synthetic Data)
876
- plot_glm_shap_importance(
877
- X_train=X_train_freq_synth_filtered,
878
- X_test=X_test_freq_filtered,
879
- y_train=y_train_freq_synth_filtered / sample_weight_freq_synth_filtered, # Target is rate
880
- sample_weight=sample_weight_freq_synth_filtered,
881
- power=1, # Power=1 for Poisson (frequency)
882
- title="SHAP Feature Importance for Frequency Model (Synthetic Data)",
883
- max_display=10
884
- )
885
-
886
- # --- SHAP Feature Importance for Severity ---
887
- st.subheader('SHAP Feature Importance for Severity Model')
888
- st.write('Assesses stability of model explanations for severity outcomes')
889
-
890
- # Prepare data for severity model SHAP
891
- X_train_cost_prep = X_train[X_train['ClaimAmount'] != 0].copy()
892
- X_test_cost_prep = X_test[X_test['ClaimAmount'] != 0].copy()
893
-
894
- X_train_sev = X_train_cost_prep.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
895
- y_train_sev = X_train_cost_prep['ClaimAmount'] / X_train_cost_prep['ClaimNb']
896
- sample_weight_sev = X_train_cost_prep['ClaimNb'] # Number of claims is the weight for severity
897
-
898
- X_test_sev = X_test_cost_prep.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
899
-
900
- # Plot SHAP for Severity
901
- plot_glm_shap_importance(
902
- X_train=X_train_sev,
903
- X_test=X_test_sev,
904
- y_train=y_train_sev,
905
- sample_weight=sample_weight_sev,
906
- power=2, # Power=2 for Gamma (severity)
907
- title="SHAP Feature Importance for Severity Model (Real Data)",
908
- max_display=10
909
- )
910
-
911
- # --- SHAP Feature Importance for Severity (Synthetic Data) ---
912
- # Prepare data for severity model SHAP using synthetic data
913
- X_train_cost_prep_synth = new_samples_df[new_samples_df['ClaimAmount'] != 0].copy()
914
- X_test_cost_prep_synth = X_test[X_test['ClaimAmount'] != 0].copy() # Keep using real test data for explanation
915
-
916
- X_train_sev_synth = X_train_cost_prep_synth.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
917
- y_train_sev_synth = X_train_cost_prep_synth['ClaimAmount'] / X_train_cost_prep_synth['ClaimNb']
918
- sample_weight_sev_synth = X_train_cost_prep_synth['ClaimNb'] # Number of claims is the weight for severity
919
-
920
- X_test_sev_synth = X_test_cost_prep_synth.drop(columns=['Acost', 'Exposure', 'ClaimAmount', 'ClaimNb'], errors='ignore')
921
-
922
-
923
- # Plot SHAP for Severity (Synthetic Data)
924
- plot_glm_shap_importance(
925
- X_train=X_train_sev_synth,
926
- X_test=X_test_sev_synth,
927
- y_train=y_train_sev_synth,
928
- sample_weight=sample_weight_sev_synth,
929
- power=2, # Power=2 for Gamma (severity)
930
- title="SHAP Feature Importance for Severity Model (Synthetic Data)",
931
- max_display=10
932
- )
933
-
934
-
935
- # ### Results
936
- st.subheader('Overall results')
937
- # The dictionary dataset 1
938
- metrics_dict_1 = results_frequency_1[1]
939
- mpd_train_1 = metrics_dict_1['mpd_train']
940
- mpd_test_1 = metrics_dict_1['mpd_test']
941
-
942
-
943
- # The dictionary synthetic dataset 1
944
- metrics_dict_2 = results_frequency_2[1]
945
- mpd_train_2 = metrics_dict_2['mpd_train']
946
- mpd_test_2 = metrics_dict_2['mpd_test']
947
-
948
-
949
-
950
- # The dictionary dataset 2
951
- metrics_dict_3 = results_frequency_3[1]
952
- mpd_train_3 = metrics_dict_3['mpd_train']
953
- mpd_test_3 = metrics_dict_3['mpd_test']
954
-
955
-
956
-
957
- # The dictionary synthetic dataset 2
958
- metrics_dict_4 = results_frequency_4[1]
959
- mpd_train_4 = metrics_dict_4['mpd_train']
960
- mpd_test_4 = metrics_dict_4['mpd_test']
961
-
962
-
963
-
964
- # The dictionary dataset 1
965
- mgd_train_1 = results_cost_1['mgd_train']
966
- mgd_test_1 = results_cost_1['mgd_test']
967
-
968
-
969
-
970
- # The dictionary synthetic dataset 1
971
- mgd_train_2 = results_cost_2['mgd_train']
972
- mgd_test_2 = results_cost_2['mgd_test']
973
-
974
-
975
-
976
- # The dictionary dataset 2
977
- mgd_train_3 = results_cost_3['mgd_train']
978
- mgd_test_3 = results_cost_3['mgd_test']
979
-
980
-
981
-
982
- # The dictionary synthetic dataset 2
983
- mgd_train_4 = results_cost_4['mgd_train']
984
- mgd_test_4 = results_cost_4['mgd_test']
985
-
986
-
987
-
988
- # Create the DataFrame
989
- results_df1 = {
990
- 'mpd_train': mpd_train_1,
991
- 'mpd_test': mpd_test_1,
992
- 'mgd_train': mgd_train_1,
993
- 'mgd_test': mgd_test_1,
994
- }
995
- results_df2 = {
996
- 'mpd_train': mpd_train_2,
997
- 'mpd_test': mpd_test_2,
998
- 'mgd_train': mgd_train_2,
999
- 'mgd_test': mgd_test_2,
1000
- }
1001
- results_df3 = {
1002
- 'mpd_train': mpd_train_3,
1003
- 'mpd_test': mpd_test_3,
1004
- 'mgd_train': mgd_train_3,
1005
- 'mgd_test': mgd_test_3,
1006
- }
1007
- results_df4 = {
1008
- 'mpd_train': mpd_train_4,
1009
- 'mpd_test': mpd_test_4,
1010
- 'mgd_train': mgd_train_4,
1011
- 'mgd_test': mgd_test_4,
1012
- }
1013
- d1=pd.DataFrame(results_df1, index=['dataset 1'])
1014
- d2=pd.DataFrame(results_df2, index=['synthetic dataset 1'])
1015
- d3=pd.DataFrame(results_df3, index=['dataset 2'])
1016
- d4=pd.DataFrame(results_df4, index=['synthetic dataset 2'])
1017
- df_tot= pd.concat([d1,d2,d3,d4])
1018
- st.dataframe(df_tot)
1019
-
1020
-
1021
- # barplot comparison
1022
- fig, ax = plt.subplots(figsize=(9, 5))
1023
- df_tot.plot(kind='bar', ax=ax)
1024
- ax.set_title('Comparison of MPD and MGD Metrics')
1025
- ax.set_ylabel('Value')
1026
- ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
1027
- ax.legend(title='Metric')
1028
- for container in ax.containers:
1029
- labels = ax.bar_label(container, fmt='%.2f', label_type='edge', padding=2)
1030
- for label in labels:
1031
- label.set_fontsize(8)
1032
-
1033
- plt.tight_layout()
1034
- st.pyplot(fig)
1035
-
1036
-
1037
- # MPD: Train vs Test Comparison
1038
- fig, axes = plt.subplots(1, 2, figsize=(15, 6))
1039
-
1040
- # --- MPD Comparison ---
1041
- mpd_data = df_tot[['mpd_train', 'mpd_test']]
1042
- mpd_data.plot(kind='bar', ax=axes[0], color=['#2ecc71', '#e74c3c'])
1043
-
1044
- axes[0].set_title('Mean Poisson Deviance: Train vs Test', fontsize=16, fontweight='bold')
1045
- axes[0].set_ylabel('MPD Value', fontsize=14)
1046
- axes[0].set_xlabel('Dataset', fontsize=14)
1047
- axes[0].legend(['Train', 'Test'], fontsize=10)
1048
-
1049
- # Larger tick labels
1050
- axes[0].tick_params(axis='x', labelsize=12, rotation=45)
1051
- axes[0].tick_params(axis='y', labelsize=12)
1052
-
1053
- axes[0].grid(axis='y', alpha=0.3)
1054
- for container in axes[0].containers:
1055
- axes[0].bar_label(container, fmt='%.3f', fontsize=15)
1056
-
1057
- # --- MGD Comparison ---
1058
- mgd_data = df_tot[['mgd_train', 'mgd_test']]
1059
- mgd_data.plot(kind='bar', ax=axes[1], color=['#3498db', '#f39c12'])
1060
-
1061
- axes[1].set_title('Mean Gamma Deviance: Train vs Test', fontsize=16, fontweight='bold')
1062
- axes[1].set_ylabel('MGD Value', fontsize=14)
1063
- axes[1].set_xlabel('Dataset', fontsize=14)
1064
- axes[1].legend(['Train', 'Test'], fontsize=10)
1065
-
1066
- # Larger tick labels
1067
- axes[1].tick_params(axis='x', labelsize=12, rotation=45)
1068
- axes[1].tick_params(axis='y', labelsize=12)
1069
-
1070
- axes[1].grid(axis='y', alpha=0.3)
1071
- for container in axes[1].containers:
1072
- axes[1].bar_label(container, fmt='%.3f', fontsize=15)
1073
-
1074
- plt.tight_layout()
1075
- st.pyplot(fig)
1076
-
1077
- # Create a heatmap
1078
- fig, ax = plt.subplots(figsize=(10, 6))
1079
-
1080
- sns.heatmap(df_tot, annot=True, fmt='.3f', cmap='RdYlGn_r',
1081
- linewidths=0.5, ax=ax, cbar_kws={'label': 'Deviance Value'})
1082
- ax.set_title('Performance Heatmap: All Metrics Across Datasets', fontsize=15, fontweight='bold', pad=20)
1083
- ax.set_xlabel('Metrics')
1084
- ax.set_ylabel('Datasets')
1085
-
1086
- plt.tight_layout()
1087
- st.pyplot(fig)
1088
-