validmind 2.9.1__py3-none-any.whl → 2.9.3__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 (60) hide show
  1. validmind/__init__.py +16 -5
  2. validmind/__version__.py +1 -1
  3. validmind/ai/test_descriptions.py +24 -17
  4. validmind/ai/utils.py +2 -2
  5. validmind/api_client.py +0 -2
  6. validmind/datasets/credit_risk/lending_club.py +13 -1
  7. validmind/datasets/nlp/cnn_dailymail.py +15 -1
  8. validmind/tests/data_validation/ChiSquaredFeaturesTable.py +14 -2
  9. validmind/tests/data_validation/DickeyFullerGLS.py +13 -2
  10. validmind/tests/data_validation/PhillipsPerronArch.py +13 -2
  11. validmind/tests/data_validation/ScoreBandDefaultRates.py +1 -1
  12. validmind/tests/data_validation/SeasonalDecompose.py +14 -2
  13. validmind/tests/data_validation/ShapiroWilk.py +14 -1
  14. validmind/tests/data_validation/TimeSeriesDescriptiveStatistics.py +14 -1
  15. validmind/tests/data_validation/WOEBinPlots.py +14 -1
  16. validmind/tests/data_validation/WOEBinTable.py +13 -2
  17. validmind/tests/data_validation/ZivotAndrewsArch.py +13 -2
  18. validmind/tests/data_validation/nlp/CommonWords.py +14 -2
  19. validmind/tests/data_validation/nlp/LanguageDetection.py +14 -1
  20. validmind/tests/data_validation/nlp/PolarityAndSubjectivity.py +13 -1
  21. validmind/tests/data_validation/nlp/Sentiment.py +13 -1
  22. validmind/tests/data_validation/nlp/StopWords.py +14 -2
  23. validmind/tests/data_validation/nlp/TextDescription.py +14 -2
  24. validmind/tests/data_validation/nlp/Toxicity.py +13 -1
  25. validmind/tests/model_validation/BertScore.py +13 -2
  26. validmind/tests/model_validation/BleuScore.py +13 -2
  27. validmind/tests/model_validation/ContextualRecall.py +13 -1
  28. validmind/tests/model_validation/MeteorScore.py +13 -2
  29. validmind/tests/model_validation/ModelPredictionResiduals.py +14 -1
  30. validmind/tests/model_validation/RegardScore.py +13 -2
  31. validmind/tests/model_validation/RougeScore.py +14 -1
  32. validmind/tests/model_validation/TimeSeriesPredictionWithCI.py +14 -1
  33. validmind/tests/model_validation/ToxicityScore.py +13 -1
  34. validmind/tests/model_validation/embeddings/PCAComponentsPairwisePlots.py +1 -1
  35. validmind/tests/model_validation/embeddings/TSNEComponentsPairwisePlots.py +1 -1
  36. validmind/tests/model_validation/sklearn/KMeansClustersOptimization.py +14 -2
  37. validmind/tests/model_validation/sklearn/RobustnessDiagnosis.py +1 -1
  38. validmind/tests/model_validation/sklearn/SHAPGlobalImportance.py +13 -2
  39. validmind/tests/model_validation/statsmodels/CumulativePredictionProbabilities.py +1 -1
  40. validmind/tests/model_validation/statsmodels/PredictionProbabilitiesHistogram.py +1 -1
  41. validmind/tests/model_validation/statsmodels/RegressionCoeffs.py +14 -2
  42. validmind/tests/model_validation/statsmodels/ScorecardHistogram.py +1 -1
  43. validmind/tests/ongoing_monitoring/CalibrationCurveDrift.py +1 -1
  44. validmind/tests/ongoing_monitoring/ClassDiscriminationDrift.py +14 -1
  45. validmind/tests/ongoing_monitoring/PredictionProbabilitiesHistogramDrift.py +15 -2
  46. validmind/tests/ongoing_monitoring/ScoreBandsDrift.py +1 -1
  47. validmind/tests/ongoing_monitoring/ScorecardHistogramDrift.py +15 -2
  48. validmind/tests/ongoing_monitoring/TargetPredictionDistributionPlot.py +14 -1
  49. validmind/tests/plots/BoxPlot.py +2 -2
  50. validmind/tests/plots/HistogramPlot.py +4 -4
  51. validmind/tests/stats/DescriptiveStats.py +2 -2
  52. validmind/vm_models/result/pii_filter.py +202 -0
  53. validmind/vm_models/result/result.py +34 -8
  54. validmind/vm_models/result/utils.py +0 -27
  55. validmind-2.9.3.dist-info/METADATA +848 -0
  56. {validmind-2.9.1.dist-info → validmind-2.9.3.dist-info}/RECORD +59 -58
  57. validmind-2.9.1.dist-info/METADATA +0 -137
  58. {validmind-2.9.1.dist-info → validmind-2.9.3.dist-info}/LICENSE +0 -0
  59. {validmind-2.9.1.dist-info → validmind-2.9.3.dist-info}/WHEEL +0 -0
  60. {validmind-2.9.1.dist-info → validmind-2.9.3.dist-info}/entry_points.txt +0 -0
