validmind 1.11.4__py3-none-any.whl → 1.11.6__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.
- validmind/client.py +1 -3
- validmind/model_validation/model_metadata.py +15 -0
- validmind/model_validation/sklearn/metrics.py +9 -3
- validmind/model_validation/sklearn/threshold_tests.py +78 -33
- validmind/vm_models/model.py +1 -0
- {validmind-1.11.4.dist-info → validmind-1.11.6.dist-info}/METADATA +2 -1
- {validmind-1.11.4.dist-info → validmind-1.11.6.dist-info}/RECORD +9 -9
- {validmind-1.11.4.dist-info → validmind-1.11.6.dist-info}/LICENSE +0 -0
- {validmind-1.11.4.dist-info → validmind-1.11.6.dist-info}/WHEEL +0 -0
validmind/client.py
CHANGED
@@ -91,9 +91,7 @@ def init_model(
|
|
91
91
|
|
92
92
|
if not Model.is_supported_model(model):
|
93
93
|
raise ValueError(
|
94
|
-
"Model type {} is not supported at the moment."
|
95
|
-
Model.model_class(model)
|
96
|
-
)
|
94
|
+
f"Model type {Model.model_library(model)}.{Model.model_class(model)} is not supported at the moment."
|
97
95
|
)
|
98
96
|
|
99
97
|
return Model.init_vm_model(
|
@@ -18,6 +18,13 @@ SUPPORTED_STATSMODELS_LINK_FUNCTIONS = {
|
|
18
18
|
}
|
19
19
|
|
20
20
|
|
21
|
+
def get_catboost_version():
|
22
|
+
if "catboost" in sys.modules:
|
23
|
+
return sys.modules["catboost"].__version__
|
24
|
+
|
25
|
+
return "n/a"
|
26
|
+
|
27
|
+
|
21
28
|
def get_pytorch_version():
|
22
29
|
if "torch" in sys.modules:
|
23
30
|
return sys.modules["torch"].__version__
|
@@ -113,6 +120,12 @@ def get_info_from_model_instance(model):
|
|
113
120
|
subtask = "binary"
|
114
121
|
framework = "PyTorch"
|
115
122
|
framework_version = get_pytorch_version()
|
123
|
+
elif model_class == "CatBoostClassifier":
|
124
|
+
architecture = "Gradient Boosting"
|
125
|
+
task = "classification"
|
126
|
+
subtask = "binary"
|
127
|
+
framework = "CatBoost"
|
128
|
+
framework_version = get_catboost_version()
|
116
129
|
else:
|
117
130
|
raise ValueError(f"Model class {model_class} is not supported by this test")
|
118
131
|
|
@@ -162,6 +175,8 @@ def get_params_from_model_instance(model):
|
|
162
175
|
params = model.get_params()
|
163
176
|
elif model_library == "pytorch":
|
164
177
|
params = {}
|
178
|
+
elif model_library == "catboost":
|
179
|
+
params = model.get_all_params()
|
165
180
|
else:
|
166
181
|
raise ValueError(f"Model library {model_library} is not supported by this test")
|
167
182
|
|
@@ -444,8 +444,12 @@ class SHAPGlobalImportance(Metric):
|
|
444
444
|
# the shap library generates a bunch of annoying warnings that we don't care about
|
445
445
|
warnings.filterwarnings("ignore", category=UserWarning)
|
446
446
|
|
447
|
-
#
|
448
|
-
if
|
447
|
+
# Any tree based model can go here
|
448
|
+
if (
|
449
|
+
model_class == "XGBClassifier"
|
450
|
+
or model_class == "RandomForestClassifier"
|
451
|
+
or model_class == "CatBoostClassifier"
|
452
|
+
):
|
449
453
|
explainer = shap.TreeExplainer(trained_model)
|
450
454
|
elif (
|
451
455
|
model_class == "LogisticRegression"
|
@@ -485,6 +489,8 @@ class PopulationStabilityIndex(Metric):
|
|
485
489
|
print(f"Skiping PSI for {model_library} models")
|
486
490
|
return
|
487
491
|
|
488
|
-
psi_df = _get_psi(
|
492
|
+
psi_df = _get_psi(
|
493
|
+
self.model.y_train_predict.copy(), self.model.y_test_predict.copy()
|
494
|
+
)
|
489
495
|
|
490
496
|
return self.cache_results(metric_value=psi_df)
|
@@ -313,13 +313,19 @@ class OverfitDiagnosis(ThresholdTest):
|
|
313
313
|
raise ValueError("model must of provided to run this test")
|
314
314
|
|
315
315
|
if self.params["features_columns"] is None:
|
316
|
-
features_list =
|
317
|
-
field_dict["id"] for field_dict in self.model.train_ds.fields
|
318
|
-
]
|
319
|
-
features_list.remove(self.model.train_ds.target_column)
|
316
|
+
features_list = self.model.train_ds.get_features_columns()
|
320
317
|
else:
|
321
318
|
features_list = self.params["features_columns"]
|
322
319
|
|
320
|
+
# Check if all elements from features_list are present in the feature columns
|
321
|
+
all_present = all(
|
322
|
+
elem in self.model.train_ds.get_features_columns() for elem in features_list
|
323
|
+
)
|
324
|
+
if not all_present:
|
325
|
+
raise ValueError(
|
326
|
+
"The list of feature columns provided do not match with training dataset feature columns"
|
327
|
+
)
|
328
|
+
|
323
329
|
if not isinstance(features_list, list):
|
324
330
|
raise ValueError(
|
325
331
|
"features_columns must be a list of features you would like to test"
|
@@ -344,7 +350,11 @@ class OverfitDiagnosis(ThresholdTest):
|
|
344
350
|
results_headers.extend(self.default_metrics.keys())
|
345
351
|
|
346
352
|
for feature_column in features_list:
|
347
|
-
|
353
|
+
bins = 10
|
354
|
+
if feature_column in self.model.train_ds.get_categorical_features_columns():
|
355
|
+
bins = len(train_df[feature_column].unique())
|
356
|
+
train_df["bin"] = pd.cut(train_df[feature_column], bins=bins)
|
357
|
+
|
348
358
|
results_train = {k: [] for k in results_headers}
|
349
359
|
results_test = {k: [] for k in results_headers}
|
350
360
|
|
@@ -583,17 +593,21 @@ class WeakspotsDiagnosis(ThresholdTest):
|
|
583
593
|
if self.model is None:
|
584
594
|
raise ValueError("model must of provided to run this test")
|
585
595
|
|
586
|
-
if "features_columns" not in self.params:
|
587
|
-
raise ValueError("features_columns must be provided in params")
|
588
|
-
|
589
596
|
if self.params["features_columns"] is None:
|
590
|
-
features_list =
|
591
|
-
field_dict["id"] for field_dict in self.model.train_ds.fields
|
592
|
-
]
|
593
|
-
features_list.remove(self.model.train_ds.target_column)
|
597
|
+
features_list = self.model.train_ds.get_features_columns()
|
594
598
|
else:
|
595
599
|
features_list = self.params["features_columns"]
|
596
600
|
|
601
|
+
# Check if all elements from features_list are present in the feature columns
|
602
|
+
all_present = all(
|
603
|
+
elem in self.model.train_ds.get_features_columns() for elem in features_list
|
604
|
+
)
|
605
|
+
if not all_present:
|
606
|
+
raise ValueError(
|
607
|
+
"The list of feature columns provided do not match with "
|
608
|
+
+ "training dataset feature columns"
|
609
|
+
)
|
610
|
+
|
597
611
|
target_column = self.model.train_ds.target_column
|
598
612
|
prediction_column = f"{target_column}_pred"
|
599
613
|
|
@@ -610,7 +624,11 @@ class WeakspotsDiagnosis(ThresholdTest):
|
|
610
624
|
results_headers = ["slice", "shape"]
|
611
625
|
results_headers.extend(self.default_metrics.keys())
|
612
626
|
for feature in features_list:
|
613
|
-
|
627
|
+
bins = 10
|
628
|
+
if feature in self.model.train_ds.get_categorical_features_columns():
|
629
|
+
bins = len(train_df[feature].unique())
|
630
|
+
train_df["bin"] = pd.cut(train_df[feature], bins=bins)
|
631
|
+
|
614
632
|
results_train = {k: [] for k in results_headers}
|
615
633
|
results_test = {k: [] for k in results_headers}
|
616
634
|
|
@@ -811,6 +829,7 @@ class RobustnessDiagnosis(ThresholdTest):
|
|
811
829
|
default_params = {
|
812
830
|
"features_columns": None,
|
813
831
|
"scaling_factor_std_dev_list": [0.01, 0.02],
|
832
|
+
"accuracy_decay_threshold": 3,
|
814
833
|
}
|
815
834
|
default_metrics = {
|
816
835
|
"accuracy": metrics.accuracy_score,
|
@@ -839,6 +858,10 @@ class RobustnessDiagnosis(ThresholdTest):
|
|
839
858
|
raise ValueError("scaling_factor_std_dev_list must be provided in params")
|
840
859
|
x_std_dev_list = self.params["scaling_factor_std_dev_list"]
|
841
860
|
|
861
|
+
if self.params["accuracy_decay_threshold"] is None:
|
862
|
+
raise ValueError("accuracy_decay_threshold must be provided in params")
|
863
|
+
accuracy_threshold = self.params["accuracy_decay_threshold"]
|
864
|
+
|
842
865
|
if self.model is None:
|
843
866
|
raise ValueError("model must of provided to run this test")
|
844
867
|
|
@@ -846,20 +869,25 @@ class RobustnessDiagnosis(ThresholdTest):
|
|
846
869
|
if "features_columns" not in self.params:
|
847
870
|
raise ValueError("features_columns must be provided in params")
|
848
871
|
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
872
|
+
features_list = self.params["features_columns"]
|
873
|
+
if features_list is None:
|
874
|
+
features_list = self.model.train_ds.get_numeric_features_columns()
|
875
|
+
|
876
|
+
# Check if all elements from features_list are present in the numerical feature columns
|
877
|
+
all_present = all(
|
878
|
+
elem in self.model.train_ds.get_numeric_features_columns()
|
879
|
+
for elem in features_list
|
880
|
+
)
|
881
|
+
if not all_present:
|
882
|
+
raise ValueError(
|
883
|
+
"The list of feature columns provided do not match with training "
|
884
|
+
+ "dataset numerical feature columns"
|
885
|
+
)
|
859
886
|
|
860
887
|
# Remove target column if it exist in the list
|
861
|
-
|
862
|
-
features_list
|
888
|
+
features_list = [
|
889
|
+
col for col in features_list if col != self.model.train_ds.target_column
|
890
|
+
]
|
863
891
|
|
864
892
|
train_df = self.model.train_ds.x.copy()
|
865
893
|
train_y_true = self.model.train_ds.y
|
@@ -870,8 +898,9 @@ class RobustnessDiagnosis(ThresholdTest):
|
|
870
898
|
test_results = []
|
871
899
|
test_figures = []
|
872
900
|
|
873
|
-
results_headers = ["Perturbation Size", "Dataset Type", "Records"]
|
874
|
-
|
901
|
+
results_headers = ["Perturbation Size", "Dataset Type", "Records"] + list(
|
902
|
+
self.default_metrics.keys()
|
903
|
+
)
|
875
904
|
results = {k: [] for k in results_headers}
|
876
905
|
|
877
906
|
# Iterate scaling factor for the standard deviation list
|
@@ -881,10 +910,10 @@ class RobustnessDiagnosis(ThresholdTest):
|
|
881
910
|
|
882
911
|
# Add noise to numeric features columns provided by user
|
883
912
|
for feature in features_list:
|
884
|
-
temp_train_df[feature] = self.
|
913
|
+
temp_train_df[feature] = self._add_noise_std_dev(
|
885
914
|
temp_train_df[feature].to_list(), x_std_dev
|
886
915
|
)
|
887
|
-
temp_test_df[feature] = self.
|
916
|
+
temp_test_df[feature] = self._add_noise_std_dev(
|
888
917
|
temp_test_df[feature].to_list(), x_std_dev
|
889
918
|
)
|
890
919
|
|
@@ -907,15 +936,31 @@ class RobustnessDiagnosis(ThresholdTest):
|
|
907
936
|
)
|
908
937
|
)
|
909
938
|
|
939
|
+
train_acc = df.loc[(df["Dataset Type"] == "Training"), "accuracy"].values[0]
|
940
|
+
test_acc = df.loc[(df["Dataset Type"] == "Test"), "accuracy"].values[0]
|
941
|
+
|
942
|
+
df["Passed"] = np.where(
|
943
|
+
(df["Dataset Type"] == "Training")
|
944
|
+
& (df["accuracy"] >= (train_acc - accuracy_threshold)),
|
945
|
+
True,
|
946
|
+
np.where(
|
947
|
+
(df["Dataset Type"] == "Test")
|
948
|
+
& (df["accuracy"] >= (test_acc - accuracy_threshold)),
|
949
|
+
True,
|
950
|
+
False,
|
951
|
+
),
|
952
|
+
)
|
910
953
|
test_results.append(
|
911
954
|
TestResult(
|
912
955
|
test_name="accuracy",
|
913
|
-
column=features_list
|
956
|
+
column=features_list,
|
914
957
|
passed=True,
|
915
|
-
values=df.to_dict(
|
958
|
+
values=df.to_dict(),
|
916
959
|
)
|
917
960
|
)
|
918
|
-
return self.cache_results(
|
961
|
+
return self.cache_results(
|
962
|
+
test_results, passed=df["Passed"].all(), figures=test_figures
|
963
|
+
)
|
919
964
|
|
920
965
|
def _compute_metrics(
|
921
966
|
self,
|
@@ -946,7 +991,7 @@ class RobustnessDiagnosis(ThresholdTest):
|
|
946
991
|
for metric, metric_fn in self.default_metrics.items():
|
947
992
|
results[metric].append(metric_fn(y_true.values, y_prediction) * 100)
|
948
993
|
|
949
|
-
def
|
994
|
+
def _add_noise_std_dev(
|
950
995
|
self, values: List[float], x_std_dev: float
|
951
996
|
) -> Tuple[List[float], float]:
|
952
997
|
"""
|
validmind/vm_models/model.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: validmind
|
3
|
-
Version: 1.11.
|
3
|
+
Version: 1.11.6
|
4
4
|
Summary: ValidMind Developer Framework
|
5
5
|
Author: Andres Rodriguez
|
6
6
|
Author-email: andres@validmind.ai
|
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
12
12
|
Provides-Extra: r-support
|
13
13
|
Requires-Dist: arch (>=5.4.0,<6.0.0)
|
14
|
+
Requires-Dist: catboost (>=1.2,<2.0)
|
14
15
|
Requires-Dist: click (>=8.0.4,<9.0.0)
|
15
16
|
Requires-Dist: dython (>=0.7.1,<0.8.0)
|
16
17
|
Requires-Dist: ipython (==7.34.0)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
validmind/__init__.py,sha256=ND6a4RZrm1QFdYvDnGqhfwoXFsC762CJrUzdPdcVtp0,1443
|
2
2
|
validmind/api_client.py,sha256=bjRsGzSJlviQVah8Dben_NHnaYcoMov06xeT2rxZiG0,11540
|
3
|
-
validmind/client.py,sha256=
|
3
|
+
validmind/client.py,sha256=hUdQGgKL_aJDW_rRQufQoOGeSIroUzmy8S3xCDaKL44,9223
|
4
4
|
validmind/data_validation/__init__.py,sha256=xytRpsfQ86fDnIZRoAO7GMVVU_TwWVMXxSCwm0mb45I,590
|
5
5
|
validmind/data_validation/metrics.py,sha256=fLi9vkalf8Yp1MQ0HyJ7y_RbArf-NriE0-gzeXxlI3Q,44383
|
6
6
|
validmind/data_validation/threshold_tests.py,sha256=lUW3_LKHaLg9_Npp-HViOW4cbGbPF18qtprODjQEiEw,31630
|
@@ -27,10 +27,10 @@ validmind/datasets/regression/models/fred_loan_rates_model_4.pkl,sha256=cSxhpcrI
|
|
27
27
|
validmind/datasets/regression/models/fred_loan_rates_model_5.pkl,sha256=FkNLHq9xkPMbYks_vyMjFL371mw9SQYbP1iX9lY4Ljo,60343
|
28
28
|
validmind/model_utils.py,sha256=DuPN2tF582ho167mfodODseJ6LIVuQOF9Xx0zv6b4Yk,10529
|
29
29
|
validmind/model_validation/__init__.py,sha256=fYWK9BES5uKGW4yhRLtXk6L2IAytk9xkB-NFVMVK_Gk,43
|
30
|
-
validmind/model_validation/model_metadata.py,sha256=
|
30
|
+
validmind/model_validation/model_metadata.py,sha256=r-MyR1KTg7Dnmtbw1VW18dGwDt2mDjjxzk2kqLoOfrw,7153
|
31
31
|
validmind/model_validation/sklearn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
|
-
validmind/model_validation/sklearn/metrics.py,sha256=
|
33
|
-
validmind/model_validation/sklearn/threshold_tests.py,sha256=
|
32
|
+
validmind/model_validation/sklearn/metrics.py,sha256=J6vizOm06VoMK1YA--3BrBC-JcmcBoC2s7PvHLeRcWY,15251
|
33
|
+
validmind/model_validation/sklearn/threshold_tests.py,sha256=Phc4Ppek25Fb5B5bul7X8Zuue_8KU5O1jkAh2Foalsk,39850
|
34
34
|
validmind/model_validation/statsmodels/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
35
|
validmind/model_validation/statsmodels/metrics.py,sha256=4OUd-pv7kfrnIMXUyYudJX9tPGLH5yELLDBoJ8g5quU,28272
|
36
36
|
validmind/model_validation/statsmodels/threshold_tests.py,sha256=SyEv7oaNIgiQ1ML3dQrGN54pSP88j9htOy4V2l4Ipwk,1317
|
@@ -50,7 +50,7 @@ validmind/vm_models/dataset_utils.py,sha256=xWq6dbxe9fCUdpKCiEFvbxhy9t7cOKh0boS-
|
|
50
50
|
validmind/vm_models/figure.py,sha256=EarfMm49J2BWf6UhsMFGr3VSdGu8v2ZewzArKKp_LfU,592
|
51
51
|
validmind/vm_models/metric.py,sha256=kf1N646Wq2pSZ1GkxG1tDoFyqGntN1N-PTMLPz1j-5o,3746
|
52
52
|
validmind/vm_models/metric_result.py,sha256=NVPNIt4S9HN05CnFr-DPYp2ZUYoFGVP-zT2KX6gNypQ,1757
|
53
|
-
validmind/vm_models/model.py,sha256=
|
53
|
+
validmind/vm_models/model.py,sha256=9ubRdS8eVZaQWtmupLedtD7xf905r3UxePBJrMoxcFs,6565
|
54
54
|
validmind/vm_models/plot_utils.py,sha256=BWYc9SwITwZxaAJePVYDLrBSV1XEV0EmVllq9A1K_IM,3721
|
55
55
|
validmind/vm_models/result_summary.py,sha256=1YGlWqcO4PY2NtDm7fbuOSLXPIu6KM1USp_pgh6rmJM,1518
|
56
56
|
validmind/vm_models/test_context.py,sha256=nWiTIORPNEl7mKkYme8n2QaJyAotp034A2NK33MNmhE,2501
|
@@ -59,7 +59,7 @@ validmind/vm_models/test_plan_result.py,sha256=oPEkss0eJAetRzv11P4McF9b651v6Tq7k
|
|
59
59
|
validmind/vm_models/test_result.py,sha256=jiX8yb1NptBXZQ_pOyHloc8I6yS6zamYm0j9OWUqrHs,1698
|
60
60
|
validmind/vm_models/test_suite.py,sha256=d2yBuLD4ga7Bb_yK67LJ14C58_Mj4GYBPdy4BuxoBog,5407
|
61
61
|
validmind/vm_models/threshold_test.py,sha256=F0s4JPN8JXpGjsNU40xaeOgt8kB2BI1GrOrcYCGcxqA,4231
|
62
|
-
validmind-1.11.
|
63
|
-
validmind-1.11.
|
64
|
-
validmind-1.11.
|
65
|
-
validmind-1.11.
|
62
|
+
validmind-1.11.6.dist-info/LICENSE,sha256=oyp_7jnk_p7ZNF9mcWpiHadwWc1JqR1aaemjjfCFscE,5458
|
63
|
+
validmind-1.11.6.dist-info/METADATA,sha256=Qbl-H0aQ0ma-SA8SiC7Os1_F94fWMpmhWItRK_k8zXU,1457
|
64
|
+
validmind-1.11.6.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
65
|
+
validmind-1.11.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|