validmind 2.8.28__py3-none-any.whl → 2.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- validmind/__version__.py +1 -1
- validmind/ai/utils.py +4 -24
- validmind/api_client.py +6 -17
- validmind/logging.py +48 -0
- validmind/models/function.py +11 -3
- validmind/tests/__init__.py +2 -0
- validmind/tests/__types__.py +18 -0
- validmind/tests/data_validation/ACFandPACFPlot.py +3 -1
- validmind/tests/data_validation/ADF.py +3 -1
- validmind/tests/data_validation/AutoAR.py +3 -1
- validmind/tests/data_validation/AutoMA.py +5 -1
- validmind/tests/data_validation/AutoStationarity.py +5 -1
- validmind/tests/data_validation/BivariateScatterPlots.py +3 -1
- validmind/tests/data_validation/BoxPierce.py +4 -1
- validmind/tests/data_validation/ChiSquaredFeaturesTable.py +1 -1
- validmind/tests/data_validation/ClassImbalance.py +1 -1
- validmind/tests/data_validation/DatasetDescription.py +4 -1
- validmind/tests/data_validation/DatasetSplit.py +3 -2
- validmind/tests/data_validation/DescriptiveStatistics.py +3 -1
- validmind/tests/data_validation/DickeyFullerGLS.py +3 -1
- validmind/tests/data_validation/Duplicates.py +3 -1
- validmind/tests/data_validation/EngleGrangerCoint.py +6 -1
- validmind/tests/data_validation/FeatureTargetCorrelationPlot.py +3 -1
- validmind/tests/data_validation/HighCardinality.py +3 -1
- validmind/tests/data_validation/HighPearsonCorrelation.py +4 -1
- validmind/tests/data_validation/IQROutliersBarPlot.py +4 -1
- validmind/tests/data_validation/IQROutliersTable.py +6 -1
- validmind/tests/data_validation/IsolationForestOutliers.py +3 -1
- validmind/tests/data_validation/JarqueBera.py +3 -1
- validmind/tests/data_validation/KPSS.py +3 -1
- validmind/tests/data_validation/LJungBox.py +3 -1
- validmind/tests/data_validation/LaggedCorrelationHeatmap.py +6 -1
- validmind/tests/data_validation/MissingValues.py +5 -1
- validmind/tests/data_validation/MissingValuesBarPlot.py +3 -1
- validmind/tests/data_validation/MutualInformation.py +4 -1
- validmind/tests/data_validation/PearsonCorrelationMatrix.py +3 -1
- validmind/tests/data_validation/PhillipsPerronArch.py +3 -1
- validmind/tests/data_validation/ProtectedClassesCombination.py +5 -1
- validmind/tests/data_validation/ProtectedClassesDescription.py +5 -1
- validmind/tests/data_validation/ProtectedClassesDisparity.py +5 -3
- validmind/tests/data_validation/ProtectedClassesThresholdOptimizer.py +9 -2
- validmind/tests/data_validation/RollingStatsPlot.py +5 -1
- validmind/tests/data_validation/RunsTest.py +1 -1
- validmind/tests/data_validation/ScatterPlot.py +2 -1
- validmind/tests/data_validation/ScoreBandDefaultRates.py +3 -1
- validmind/tests/data_validation/SeasonalDecompose.py +6 -1
- validmind/tests/data_validation/ShapiroWilk.py +4 -1
- validmind/tests/data_validation/Skewness.py +3 -1
- validmind/tests/data_validation/SpreadPlot.py +3 -1
- validmind/tests/data_validation/TabularCategoricalBarPlots.py +4 -1
- validmind/tests/data_validation/TabularDateTimeHistograms.py +3 -1
- validmind/tests/data_validation/TabularDescriptionTables.py +4 -1
- validmind/tests/data_validation/TabularNumericalHistograms.py +3 -1
- validmind/tests/data_validation/TargetRateBarPlots.py +4 -1
- validmind/tests/data_validation/TimeSeriesDescription.py +1 -1
- validmind/tests/data_validation/TimeSeriesDescriptiveStatistics.py +1 -1
- validmind/tests/data_validation/TimeSeriesFrequency.py +5 -1
- validmind/tests/data_validation/TimeSeriesHistogram.py +4 -1
- validmind/tests/data_validation/TimeSeriesLinePlot.py +3 -1
- validmind/tests/data_validation/TimeSeriesMissingValues.py +6 -1
- validmind/tests/data_validation/TimeSeriesOutliers.py +5 -1
- validmind/tests/data_validation/TooManyZeroValues.py +6 -1
- validmind/tests/data_validation/UniqueRows.py +5 -1
- validmind/tests/data_validation/WOEBinPlots.py +4 -1
- validmind/tests/data_validation/WOEBinTable.py +5 -1
- validmind/tests/data_validation/ZivotAndrewsArch.py +3 -1
- validmind/tests/data_validation/nlp/CommonWords.py +2 -1
- validmind/tests/data_validation/nlp/Hashtags.py +2 -1
- validmind/tests/data_validation/nlp/LanguageDetection.py +4 -1
- validmind/tests/data_validation/nlp/Mentions.py +3 -1
- validmind/tests/data_validation/nlp/PolarityAndSubjectivity.py +6 -1
- validmind/tests/data_validation/nlp/Punctuations.py +2 -1
- validmind/tests/data_validation/nlp/Sentiment.py +3 -1
- validmind/tests/data_validation/nlp/StopWords.py +2 -1
- validmind/tests/data_validation/nlp/TextDescription.py +3 -1
- validmind/tests/data_validation/nlp/Toxicity.py +3 -1
- validmind/tests/load.py +91 -17
- validmind/tests/model_validation/BertScore.py +6 -3
- validmind/tests/model_validation/BleuScore.py +6 -1
- validmind/tests/model_validation/ClusterSizeDistribution.py +5 -1
- validmind/tests/model_validation/ContextualRecall.py +6 -1
- validmind/tests/model_validation/FeaturesAUC.py +5 -1
- validmind/tests/model_validation/MeteorScore.py +6 -1
- validmind/tests/model_validation/ModelMetadata.py +2 -1
- validmind/tests/model_validation/ModelPredictionResiduals.py +10 -2
- validmind/tests/model_validation/RegardScore.py +7 -1
- validmind/tests/model_validation/RegressionResidualsPlot.py +5 -1
- validmind/tests/model_validation/RougeScore.py +8 -1
- validmind/tests/model_validation/TimeSeriesPredictionWithCI.py +8 -1
- validmind/tests/model_validation/TimeSeriesPredictionsPlot.py +7 -1
- validmind/tests/model_validation/TimeSeriesR2SquareBySegments.py +6 -1
- validmind/tests/model_validation/TokenDisparity.py +6 -1
- validmind/tests/model_validation/ToxicityScore.py +6 -1
- validmind/tests/model_validation/embeddings/ClusterDistribution.py +6 -1
- validmind/tests/model_validation/embeddings/CosineSimilarityComparison.py +6 -1
- validmind/tests/model_validation/embeddings/CosineSimilarityDistribution.py +6 -1
- validmind/tests/model_validation/embeddings/CosineSimilarityHeatmap.py +7 -3
- validmind/tests/model_validation/embeddings/DescriptiveAnalytics.py +6 -1
- validmind/tests/model_validation/embeddings/EmbeddingsVisualization2D.py +4 -3
- validmind/tests/model_validation/embeddings/EuclideanDistanceComparison.py +6 -1
- validmind/tests/model_validation/embeddings/EuclideanDistanceHeatmap.py +7 -3
- validmind/tests/model_validation/embeddings/PCAComponentsPairwisePlots.py +6 -1
- validmind/tests/model_validation/embeddings/StabilityAnalysisKeyword.py +5 -2
- validmind/tests/model_validation/embeddings/StabilityAnalysisRandomNoise.py +5 -1
- validmind/tests/model_validation/embeddings/StabilityAnalysisSynonyms.py +4 -1
- validmind/tests/model_validation/embeddings/StabilityAnalysisTranslation.py +5 -1
- validmind/tests/model_validation/embeddings/TSNEComponentsPairwisePlots.py +9 -6
- validmind/tests/model_validation/ragas/AnswerCorrectness.py +8 -5
- validmind/tests/model_validation/ragas/AspectCritic.py +11 -8
- validmind/tests/model_validation/ragas/ContextEntityRecall.py +5 -2
- validmind/tests/model_validation/ragas/ContextPrecision.py +5 -2
- validmind/tests/model_validation/ragas/ContextPrecisionWithoutReference.py +5 -2
- validmind/tests/model_validation/ragas/ContextRecall.py +6 -2
- validmind/tests/model_validation/ragas/Faithfulness.py +9 -5
- validmind/tests/model_validation/ragas/NoiseSensitivity.py +10 -7
- validmind/tests/model_validation/ragas/ResponseRelevancy.py +9 -6
- validmind/tests/model_validation/ragas/SemanticSimilarity.py +7 -4
- validmind/tests/model_validation/sklearn/AdjustedMutualInformation.py +5 -1
- validmind/tests/model_validation/sklearn/AdjustedRandIndex.py +5 -1
- validmind/tests/model_validation/sklearn/CalibrationCurve.py +5 -1
- validmind/tests/model_validation/sklearn/ClassifierPerformance.py +5 -1
- validmind/tests/model_validation/sklearn/ClusterCosineSimilarity.py +5 -1
- validmind/tests/model_validation/sklearn/ClusterPerformanceMetrics.py +5 -1
- validmind/tests/model_validation/sklearn/CompletenessScore.py +5 -1
- validmind/tests/model_validation/sklearn/ConfusionMatrix.py +4 -1
- validmind/tests/model_validation/sklearn/FeatureImportance.py +5 -1
- validmind/tests/model_validation/sklearn/FowlkesMallowsScore.py +5 -1
- validmind/tests/model_validation/sklearn/HomogeneityScore.py +5 -1
- validmind/tests/model_validation/sklearn/HyperParametersTuning.py +2 -4
- validmind/tests/model_validation/sklearn/KMeansClustersOptimization.py +3 -3
- validmind/tests/model_validation/sklearn/MinimumAccuracy.py +5 -1
- validmind/tests/model_validation/sklearn/MinimumF1Score.py +5 -1
- validmind/tests/model_validation/sklearn/MinimumROCAUCScore.py +5 -1
- validmind/tests/model_validation/sklearn/ModelParameters.py +6 -1
- validmind/tests/model_validation/sklearn/ModelsPerformanceComparison.py +5 -1
- validmind/tests/model_validation/sklearn/OverfitDiagnosis.py +3 -2
- validmind/tests/model_validation/sklearn/PermutationFeatureImportance.py +4 -4
- validmind/tests/model_validation/sklearn/PopulationStabilityIndex.py +2 -2
- validmind/tests/model_validation/sklearn/PrecisionRecallCurve.py +5 -1
- validmind/tests/model_validation/sklearn/ROCCurve.py +3 -1
- validmind/tests/model_validation/sklearn/RegressionErrors.py +6 -1
- validmind/tests/model_validation/sklearn/RegressionErrorsComparison.py +6 -1
- validmind/tests/model_validation/sklearn/RegressionPerformance.py +5 -1
- validmind/tests/model_validation/sklearn/RegressionR2Square.py +6 -1
- validmind/tests/model_validation/sklearn/RegressionR2SquareComparison.py +6 -1
- validmind/tests/model_validation/sklearn/RobustnessDiagnosis.py +2 -2
- validmind/tests/model_validation/sklearn/ScoreProbabilityAlignment.py +3 -1
- validmind/tests/model_validation/sklearn/SilhouettePlot.py +6 -1
- validmind/tests/model_validation/sklearn/TrainingTestDegradation.py +2 -2
- validmind/tests/model_validation/sklearn/VMeasure.py +5 -1
- validmind/tests/model_validation/sklearn/WeakspotsDiagnosis.py +6 -5
- validmind/tests/model_validation/statsmodels/AutoARIMA.py +3 -1
- validmind/tests/model_validation/statsmodels/CumulativePredictionProbabilities.py +6 -1
- validmind/tests/model_validation/statsmodels/DurbinWatsonTest.py +6 -1
- validmind/tests/model_validation/statsmodels/GINITable.py +4 -1
- validmind/tests/model_validation/statsmodels/KolmogorovSmirnov.py +5 -1
- validmind/tests/model_validation/statsmodels/Lilliefors.py +3 -1
- validmind/tests/model_validation/statsmodels/PredictionProbabilitiesHistogram.py +6 -2
- validmind/tests/model_validation/statsmodels/RegressionCoeffs.py +4 -1
- validmind/tests/model_validation/statsmodels/RegressionFeatureSignificance.py +7 -2
- validmind/tests/model_validation/statsmodels/RegressionModelForecastPlot.py +5 -4
- validmind/tests/model_validation/statsmodels/RegressionModelForecastPlotLevels.py +4 -1
- validmind/tests/model_validation/statsmodels/RegressionModelSensitivityPlot.py +3 -2
- validmind/tests/model_validation/statsmodels/RegressionModelSummary.py +5 -1
- validmind/tests/model_validation/statsmodels/RegressionPermutationFeatureImportance.py +3 -1
- validmind/tests/model_validation/statsmodels/ScorecardHistogram.py +6 -1
- validmind/tests/ongoing_monitoring/CalibrationCurveDrift.py +2 -2
- validmind/tests/ongoing_monitoring/ClassDiscriminationDrift.py +2 -2
- validmind/tests/ongoing_monitoring/ClassImbalanceDrift.py +2 -2
- validmind/tests/ongoing_monitoring/ClassificationAccuracyDrift.py +2 -2
- validmind/tests/ongoing_monitoring/ConfusionMatrixDrift.py +2 -2
- validmind/tests/ongoing_monitoring/CumulativePredictionProbabilitiesDrift.py +2 -2
- validmind/tests/ongoing_monitoring/FeatureDrift.py +5 -2
- validmind/tests/ongoing_monitoring/PredictionAcrossEachFeature.py +6 -1
- validmind/tests/ongoing_monitoring/PredictionCorrelation.py +8 -1
- validmind/tests/ongoing_monitoring/PredictionProbabilitiesHistogramDrift.py +2 -2
- validmind/tests/ongoing_monitoring/PredictionQuantilesAcrossFeatures.py +6 -1
- validmind/tests/ongoing_monitoring/ROCCurveDrift.py +4 -2
- validmind/tests/ongoing_monitoring/ScoreBandsDrift.py +2 -2
- validmind/tests/ongoing_monitoring/ScorecardHistogramDrift.py +2 -2
- validmind/tests/ongoing_monitoring/TargetPredictionDistributionPlot.py +8 -1
- validmind/tests/output.py +9 -2
- validmind/tests/plots/BoxPlot.py +260 -0
- validmind/tests/plots/CorrelationHeatmap.py +235 -0
- validmind/tests/plots/HistogramPlot.py +233 -0
- validmind/tests/plots/ViolinPlot.py +125 -0
- validmind/tests/plots/__init__.py +0 -0
- validmind/tests/prompt_validation/Bias.py +5 -1
- validmind/tests/prompt_validation/Clarity.py +5 -1
- validmind/tests/prompt_validation/Conciseness.py +5 -1
- validmind/tests/prompt_validation/Delimitation.py +5 -1
- validmind/tests/prompt_validation/NegativeInstruction.py +5 -1
- validmind/tests/prompt_validation/Robustness.py +5 -1
- validmind/tests/prompt_validation/Specificity.py +5 -1
- validmind/tests/stats/CorrelationAnalysis.py +251 -0
- validmind/tests/stats/DescriptiveStats.py +197 -0
- validmind/tests/stats/NormalityTests.py +147 -0
- validmind/tests/stats/OutlierDetection.py +173 -0
- validmind/tests/stats/__init__.py +0 -0
- validmind/unit_metrics/classification/Accuracy.py +2 -1
- validmind/unit_metrics/classification/F1.py +2 -1
- validmind/unit_metrics/classification/Precision.py +2 -1
- validmind/unit_metrics/classification/ROC_AUC.py +2 -1
- validmind/unit_metrics/classification/Recall.py +2 -1
- validmind/unit_metrics/classification/individual/AbsoluteError.py +42 -0
- validmind/unit_metrics/classification/individual/BrierScore.py +56 -0
- validmind/unit_metrics/classification/individual/CalibrationError.py +77 -0
- validmind/unit_metrics/classification/individual/ClassBalance.py +65 -0
- validmind/unit_metrics/classification/individual/Confidence.py +52 -0
- validmind/unit_metrics/classification/individual/Correctness.py +41 -0
- validmind/unit_metrics/classification/individual/LogLoss.py +61 -0
- validmind/unit_metrics/classification/individual/OutlierScore.py +86 -0
- validmind/unit_metrics/classification/individual/ProbabilityError.py +54 -0
- validmind/unit_metrics/classification/individual/Uncertainty.py +60 -0
- validmind/unit_metrics/classification/individual/__init__.py +0 -0
- validmind/unit_metrics/regression/AdjustedRSquaredScore.py +2 -1
- validmind/unit_metrics/regression/GiniCoefficient.py +2 -1
- validmind/unit_metrics/regression/HuberLoss.py +2 -1
- validmind/unit_metrics/regression/KolmogorovSmirnovStatistic.py +2 -1
- validmind/unit_metrics/regression/MeanAbsoluteError.py +2 -1
- validmind/unit_metrics/regression/MeanAbsolutePercentageError.py +2 -1
- validmind/unit_metrics/regression/MeanBiasDeviation.py +2 -1
- validmind/unit_metrics/regression/MeanSquaredError.py +2 -1
- validmind/unit_metrics/regression/QuantileLoss.py +1 -1
- validmind/unit_metrics/regression/RSquaredScore.py +2 -1
- validmind/unit_metrics/regression/RootMeanSquaredError.py +2 -1
- validmind/vm_models/dataset/dataset.py +291 -38
- validmind/vm_models/result/result.py +26 -4
- {validmind-2.8.28.dist-info → validmind-2.9.1.dist-info}/METADATA +2 -2
- {validmind-2.8.28.dist-info → validmind-2.9.1.dist-info}/RECORD +233 -212
- {validmind-2.8.28.dist-info → validmind-2.9.1.dist-info}/LICENSE +0 -0
- {validmind-2.8.28.dist-info → validmind-2.9.1.dist-info}/WHEEL +0 -0
- {validmind-2.8.28.dist-info → validmind-2.9.1.dist-info}/entry_points.txt +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import Dict, List, Tuple
|
6
6
|
|
7
7
|
import pandas as pd
|
8
8
|
import plotly.graph_objs as go
|
@@ -18,7 +18,7 @@ def ClassImbalanceDrift(
|
|
18
18
|
datasets: List[VMDataset],
|
19
19
|
drift_pct_threshold: float = 5.0,
|
20
20
|
title: str = "Class Distribution Drift",
|
21
|
-
):
|
21
|
+
) -> Tuple[go.Figure, Dict[str, pd.DataFrame], bool]:
|
22
22
|
"""
|
23
23
|
Evaluates drift in class distribution between reference and monitoring datasets.
|
24
24
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import Dict, List, Tuple
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import pandas as pd
|
@@ -18,7 +18,7 @@ from validmind.vm_models import VMDataset, VMModel
|
|
18
18
|
@tasks("classification", "text_classification")
|
19
19
|
def ClassificationAccuracyDrift(
|
20
20
|
datasets: List[VMDataset], model: VMModel, drift_pct_threshold=20
|
21
|
-
):
|
21
|
+
) -> Tuple[Dict[str, pd.DataFrame], bool, RawData]:
|
22
22
|
"""
|
23
23
|
Compares classification accuracy metrics between reference and monitoring datasets.
|
24
24
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import Dict, List, Tuple
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import pandas as pd
|
@@ -18,7 +18,7 @@ from validmind.vm_models import VMDataset, VMModel
|
|
18
18
|
@tasks("classification", "text_classification")
|
19
19
|
def ConfusionMatrixDrift(
|
20
20
|
datasets: List[VMDataset], model: VMModel, drift_pct_threshold=20
|
21
|
-
):
|
21
|
+
) -> Tuple[Dict[str, pd.DataFrame], bool, RawData]:
|
22
22
|
"""
|
23
23
|
Compares confusion matrix metrics between reference and monitoring datasets.
|
24
24
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import List, Tuple
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import plotly.graph_objects as go
|
@@ -17,7 +17,7 @@ from validmind.vm_models import VMDataset, VMModel
|
|
17
17
|
def CumulativePredictionProbabilitiesDrift(
|
18
18
|
datasets: List[VMDataset],
|
19
19
|
model: VMModel,
|
20
|
-
):
|
20
|
+
) -> Tuple[go.Figure, RawData]:
|
21
21
|
"""
|
22
22
|
Compares cumulative prediction probability distributions between reference and monitoring datasets.
|
23
23
|
|
@@ -2,11 +2,14 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
+
from typing import Dict, List, Tuple
|
6
|
+
|
5
7
|
import numpy as np
|
6
8
|
import pandas as pd
|
7
9
|
import plotly.graph_objects as go
|
8
10
|
|
9
11
|
from validmind import RawData, tags, tasks
|
12
|
+
from validmind.vm_models import VMDataset
|
10
13
|
|
11
14
|
|
12
15
|
def calculate_psi_score(actual, expected):
|
@@ -92,11 +95,11 @@ def create_distribution_plot(feature_name, reference_dist, monitoring_dist, bins
|
|
92
95
|
@tags("visualization")
|
93
96
|
@tasks("monitoring")
|
94
97
|
def FeatureDrift(
|
95
|
-
datasets,
|
98
|
+
datasets: List[VMDataset],
|
96
99
|
bins=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9],
|
97
100
|
feature_columns=None,
|
98
101
|
psi_threshold=0.2,
|
99
|
-
):
|
102
|
+
) -> Tuple[Dict[str, pd.DataFrame], go.Figure, bool, RawData]:
|
100
103
|
"""
|
101
104
|
Evaluates changes in feature distribution over time to identify potential model drift.
|
102
105
|
|
@@ -3,14 +3,19 @@
|
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
5
|
|
6
|
+
from typing import List, Tuple
|
7
|
+
|
6
8
|
import matplotlib.pyplot as plt
|
7
9
|
|
8
10
|
from validmind import RawData, tags, tasks
|
11
|
+
from validmind.vm_models import VMDataset, VMModel
|
9
12
|
|
10
13
|
|
11
14
|
@tags("visualization")
|
12
15
|
@tasks("monitoring")
|
13
|
-
def PredictionAcrossEachFeature(
|
16
|
+
def PredictionAcrossEachFeature(
|
17
|
+
datasets: List[VMDataset], model: VMModel
|
18
|
+
) -> Tuple[plt.Figure, RawData]:
|
14
19
|
"""
|
15
20
|
Assesses differences in model predictions across individual features between reference and monitoring datasets
|
16
21
|
through visual analysis.
|
@@ -2,15 +2,22 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
+
from typing import Dict, List, Tuple
|
6
|
+
|
5
7
|
import pandas as pd
|
6
8
|
import plotly.graph_objects as go
|
7
9
|
|
8
10
|
from validmind import RawData, tags, tasks
|
11
|
+
from validmind.vm_models import VMDataset, VMModel
|
9
12
|
|
10
13
|
|
11
14
|
@tags("visualization")
|
12
15
|
@tasks("monitoring")
|
13
|
-
def PredictionCorrelation(
|
16
|
+
def PredictionCorrelation(
|
17
|
+
datasets: List[VMDataset],
|
18
|
+
model: VMModel,
|
19
|
+
drift_pct_threshold: float = 20,
|
20
|
+
) -> Tuple[Dict[str, pd.DataFrame], go.Figure, bool, RawData]:
|
14
21
|
"""
|
15
22
|
Assesses correlation changes between model predictions from reference and monitoring datasets to detect potential
|
16
23
|
target drift.
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import Dict, List, Tuple
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import pandas as pd
|
@@ -21,7 +21,7 @@ def PredictionProbabilitiesHistogramDrift(
|
|
21
21
|
model: VMModel,
|
22
22
|
title="Prediction Probabilities Histogram Drift",
|
23
23
|
drift_pct_threshold: float = 20.0,
|
24
|
-
):
|
24
|
+
) -> Tuple[go.Figure, Dict[str, pd.DataFrame], bool, RawData]:
|
25
25
|
"""
|
26
26
|
Compares prediction probability distributions between reference and monitoring datasets.
|
27
27
|
|
@@ -2,15 +2,20 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
+
from typing import List, Tuple
|
6
|
+
|
5
7
|
import plotly.graph_objects as go
|
6
8
|
from plotly.subplots import make_subplots
|
7
9
|
|
8
10
|
from validmind import tags, tasks
|
11
|
+
from validmind.vm_models import VMDataset, VMModel
|
9
12
|
|
10
13
|
|
11
14
|
@tags("visualization")
|
12
15
|
@tasks("monitoring")
|
13
|
-
def PredictionQuantilesAcrossFeatures(
|
16
|
+
def PredictionQuantilesAcrossFeatures(
|
17
|
+
datasets: List[VMDataset], model: VMModel
|
18
|
+
) -> Tuple[go.Figure, ...]:
|
14
19
|
"""
|
15
20
|
Assesses differences in model prediction distributions across individual features between reference
|
16
21
|
and monitoring datasets through quantile analysis.
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import List, Tuple
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import plotly.graph_objects as go
|
@@ -20,7 +20,9 @@ from validmind.vm_models import VMDataset, VMModel
|
|
20
20
|
"visualization",
|
21
21
|
)
|
22
22
|
@tasks("classification", "text_classification")
|
23
|
-
def ROCCurveDrift(
|
23
|
+
def ROCCurveDrift(
|
24
|
+
datasets: List[VMDataset], model: VMModel
|
25
|
+
) -> Tuple[go.Figure, go.Figure, RawData]:
|
24
26
|
"""
|
25
27
|
Compares ROC curves between reference and monitoring datasets.
|
26
28
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import Dict, List, Tuple
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import pandas as pd
|
@@ -19,7 +19,7 @@ def ScoreBandsDrift(
|
|
19
19
|
score_column: str = "score",
|
20
20
|
score_bands: list = None,
|
21
21
|
drift_threshold: float = 20.0,
|
22
|
-
):
|
22
|
+
) -> Tuple[Dict[str, pd.DataFrame], bool, RawData]:
|
23
23
|
"""
|
24
24
|
Analyzes drift in population distribution and default rates across score bands.
|
25
25
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
-
from typing import List
|
5
|
+
from typing import Dict, List, Tuple
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
import pandas as pd
|
@@ -21,7 +21,7 @@ def ScorecardHistogramDrift(
|
|
21
21
|
score_column: str = "score",
|
22
22
|
title: str = "Scorecard Histogram Drift",
|
23
23
|
drift_pct_threshold: float = 20.0,
|
24
|
-
):
|
24
|
+
) -> Tuple[go.Figure, Dict[str, pd.DataFrame], bool]:
|
25
25
|
"""
|
26
26
|
Compares score distributions between reference and monitoring datasets for each class.
|
27
27
|
|
@@ -2,17 +2,24 @@
|
|
2
2
|
# See the LICENSE file in the root of this repository for details.
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
4
|
|
5
|
+
from typing import Dict, List, Tuple
|
6
|
+
|
5
7
|
import pandas as pd
|
6
8
|
import plotly.figure_factory as ff
|
7
9
|
import plotly.graph_objects as go
|
8
10
|
from scipy.stats import kurtosis, skew
|
9
11
|
|
10
12
|
from validmind import RawData, tags, tasks
|
13
|
+
from validmind.vm_models import VMDataset, VMModel
|
11
14
|
|
12
15
|
|
13
16
|
@tags("visualization")
|
14
17
|
@tasks("monitoring")
|
15
|
-
def TargetPredictionDistributionPlot(
|
18
|
+
def TargetPredictionDistributionPlot(
|
19
|
+
datasets: List[VMDataset],
|
20
|
+
model: VMModel,
|
21
|
+
drift_pct_threshold: float = 20,
|
22
|
+
) -> Tuple[Dict[str, pd.DataFrame], go.Figure, bool, RawData]:
|
16
23
|
"""
|
17
24
|
Assesses differences in prediction distributions between a reference dataset and a monitoring dataset to identify
|
18
25
|
potential data drift.
|
validmind/tests/output.py
CHANGED
@@ -45,7 +45,13 @@ class BooleanOutputHandler(OutputHandler):
|
|
45
45
|
|
46
46
|
class MetricOutputHandler(OutputHandler):
|
47
47
|
def can_handle(self, item: Any) -> bool:
|
48
|
-
|
48
|
+
# Accept individual numbers
|
49
|
+
if isinstance(item, (int, float)):
|
50
|
+
return True
|
51
|
+
# Accept lists/arrays of numbers for per-row metrics
|
52
|
+
if isinstance(item, (list, tuple, np.ndarray)):
|
53
|
+
return all(isinstance(x, (int, float, np.number)) for x in item)
|
54
|
+
return False
|
49
55
|
|
50
56
|
def process(self, item: Any, result: TestResult) -> None:
|
51
57
|
if result.metric is not None:
|
@@ -169,11 +175,12 @@ def process_output(item: Any, result: TestResult) -> None:
|
|
169
175
|
"""Process a single test output item and update the TestResult."""
|
170
176
|
handlers = [
|
171
177
|
BooleanOutputHandler(),
|
172
|
-
MetricOutputHandler(),
|
173
178
|
FigureOutputHandler(),
|
174
179
|
TableOutputHandler(),
|
175
180
|
RawDataOutputHandler(),
|
176
181
|
StringOutputHandler(),
|
182
|
+
# Unit metrics should be processed last
|
183
|
+
MetricOutputHandler(),
|
177
184
|
]
|
178
185
|
|
179
186
|
for handler in handlers:
|
@@ -0,0 +1,260 @@
|
|
1
|
+
# Copyright © 2023-2024 ValidMind Inc. All rights reserved.
|
2
|
+
# See the LICENSE file in the root of this repository for details.
|
3
|
+
# SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
|
4
|
+
|
5
|
+
from typing import List, Optional
|
6
|
+
|
7
|
+
import plotly.graph_objects as go
|
8
|
+
from plotly.subplots import make_subplots
|
9
|
+
|
10
|
+
from validmind import tags, tasks
|
11
|
+
from validmind.errors import SkipTestError
|
12
|
+
from validmind.vm_models import VMDataset
|
13
|
+
|
14
|
+
|
15
|
+
def _validate_inputs(
|
16
|
+
dataset: VMDataset, columns: Optional[List[str]], group_by: Optional[str]
|
17
|
+
):
|
18
|
+
"""Validate inputs and return validated columns."""
|
19
|
+
if columns is None:
|
20
|
+
columns = dataset.feature_columns_numeric
|
21
|
+
else:
|
22
|
+
available_columns = set(dataset.feature_columns_numeric)
|
23
|
+
columns = [col for col in columns if col in available_columns]
|
24
|
+
|
25
|
+
if not columns:
|
26
|
+
raise SkipTestError("No numerical columns found for box plotting")
|
27
|
+
|
28
|
+
if group_by is not None:
|
29
|
+
if group_by not in dataset.df.columns:
|
30
|
+
raise SkipTestError(f"Group column '{group_by}' not found in dataset")
|
31
|
+
if group_by in columns:
|
32
|
+
columns.remove(group_by)
|
33
|
+
|
34
|
+
return columns
|
35
|
+
|
36
|
+
|
37
|
+
def _create_grouped_boxplot(
|
38
|
+
dataset, columns, group_by, colors, show_outliers, title_prefix, width, height
|
39
|
+
):
|
40
|
+
"""Create grouped box plots."""
|
41
|
+
fig = go.Figure()
|
42
|
+
groups = dataset.df[group_by].dropna().unique()
|
43
|
+
|
44
|
+
for col_idx, column in enumerate(columns):
|
45
|
+
for group_idx, group_value in enumerate(groups):
|
46
|
+
data_subset = dataset.df[dataset.df[group_by] == group_value][
|
47
|
+
column
|
48
|
+
].dropna()
|
49
|
+
|
50
|
+
if len(data_subset) > 0:
|
51
|
+
color = colors[group_idx % len(colors)]
|
52
|
+
fig.add_trace(
|
53
|
+
go.Box(
|
54
|
+
y=data_subset,
|
55
|
+
name=f"{group_value}",
|
56
|
+
marker_color=color,
|
57
|
+
boxpoints="outliers" if show_outliers else False,
|
58
|
+
jitter=0.3,
|
59
|
+
pointpos=-1.8,
|
60
|
+
legendgroup=f"{group_value}",
|
61
|
+
showlegend=(col_idx == 0),
|
62
|
+
offsetgroup=group_idx,
|
63
|
+
x=[column] * len(data_subset),
|
64
|
+
)
|
65
|
+
)
|
66
|
+
|
67
|
+
fig.update_layout(
|
68
|
+
title=f"{title_prefix} Features by {group_by}",
|
69
|
+
xaxis_title="Features",
|
70
|
+
yaxis_title="Values",
|
71
|
+
boxmode="group",
|
72
|
+
width=width,
|
73
|
+
height=height,
|
74
|
+
template="plotly_white",
|
75
|
+
)
|
76
|
+
return fig
|
77
|
+
|
78
|
+
|
79
|
+
def _create_single_boxplot(
|
80
|
+
dataset, column, colors, show_outliers, title_prefix, width, height
|
81
|
+
):
|
82
|
+
"""Create single column box plot."""
|
83
|
+
data = dataset.df[column].dropna()
|
84
|
+
if len(data) == 0:
|
85
|
+
raise SkipTestError(f"No data available for column {column}")
|
86
|
+
|
87
|
+
fig = go.Figure()
|
88
|
+
fig.add_trace(
|
89
|
+
go.Box(
|
90
|
+
y=data,
|
91
|
+
name=column,
|
92
|
+
marker_color=colors[0],
|
93
|
+
boxpoints="outliers" if show_outliers else False,
|
94
|
+
jitter=0.3,
|
95
|
+
pointpos=-1.8,
|
96
|
+
)
|
97
|
+
)
|
98
|
+
|
99
|
+
fig.update_layout(
|
100
|
+
title=f"{title_prefix} {column}",
|
101
|
+
yaxis_title=column,
|
102
|
+
width=width,
|
103
|
+
height=height,
|
104
|
+
template="plotly_white",
|
105
|
+
showlegend=False,
|
106
|
+
)
|
107
|
+
return fig
|
108
|
+
|
109
|
+
|
110
|
+
def _create_multiple_boxplots(
|
111
|
+
dataset, columns, colors, show_outliers, title_prefix, width, height
|
112
|
+
):
|
113
|
+
"""Create multiple column box plots in subplot layout."""
|
114
|
+
n_cols = min(3, len(columns))
|
115
|
+
n_rows = (len(columns) + n_cols - 1) // n_cols
|
116
|
+
|
117
|
+
subplot_titles = [f"{title_prefix} {col}" for col in columns]
|
118
|
+
fig = make_subplots(
|
119
|
+
rows=n_rows,
|
120
|
+
cols=n_cols,
|
121
|
+
subplot_titles=subplot_titles,
|
122
|
+
vertical_spacing=0.1,
|
123
|
+
horizontal_spacing=0.1,
|
124
|
+
)
|
125
|
+
|
126
|
+
for idx, column in enumerate(columns):
|
127
|
+
row = (idx // n_cols) + 1
|
128
|
+
col = (idx % n_cols) + 1
|
129
|
+
data = dataset.df[column].dropna()
|
130
|
+
|
131
|
+
if len(data) > 0:
|
132
|
+
color = colors[idx % len(colors)]
|
133
|
+
fig.add_trace(
|
134
|
+
go.Box(
|
135
|
+
y=data,
|
136
|
+
name=column,
|
137
|
+
marker_color=color,
|
138
|
+
boxpoints="outliers" if show_outliers else False,
|
139
|
+
jitter=0.3,
|
140
|
+
pointpos=-1.8,
|
141
|
+
showlegend=False,
|
142
|
+
),
|
143
|
+
row=row,
|
144
|
+
col=col,
|
145
|
+
)
|
146
|
+
fig.update_yaxes(title_text=column, row=row, col=col)
|
147
|
+
else:
|
148
|
+
fig.add_annotation(
|
149
|
+
text=f"No data available<br>for {column}",
|
150
|
+
x=0.5,
|
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",
|
154
|
+
showarrow=False,
|
155
|
+
row=row,
|
156
|
+
col=col,
|
157
|
+
)
|
158
|
+
|
159
|
+
fig.update_layout(
|
160
|
+
title="Dataset Feature Distributions",
|
161
|
+
width=width,
|
162
|
+
height=height,
|
163
|
+
template="plotly_white",
|
164
|
+
showlegend=False,
|
165
|
+
)
|
166
|
+
return fig
|
167
|
+
|
168
|
+
|
169
|
+
@tags("tabular_data", "visualization", "data_quality")
|
170
|
+
@tasks("classification", "regression", "clustering")
|
171
|
+
def BoxPlot(
|
172
|
+
dataset: VMDataset,
|
173
|
+
columns: Optional[List[str]] = None,
|
174
|
+
group_by: Optional[str] = None,
|
175
|
+
width: int = 1200,
|
176
|
+
height: int = 600,
|
177
|
+
colors: Optional[List[str]] = None,
|
178
|
+
show_outliers: bool = True,
|
179
|
+
title_prefix: str = "Box Plot of",
|
180
|
+
) -> go.Figure:
|
181
|
+
"""
|
182
|
+
Generates customizable box plots for numerical features in a dataset with optional grouping using Plotly.
|
183
|
+
|
184
|
+
### Purpose
|
185
|
+
|
186
|
+
This test provides a flexible way to visualize the distribution of numerical features
|
187
|
+
through interactive box plots, with optional grouping by categorical variables. Box plots are
|
188
|
+
effective for identifying outliers, comparing distributions across groups, and
|
189
|
+
understanding the spread and central tendency of the data.
|
190
|
+
|
191
|
+
### Test Mechanism
|
192
|
+
|
193
|
+
The test creates interactive box plots for specified numerical columns (or all numerical columns
|
194
|
+
if none specified). It supports various customization options including:
|
195
|
+
- Grouping by categorical variables
|
196
|
+
- Customizable colors and styling
|
197
|
+
- Outlier display options
|
198
|
+
- Interactive hover information
|
199
|
+
- Zoom and pan capabilities
|
200
|
+
|
201
|
+
### Signs of High Risk
|
202
|
+
|
203
|
+
- Presence of many outliers indicating data quality issues
|
204
|
+
- Highly skewed distributions
|
205
|
+
- Large differences in variance across groups
|
206
|
+
- Unexpected patterns in grouped data
|
207
|
+
|
208
|
+
### Strengths
|
209
|
+
|
210
|
+
- Clear visualization of distribution statistics (median, quartiles, outliers)
|
211
|
+
- Interactive Plotly plots with hover information and zoom capabilities
|
212
|
+
- Effective for comparing distributions across groups
|
213
|
+
- Handles missing values appropriately
|
214
|
+
- Highly customizable appearance
|
215
|
+
|
216
|
+
### Limitations
|
217
|
+
|
218
|
+
- Limited to numerical features only
|
219
|
+
- May not be suitable for continuous variables with many unique values
|
220
|
+
- Visual interpretation may be subjective
|
221
|
+
- Less effective with very large datasets
|
222
|
+
"""
|
223
|
+
# Validate inputs
|
224
|
+
columns = _validate_inputs(dataset, columns, group_by)
|
225
|
+
|
226
|
+
# Set default colors
|
227
|
+
if colors is None:
|
228
|
+
colors = [
|
229
|
+
"steelblue",
|
230
|
+
"orange",
|
231
|
+
"green",
|
232
|
+
"red",
|
233
|
+
"purple",
|
234
|
+
"brown",
|
235
|
+
"pink",
|
236
|
+
"gray",
|
237
|
+
"olive",
|
238
|
+
"cyan",
|
239
|
+
]
|
240
|
+
|
241
|
+
# Create appropriate plot type
|
242
|
+
if group_by is not None:
|
243
|
+
return _create_grouped_boxplot(
|
244
|
+
dataset,
|
245
|
+
columns,
|
246
|
+
group_by,
|
247
|
+
colors,
|
248
|
+
show_outliers,
|
249
|
+
title_prefix,
|
250
|
+
width,
|
251
|
+
height,
|
252
|
+
)
|
253
|
+
elif len(columns) == 1:
|
254
|
+
return _create_single_boxplot(
|
255
|
+
dataset, columns[0], colors, show_outliers, title_prefix, width, height
|
256
|
+
)
|
257
|
+
else:
|
258
|
+
return _create_multiple_boxplots(
|
259
|
+
dataset, columns, colors, show_outliers, title_prefix, width, height
|
260
|
+
)
|