@@ -4,14 +4,26 @@
4
4
 
5
5
  from typing import Tuple
6
6
 
7
- import evaluate
8
7
  import pandas as pd
9
8
  import plotly.graph_objects as go
10
9
 
11
10
  from validmind import RawData, tags, tasks
11
+ from validmind.errors import MissingDependencyError
12
12
  from validmind.tests.utils import validate_prediction
13
13
  from validmind.vm_models import VMDataset, VMModel
14
14
 
15
+ try:
16
+ import evaluate
17
+ except ImportError as e:
18
+ if "evaluate" in str(e):
19
+ raise MissingDependencyError(
20
+ "Missing required package `evaluate` for BleuScore. "
21
+ "Please run `pip install validmind[nlp]` to use NLP tests",
22
+ required_dependencies=["evaluate"],
23
+ extra="nlp",
24
+ ) from e
25
+ raise e
26
+
15
27
 
16
28
  @tags("nlp", "text_data", "visualization")
17
29
  @tasks("text_classification", "text_summarization")
@@ -70,7 +82,6 @@ def BleuScore(
70
82
  # Ensure equal lengths and get truncated data if necessary
71
83
  y_true, y_pred = validate_prediction(y_true, y_pred)
72
84
 
73
- # Load the BLEU evaluation metric
74
85
  bleu = evaluate.load("bleu")
75
86
 
76
87
  # Calculate BLEU scores
@@ -4,11 +4,23 @@
4
4
 
5
5
  from typing import Tuple
6
6
 
7
- import nltk
8
7
  import pandas as pd
9
8
  import plotly.graph_objects as go
10
9
 
11
10
  from validmind import RawData, tags, tasks
11
+ from validmind.errors import MissingDependencyError
12
+
13
+ try:
14
+ import nltk
15
+ except ImportError as e:
16
+ if "nltk" in str(e).lower():
17
+ raise MissingDependencyError(
18
+ "Missing required package `nltk` for ContextualRecall. "
19
+ "Please run `pip install validmind[nlp]` to use NLP tests",
20
+ required_dependencies=["nltk"],
21
+ extra="nlp",
22
+ ) from e
23
+ raise e
12
24
  from validmind.tests.utils import validate_prediction
13
25
  from validmind.vm_models import VMDataset, VMModel
14
26
 
@@ -4,14 +4,26 @@
4
4
 
5
5
  from typing import Tuple
6
6
 
7
- import evaluate
8
7
  import pandas as pd
9
8
  import plotly.graph_objects as go
10
9
 
11
10
  from validmind import RawData, tags, tasks
11
+ from validmind.errors import MissingDependencyError
12
12
  from validmind.tests.utils import validate_prediction
13
13
  from validmind.vm_models import VMDataset, VMModel
14
14
 
15
+ try:
16
+ import evaluate
17
+ except ImportError as e:
18
+ if "evaluate" in str(e):
19
+ raise MissingDependencyError(
20
+ "Missing required package `evaluate` for MeteorScore. "
21
+ "Please run `pip install validmind[nlp]` to use NLP tests",
22
+ required_dependencies=["evaluate"],
23
+ extra="nlp",
24
+ ) from e
25
+ raise e
26
+
15
27
 
16
28
  @tags("nlp", "text_data", "visualization")
17
29
  @tasks("text_classification", "text_summarization")
@@ -73,7 +85,6 @@ def MeteorScore(
73
85
 
74
86
  validate_prediction(y_true, y_pred)
75
87
 
76
- # Load the METEOR evaluation metric
77
88
  meteor = evaluate.load("meteor")
78
89
 
79
90
  # Calculate METEOR scores
@@ -6,11 +6,24 @@ from typing import Optional, Tuple
6
6
 
7
7
  import pandas as pd
8
8
  import plotly.graph_objects as go
9
- from scipy.stats import kstest
10
9
 
11
10
  from validmind import RawData, tags, tasks
11
+ from validmind.errors import MissingDependencyError
12
12
  from validmind.vm_models import VMDataset, VMModel
13
13
 
14
+ try:
15
+ from scipy.stats import kstest
16
+ except ImportError as e:
17
+ if "scipy" in str(e):
18
+ raise MissingDependencyError(
19
+ "Missing required package `scipy` for ModelPredictionResiduals. "
20
+ "Please run `pip install validmind[stats]` to use statistical tests",
21
+ required_dependencies=["scipy"],
22
+ extra="stats",
23
+ ) from e
24
+
25
+ raise e
26
+
14
27
 
15
28
  @tags("regression")
16
29
  @tasks("residual_analysis", "visualization")
@@ -4,14 +4,26 @@
4
4
 
5
5
  from typing import Tuple
6
6
 
7
- import evaluate
8
7
  import pandas as pd
9
8
  import plotly.graph_objects as go
10
9
 
11
10
  from validmind import RawData, tags, tasks
11
+ from validmind.errors import MissingDependencyError
12
12
  from validmind.tests.utils import validate_prediction
13
13
  from validmind.vm_models import VMDataset, VMModel
14
14
 
15
+ try:
16
+ import evaluate
17
+ except ImportError as e:
18
+ if "evaluate" in str(e):
19
+ raise MissingDependencyError(
20
+ "Missing required package `evaluate` for RegardScore. "
21
+ "Please run `pip install validmind[nlp]` to use NLP tests",
22
+ required_dependencies=["evaluate"],
23
+ extra="nlp",
24
+ ) from e
25
+ raise e
26
+
15
27
 
16
28
  @tags("nlp", "text_data", "visualization")
17
29
  @tasks("text_classification", "text_summarization")
@@ -66,7 +78,6 @@ def RegardScore(
66
78
  # Ensure equal lengths and get truncated data if necessary
67
79
  y_true, y_pred = validate_prediction(y_true, y_pred)
68
80
 
69
- # Load the regard evaluation metric
70
81
  regard_tool = evaluate.load("regard", module_type="measurement")
71
82
 
72
83
  # Function to calculate regard scores
@@ -6,11 +6,24 @@ from typing import Tuple
6
6
 
7
7
  import pandas as pd
8
8
  import plotly.graph_objects as go
9
- from rouge import Rouge
10
9
 
11
10
  from validmind import RawData, tags, tasks
11
+ from validmind.errors import MissingDependencyError
12
12
  from validmind.vm_models import VMDataset, VMModel
13
13
 
14
+ try:
15
+ from rouge import Rouge
16
+ except ImportError as e:
17
+ if "rouge" in str(e):
18
+ raise MissingDependencyError(
19
+ "Missing required package `rouge` for RougeScore. "
20
+ "Please run `pip install validmind[nlp]` to use NLP tests",
21
+ required_dependencies=["rouge"],
22
+ extra="nlp",
23
+ ) from e
24
+
25
+ raise e
26
+
14
27
 
15
28
  @tags("nlp", "text_data", "visualization")
16
29
  @tasks("text_classification", "text_summarization")
@@ -7,11 +7,24 @@ from typing import Tuple
7
7
  import numpy as np
8
8
  import pandas as pd
9
9
  import plotly.graph_objects as go
10
- from scipy.stats import norm
11
10
 
12
11
  from validmind import RawData, tags, tasks
12
+ from validmind.errors import MissingDependencyError
13
13
  from validmind.vm_models import VMDataset, VMModel
14
14
 
15
+ try:
16
+ from scipy.stats import norm
17
+ except ImportError as e:
18
+ if "scipy" in str(e):
19
+ raise MissingDependencyError(
20
+ "Missing required package `scipy` for TimeSeriesPredictionWithCI. "
21
+ "Please run `pip install validmind[stats]` to use statistical tests",
22
+ required_dependencies=["scipy"],
23
+ extra="stats",
24
+ ) from e
25
+
26
+ raise e
27
+
15
28
 
16
29
  @tags("model_predictions", "visualization")
17
30
  @tasks("regression", "time_series_forecasting")
@@ -4,13 +4,25 @@
4
4
 
5
5
  from typing import Tuple
6
6
 
7
- import evaluate
8
7
  import pandas as pd
9
8
  import plotly.graph_objects as go
10
9
 
11
10
  from validmind import RawData, tags, tasks
11
+ from validmind.errors import MissingDependencyError
12
12
  from validmind.vm_models import VMDataset, VMModel
13
13
 
14
+ try:
15
+ import evaluate
16
+ except ImportError as e:
17
+ if "evaluate" in str(e):
18
+ raise MissingDependencyError(
19
+ "Missing required package `evaluate` for ToxicityScore. "
20
+ "Please run `pip install validmind[nlp]` to use NLP tests",
21
+ required_dependencies=["evaluate"],
22
+ extra="nlp",
23
+ ) from e
24
+ raise e
25
+
14
26
 
15
27
  @tags("nlp", "text_data", "visualization")
16
28
  @tasks("text_classification", "text_summarization")
@@ -75,7 +75,7 @@ def PCAComponentsPairwisePlots(
75
75
 
76
76
  # Prepare DataFrame for Plotly
77
77
  pca_df = pd.DataFrame(
78
- pca_results, columns=[f"PC{i+1}" for i in range(n_components)]
78
+ pca_results, columns=[f"PC{i + 1}" for i in range(n_components)]
79
79
  )
80
80
 
81
81
  # List to store each plot
@@ -79,7 +79,7 @@ def TSNEComponentsPairwisePlots(
79
79
 
80
80
  # Prepare DataFrame for Plotly
81
81
  tsne_df = pd.DataFrame(
82
- tsne_results, columns=[f"Component {i+1}" for i in range(n_components)]
82
+ tsne_results, columns=[f"Component {i + 1}" for i in range(n_components)]
83
83
  )
84
84
 
85
85
  # List to store each plot
@@ -7,12 +7,24 @@ from typing import List, Optional, Tuple
7
7
  import numpy as np
8
8
  import plotly.graph_objects as go
9
9
  from plotly.subplots import make_subplots
10
- from scipy.spatial.distance import cdist
11
10
  from sklearn import clone
12
11
  from sklearn.metrics import silhouette_score
13
12
 
14
13
  from validmind import RawData, tags, tasks
15
- from validmind.errors import SkipTestError
14
+ from validmind.errors import MissingDependencyError, SkipTestError
15
+
16
+ try:
17
+ from scipy.spatial.distance import cdist
18
+ except ImportError as e:
19
+ if "scipy" in str(e):
20
+ raise MissingDependencyError(
21
+ "Missing required package `scipy` for KMeansClustersOptimization. "
22
+ "Please run `pip install validmind[stats]` to use statistical tests",
23
+ required_dependencies=["scipy"],
24
+ extra="stats",
25
+ ) from e
26
+
27
+ raise e
16
28
  from validmind.vm_models import VMDataset, VMModel
17
29
 
18
30
 
@@ -129,7 +129,7 @@ def _plot_robustness(
129
129
 
130
130
  datasets = results["Dataset"].unique()
131
131
  pallete = [
132
- f"#{int(r*255):02x}{int(g*255):02x}{int(b*255):02x}"
132
+ f"#{int(r * 255):02x}{int(g * 255):02x}{int(b * 255):02x}"
133
133
  for r, g, b in sns.color_palette("husl", len(datasets))
134
134
  ]
135
135
 
@@ -9,14 +9,25 @@ from warnings import filters as _warnings_filters
9
9
  import matplotlib.pyplot as plt
10
10
  import numpy as np
11
11
  import pandas as pd
12
- import shap
13
12
 
14
13
  from validmind import RawData, tags, tasks
15
- from validmind.errors import UnsupportedModelForSHAPError
14
+ from validmind.errors import MissingDependencyError, UnsupportedModelForSHAPError
16
15
  from validmind.logging import get_logger
17
16
  from validmind.models import CatBoostModel, SKlearnModel, StatsModelsModel
18
17
  from validmind.vm_models import VMDataset, VMModel
19
18
 
19
+ try:
20
+ import shap
21
+ except ImportError as e:
22
+ if "shap" in str(e):
23
+ raise MissingDependencyError(
24
+ "Missing required package `shap` for SHAPGlobalImportance. "
25
+ "Please run `pip install validmind[explainability]` to use SHAP tests",
26
+ required_dependencies=["shap"],
27
+ extra="explainability",
28
+ ) from e
29
+ raise e
30
+
20
31
  logger = get_logger(__name__)
21
32
 
22
33
 
@@ -88,7 +88,7 @@ def _plot_cumulative_prob(df, target_col, title):
88
88
  classes = sorted(df[target_col].unique())
89
89
  colors = [colormap(i / len(classes))[:3] for i in range(len(classes))] # RGB
90
90
  color_dict = {
91
- cls: f"rgb({int(rgb[0]*255)}, {int(rgb[1]*255)}, {int(rgb[2]*255)})"
91
+ cls: f"rgb({int(rgb[0] * 255)}, {int(rgb[1] * 255)}, {int(rgb[2] * 255)})"
92
92
  for cls, rgb in zip(classes, colors)
93
93
  }
94
94
 
@@ -83,7 +83,7 @@ def _plot_prob_histogram(df, target_col, title):
83
83
  classes = sorted(df[target_col].unique())
84
84
  colors = [colormap(i / len(classes))[:3] for i in range(len(classes))] # RGB
85
85
  color_dict = {
86
- cls: f"rgb({int(rgb[0]*255)}, {int(rgb[1]*255)}, {int(rgb[2]*255)})"
86
+ cls: f"rgb({int(rgb[0] * 255)}, {int(rgb[1] * 255)}, {int(rgb[2] * 255)})"
87
87
  for cls, rgb in zip(classes, colors)
88
88
  }
89
89
 
@@ -7,10 +7,22 @@ from typing import Tuple
7
7
 
8
8
  import pandas as pd
9
9
  import plotly.graph_objects as go
10
- from scipy import stats
11
10
 
12
11
  from validmind import RawData, tags, tasks
13
- from validmind.errors import SkipTestError
12
+ from validmind.errors import MissingDependencyError, SkipTestError
13
+
14
+ try:
15
+ from scipy import stats
16
+ except ImportError as e:
17
+ if "scipy" in str(e):
18
+ raise MissingDependencyError(
19
+ "Missing required package `scipy` for RegressionCoeffs. "
20
+ "Please run `pip install validmind[stats]` to use statistical tests",
21
+ required_dependencies=["scipy"],
22
+ extra="stats",
23
+ ) from e
24
+
25
+ raise e
14
26
  from validmind.vm_models import VMModel
15
27
 
16
28
 
@@ -85,7 +85,7 @@ def _plot_score_histogram(df, score_col, target_col, title):
85
85
  classes = sorted(df[target_col].unique())
86
86
  colors = [colormap(i / len(classes))[:3] for i in range(len(classes))] # RGB
87
87
  color_dict = {
88
- cls: f"rgb({int(rgb[0]*255)}, {int(rgb[1]*255)}, {int(rgb[2]*255)})"
88
+ cls: f"rgb({int(rgb[0] * 255)}, {int(rgb[1] * 255)}, {int(rgb[2] * 255)})"
89
89
  for cls, rgb in zip(classes, colors)
90
90
  }
91
91
 
@@ -96,7 +96,7 @@ def CalibrationCurveDrift(
96
96
 
97
97
  # Create bin labels
98
98
  bin_edges = np.linspace(0, 1, n_bins + 1)
99
- bin_labels = [f"{bin_edges[i]:.1f}-{bin_edges[i+1]:.1f}" for i in range(n_bins)]
99
+ bin_labels = [f"{bin_edges[i]:.1f}-{bin_edges[i + 1]:.1f}" for i in range(n_bins)]
100
100
 
101
101
  # Create predicted probabilities table
102
102
  pred_metrics = []
@@ -6,13 +6,26 @@ from typing import Dict, List, Tuple
6
6
 
7
7
  import numpy as np
8
8
  import pandas as pd
9
- from scipy import stats
10
9
  from sklearn.metrics import roc_auc_score
11
10
  from sklearn.preprocessing import LabelBinarizer
12
11
 
13
12
  from validmind import tags, tasks
13
+ from validmind.errors import MissingDependencyError
14
14
  from validmind.vm_models import VMDataset, VMModel
15
15
 
16
+ try:
17
+ from scipy import stats
18
+ except ImportError as e:
19
+ if "scipy" in str(e):
20
+ raise MissingDependencyError(
21
+ "Missing required package `scipy` for ClassDiscriminationDrift. "
22
+ "Please run `pip install validmind[stats]` to use statistical tests",
23
+ required_dependencies=["scipy"],
24
+ extra="stats",
25
+ ) from e
26
+
27
+ raise e
28
+
16
29
 
17
30
  def multiclass_roc_auc_score(y_test, y_pred, average="macro"):
18
31
  lb = LabelBinarizer()
@@ -8,11 +8,24 @@ import numpy as np
8
8
  import pandas as pd
9
9
  import plotly.graph_objects as go
10
10
  from plotly.subplots import make_subplots
11
- from scipy import stats
12
11
 
13
12
  from validmind import RawData, tags, tasks
13
+ from validmind.errors import MissingDependencyError
14
14
  from validmind.vm_models import VMDataset, VMModel
15
15
 
16
+ try:
17
+ from scipy import stats
18
+ except ImportError as e:
19
+ if "scipy" in str(e):
20
+ raise MissingDependencyError(
21
+ "Missing required package `scipy` for PredictionProbabilitiesHistogramDrift. "
22
+ "Please run `pip install validmind[stats]` to use statistical tests",
23
+ required_dependencies=["scipy"],
24
+ extra="stats",
25
+ ) from e
26
+
27
+ raise e
28
+
16
29
 
17
30
  @tags("visualization", "credit_risk")
18
31
  @tasks("classification")
@@ -191,7 +204,7 @@ def PredictionProbabilitiesHistogramDrift(
191
204
  # Add separate legend for each subplot
192
205
  fig.update_layout(
193
206
  **{
194
- f'legend{i+1 if i > 0 else ""}': dict(
207
+ f'legend{i + 1 if i > 0 else ""}': dict(
195
208
  yanchor="middle",
196
209
  y=1 - (i / len(classes)) - (0.5 / len(classes)),
197
210
  xanchor="left",
@@ -84,7 +84,7 @@ def ScoreBandsDrift(
84
84
 
85
85
  # Create band labels
86
86
  band_labels = [
87
- f"{score_bands[i]}-{score_bands[i+1]}" for i in range(len(score_bands) - 1)
87
+ f"{score_bands[i]}-{score_bands[i + 1]}" for i in range(len(score_bands) - 1)
88
88
  ]
89
89
  band_labels.insert(0, f"<{score_bands[0]}")
90
90
  band_labels.append(f">{score_bands[-1]}")
@@ -8,11 +8,24 @@ import numpy as np
8
8
  import pandas as pd
9
9
  import plotly.graph_objects as go
10
10
  from plotly.subplots import make_subplots
11
- from scipy import stats
12
11
 
13
12
  from validmind import tags, tasks
13
+ from validmind.errors import MissingDependencyError
14
14
  from validmind.vm_models import VMDataset
15
15
 
16
+ try:
17
+ from scipy import stats
18
+ except ImportError as e:
19
+ if "scipy" in str(e):
20
+ raise MissingDependencyError(
21
+ "Missing required package `scipy` for ScorecardHistogramDrift. "
22
+ "Please run `pip install validmind[stats]` to use statistical tests",
23
+ required_dependencies=["scipy"],
24
+ extra="stats",
25
+ ) from e
26
+
27
+ raise e
28
+
16
29
 
17
30
  @tags("visualization", "credit_risk", "logistic_regression")
18
31
  @tasks("classification")
@@ -196,7 +209,7 @@ def ScorecardHistogramDrift(
196
209
  # Add separate legend for each subplot
197
210
  fig.update_layout(
198
211
  **{
199
- f'legend{i+1 if i > 0 else ""}': dict(
212
+ f'legend{i + 1 if i > 0 else ""}': dict(
200
213
  yanchor="middle",
201
214
  y=1 - (i / len(classes)) - (0.5 / len(classes)),
202
215
  xanchor="left",
@@ -7,11 +7,24 @@ from typing import Dict, List, Tuple
7
7
  import pandas as pd
8
8
  import plotly.figure_factory as ff
9
9
  import plotly.graph_objects as go
10
- from scipy.stats import kurtosis, skew
11
10
 
12
11
  from validmind import RawData, tags, tasks
12
+ from validmind.errors import MissingDependencyError
13
13
  from validmind.vm_models import VMDataset, VMModel
14
14
 
15
+ try:
16
+ from scipy.stats import kurtosis, skew
17
+ except ImportError as e:
18
+ if "scipy" in str(e):
19
+ raise MissingDependencyError(
20
+ "Missing required package `scipy` for TargetPredictionDistributionPlot. "
21
+ "Please run `pip install validmind[stats]` to use statistical tests",
22
+ required_dependencies=["scipy"],
23
+ extra="stats",
24
+ ) from e
25
+
26
+ raise e
27
+
15
28
 
16
29
  @tags("visualization")
17
30
  @tasks("monitoring")
@@ -149,8 +149,8 @@ def _create_multiple_boxplots(
149
149
  text=f"No data available<br>for {column}",
150
150
  x=0.5,
151
151
  y=0.5,
152
- xref=f"x{idx+1} domain" if idx > 0 else "x domain",
153
- yref=f"y{idx+1} domain" if idx > 0 else "y domain",
152
+ xref=f"x{idx + 1} domain" if idx > 0 else "x domain",
153
+ yref=f"y{idx + 1} domain" if idx > 0 else "y domain",
154
154
  showarrow=False,
155
155
  row=row,
156
156
  col=col,
@@ -95,8 +95,8 @@ def _add_stats_annotation(fig, data, idx, row, col):
95
95
  text=stats_text,
96
96
  x=0.02,
97
97
  y=0.98,
98
- xref=f"x{idx+1} domain" if idx > 0 else "x domain",
99
- yref=f"y{idx+1} domain" if idx > 0 else "y domain",
98
+ xref=f"x{idx + 1} domain" if idx > 0 else "x domain",
99
+ yref=f"y{idx + 1} domain" if idx > 0 else "y domain",
100
100
  showarrow=False,
101
101
  align="left",
102
102
  bgcolor="rgba(255,255,255,0.8)",
@@ -195,8 +195,8 @@ def HistogramPlot(
195
195
  text=f"No data available<br>for {column}",
196
196
  x=0.5,
197
197
  y=0.5,
198
- xref=f"x{idx+1}" if idx > 0 else "x",
199
- yref=f"y{idx+1}" if idx > 0 else "y",
198
+ xref=f"x{idx + 1}" if idx > 0 else "x",
199
+ yref=f"y{idx + 1}" if idx > 0 else "y",
200
200
  showarrow=False,
201
201
  row=row,
202
202
  col=col,
@@ -96,8 +96,8 @@ def _compute_advanced_stats(column: str, data, confidence_level: float):
96
96
  "Skewness": skewness,
97
97
  "Kurtosis": kurtosis_val,
98
98
  "CV %": cv,
99
- f"CI Lower ({confidence_level*100:.0f}%)": ci_lower,
100
- f"CI Upper ({confidence_level*100:.0f}%)": ci_upper,
99
+ f"CI Lower ({confidence_level * 100:.0f}%)": ci_lower,
100
+ f"CI Upper ({confidence_level * 100:.0f}%)": ci_upper,
101
101
  "Normality Test": normality_test,
102
102
  "Normality Stat": normality_stat,
103
103
  "Normality p-value": normality_p,