validmind 2.5.8__py3-none-any.whl → 2.5.18__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/test_descriptions.py +80 -119
- validmind/ai/test_result_description/config.yaml +29 -0
- validmind/ai/test_result_description/context.py +73 -0
- validmind/ai/test_result_description/image_processing.py +124 -0
- validmind/ai/test_result_description/system.jinja +39 -0
- validmind/ai/test_result_description/user.jinja +25 -0
- validmind/api_client.py +89 -43
- validmind/client.py +2 -2
- validmind/client_config.py +11 -14
- validmind/datasets/credit_risk/__init__.py +1 -0
- validmind/datasets/credit_risk/datasets/lending_club_biased.csv.gz +0 -0
- validmind/datasets/credit_risk/lending_club_bias.py +142 -0
- validmind/datasets/regression/fred_timeseries.py +67 -138
- validmind/template.py +1 -0
- validmind/test_suites/__init__.py +0 -2
- validmind/test_suites/statsmodels_timeseries.py +1 -1
- validmind/test_suites/summarization.py +0 -1
- validmind/test_suites/time_series.py +0 -43
- validmind/tests/__types__.py +14 -15
- validmind/tests/data_validation/ACFandPACFPlot.py +15 -13
- validmind/tests/data_validation/ADF.py +31 -24
- validmind/tests/data_validation/AutoAR.py +9 -9
- validmind/tests/data_validation/AutoMA.py +23 -16
- validmind/tests/data_validation/AutoSeasonality.py +18 -16
- validmind/tests/data_validation/AutoStationarity.py +21 -16
- validmind/tests/data_validation/BivariateScatterPlots.py +67 -96
- validmind/tests/{model_validation/statsmodels → data_validation}/BoxPierce.py +34 -34
- validmind/tests/data_validation/ChiSquaredFeaturesTable.py +85 -124
- validmind/tests/data_validation/ClassImbalance.py +15 -12
- validmind/tests/data_validation/DFGLSArch.py +19 -13
- validmind/tests/data_validation/DatasetDescription.py +17 -11
- validmind/tests/data_validation/DatasetSplit.py +7 -5
- validmind/tests/data_validation/DescriptiveStatistics.py +28 -21
- validmind/tests/data_validation/Duplicates.py +33 -25
- validmind/tests/data_validation/EngleGrangerCoint.py +35 -33
- validmind/tests/data_validation/FeatureTargetCorrelationPlot.py +59 -71
- validmind/tests/data_validation/HighCardinality.py +19 -12
- validmind/tests/data_validation/HighPearsonCorrelation.py +27 -22
- validmind/tests/data_validation/IQROutliersBarPlot.py +13 -10
- validmind/tests/data_validation/IQROutliersTable.py +40 -36
- validmind/tests/data_validation/IsolationForestOutliers.py +21 -14
- validmind/tests/data_validation/JarqueBera.py +70 -0
- validmind/tests/data_validation/KPSS.py +34 -29
- validmind/tests/data_validation/LJungBox.py +66 -0
- validmind/tests/data_validation/LaggedCorrelationHeatmap.py +22 -15
- validmind/tests/data_validation/MissingValues.py +32 -27
- validmind/tests/data_validation/MissingValuesBarPlot.py +25 -21
- validmind/tests/data_validation/PearsonCorrelationMatrix.py +71 -84
- validmind/tests/data_validation/PhillipsPerronArch.py +37 -30
- validmind/tests/data_validation/ProtectedClassesCombination.py +197 -0
- validmind/tests/data_validation/ProtectedClassesDescription.py +130 -0
- validmind/tests/data_validation/ProtectedClassesDisparity.py +133 -0
- validmind/tests/data_validation/ProtectedClassesThresholdOptimizer.py +172 -0
- validmind/tests/data_validation/RollingStatsPlot.py +31 -23
- validmind/tests/data_validation/RunsTest.py +72 -0
- validmind/tests/data_validation/ScatterPlot.py +63 -78
- validmind/tests/data_validation/SeasonalDecompose.py +38 -34
- validmind/tests/{model_validation/statsmodels → data_validation}/ShapiroWilk.py +35 -30
- validmind/tests/data_validation/Skewness.py +35 -37
- validmind/tests/data_validation/SpreadPlot.py +35 -35
- validmind/tests/data_validation/TabularCategoricalBarPlots.py +23 -17
- validmind/tests/data_validation/TabularDateTimeHistograms.py +21 -13
- validmind/tests/data_validation/TabularDescriptionTables.py +51 -16
- validmind/tests/data_validation/TabularNumericalHistograms.py +25 -22
- validmind/tests/data_validation/TargetRateBarPlots.py +21 -14
- validmind/tests/data_validation/TimeSeriesDescription.py +25 -18
- validmind/tests/data_validation/TimeSeriesDescriptiveStatistics.py +23 -17
- validmind/tests/data_validation/TimeSeriesFrequency.py +24 -17
- validmind/tests/data_validation/TimeSeriesHistogram.py +33 -32
- validmind/tests/data_validation/TimeSeriesLinePlot.py +17 -10
- validmind/tests/data_validation/TimeSeriesMissingValues.py +15 -10
- validmind/tests/data_validation/TimeSeriesOutliers.py +37 -33
- validmind/tests/data_validation/TooManyZeroValues.py +16 -11
- validmind/tests/data_validation/UniqueRows.py +11 -6
- validmind/tests/data_validation/WOEBinPlots.py +23 -16
- validmind/tests/data_validation/WOEBinTable.py +35 -30
- validmind/tests/data_validation/ZivotAndrewsArch.py +34 -28
- validmind/tests/data_validation/nlp/CommonWords.py +21 -14
- validmind/tests/data_validation/nlp/Hashtags.py +42 -40
- validmind/tests/data_validation/nlp/LanguageDetection.py +33 -14
- validmind/tests/data_validation/nlp/Mentions.py +21 -15
- validmind/tests/data_validation/nlp/PolarityAndSubjectivity.py +32 -9
- validmind/tests/data_validation/nlp/Punctuations.py +24 -20
- validmind/tests/data_validation/nlp/Sentiment.py +27 -8
- validmind/tests/data_validation/nlp/StopWords.py +26 -19
- validmind/tests/data_validation/nlp/TextDescription.py +39 -36
- validmind/tests/data_validation/nlp/Toxicity.py +32 -9
- validmind/tests/decorator.py +81 -42
- validmind/tests/model_validation/BertScore.py +36 -27
- validmind/tests/model_validation/BleuScore.py +25 -19
- validmind/tests/model_validation/ClusterSizeDistribution.py +38 -34
- validmind/tests/model_validation/ContextualRecall.py +38 -13
- validmind/tests/model_validation/FeaturesAUC.py +32 -13
- validmind/tests/model_validation/MeteorScore.py +46 -33
- validmind/tests/model_validation/ModelMetadata.py +32 -64
- validmind/tests/model_validation/ModelPredictionResiduals.py +75 -73
- validmind/tests/model_validation/RegardScore.py +30 -14
- validmind/tests/model_validation/RegressionResidualsPlot.py +10 -5
- validmind/tests/model_validation/RougeScore.py +36 -30
- validmind/tests/model_validation/TimeSeriesPredictionWithCI.py +30 -14
- validmind/tests/model_validation/TimeSeriesPredictionsPlot.py +27 -30
- validmind/tests/model_validation/TimeSeriesR2SquareBySegments.py +68 -63
- validmind/tests/model_validation/TokenDisparity.py +31 -23
- validmind/tests/model_validation/ToxicityScore.py +26 -17
- validmind/tests/model_validation/embeddings/ClusterDistribution.py +24 -20
- validmind/tests/model_validation/embeddings/CosineSimilarityComparison.py +30 -27
- validmind/tests/model_validation/embeddings/CosineSimilarityDistribution.py +7 -5
- validmind/tests/model_validation/embeddings/CosineSimilarityHeatmap.py +32 -23
- validmind/tests/model_validation/embeddings/DescriptiveAnalytics.py +7 -5
- validmind/tests/model_validation/embeddings/EmbeddingsVisualization2D.py +15 -11
- validmind/tests/model_validation/embeddings/EuclideanDistanceComparison.py +29 -29
- validmind/tests/model_validation/embeddings/EuclideanDistanceHeatmap.py +34 -25
- validmind/tests/model_validation/embeddings/PCAComponentsPairwisePlots.py +38 -26
- validmind/tests/model_validation/embeddings/StabilityAnalysis.py +40 -1
- validmind/tests/model_validation/embeddings/StabilityAnalysisKeyword.py +18 -17
- validmind/tests/model_validation/embeddings/StabilityAnalysisRandomNoise.py +40 -45
- validmind/tests/model_validation/embeddings/StabilityAnalysisSynonyms.py +17 -19
- validmind/tests/model_validation/embeddings/StabilityAnalysisTranslation.py +29 -25
- validmind/tests/model_validation/embeddings/TSNEComponentsPairwisePlots.py +38 -28
- validmind/tests/model_validation/ragas/AnswerCorrectness.py +5 -4
- validmind/tests/model_validation/ragas/AnswerRelevance.py +5 -4
- validmind/tests/model_validation/ragas/AnswerSimilarity.py +5 -4
- validmind/tests/model_validation/ragas/AspectCritique.py +12 -6
- validmind/tests/model_validation/ragas/ContextEntityRecall.py +9 -8
- validmind/tests/model_validation/ragas/ContextPrecision.py +5 -4
- validmind/tests/model_validation/ragas/ContextRecall.py +5 -4
- validmind/tests/model_validation/ragas/ContextUtilization.py +155 -0
- validmind/tests/model_validation/ragas/Faithfulness.py +5 -4
- validmind/tests/model_validation/ragas/NoiseSensitivity.py +152 -0
- validmind/tests/model_validation/ragas/utils.py +6 -0
- validmind/tests/model_validation/sklearn/AdjustedMutualInformation.py +19 -12
- validmind/tests/model_validation/sklearn/AdjustedRandIndex.py +22 -17
- validmind/tests/model_validation/sklearn/ClassifierPerformance.py +27 -25
- validmind/tests/model_validation/sklearn/ClusterCosineSimilarity.py +7 -5
- validmind/tests/model_validation/sklearn/ClusterPerformance.py +40 -78
- validmind/tests/model_validation/sklearn/ClusterPerformanceMetrics.py +15 -17
- validmind/tests/model_validation/sklearn/CompletenessScore.py +17 -11
- validmind/tests/model_validation/sklearn/ConfusionMatrix.py +22 -15
- validmind/tests/model_validation/sklearn/FeatureImportance.py +95 -0
- validmind/tests/model_validation/sklearn/FowlkesMallowsScore.py +7 -7
- validmind/tests/model_validation/sklearn/HomogeneityScore.py +19 -12
- validmind/tests/model_validation/sklearn/HyperParametersTuning.py +35 -30
- validmind/tests/model_validation/sklearn/KMeansClustersOptimization.py +10 -5
- validmind/tests/model_validation/sklearn/MinimumAccuracy.py +32 -32
- validmind/tests/model_validation/sklearn/MinimumF1Score.py +23 -23
- validmind/tests/model_validation/sklearn/MinimumROCAUCScore.py +15 -10
- validmind/tests/model_validation/sklearn/ModelsPerformanceComparison.py +26 -19
- validmind/tests/model_validation/sklearn/OverfitDiagnosis.py +38 -18
- validmind/tests/model_validation/sklearn/PermutationFeatureImportance.py +32 -26
- validmind/tests/model_validation/sklearn/PopulationStabilityIndex.py +8 -6
- validmind/tests/model_validation/sklearn/PrecisionRecallCurve.py +24 -17
- validmind/tests/model_validation/sklearn/ROCCurve.py +12 -7
- validmind/tests/model_validation/sklearn/RegressionErrors.py +74 -130
- validmind/tests/model_validation/sklearn/RegressionErrorsComparison.py +27 -12
- validmind/tests/model_validation/sklearn/{RegressionModelsPerformanceComparison.py → RegressionPerformance.py} +18 -20
- validmind/tests/model_validation/sklearn/RegressionR2Square.py +55 -94
- validmind/tests/model_validation/sklearn/RegressionR2SquareComparison.py +32 -13
- validmind/tests/model_validation/sklearn/RobustnessDiagnosis.py +36 -32
- validmind/tests/model_validation/sklearn/SHAPGlobalImportance.py +66 -5
- validmind/tests/model_validation/sklearn/SilhouettePlot.py +27 -19
- validmind/tests/model_validation/sklearn/TrainingTestDegradation.py +25 -18
- validmind/tests/model_validation/sklearn/VMeasure.py +14 -13
- validmind/tests/model_validation/sklearn/WeakspotsDiagnosis.py +7 -5
- validmind/tests/model_validation/statsmodels/AutoARIMA.py +24 -18
- validmind/tests/model_validation/statsmodels/CumulativePredictionProbabilities.py +73 -104
- validmind/tests/model_validation/statsmodels/DurbinWatsonTest.py +59 -32
- validmind/tests/model_validation/statsmodels/GINITable.py +44 -77
- validmind/tests/model_validation/statsmodels/KolmogorovSmirnov.py +33 -34
- validmind/tests/model_validation/statsmodels/Lilliefors.py +27 -24
- validmind/tests/model_validation/statsmodels/PredictionProbabilitiesHistogram.py +86 -119
- validmind/tests/model_validation/statsmodels/RegressionCoeffs.py +100 -0
- validmind/tests/model_validation/statsmodels/RegressionFeatureSignificance.py +14 -9
- validmind/tests/model_validation/statsmodels/RegressionModelForecastPlot.py +17 -13
- validmind/tests/model_validation/statsmodels/RegressionModelForecastPlotLevels.py +46 -43
- validmind/tests/model_validation/statsmodels/RegressionModelSensitivityPlot.py +38 -36
- validmind/tests/model_validation/statsmodels/RegressionModelSummary.py +30 -28
- validmind/tests/model_validation/statsmodels/RegressionPermutationFeatureImportance.py +18 -11
- validmind/tests/model_validation/statsmodels/ScorecardHistogram.py +75 -107
- validmind/tests/ongoing_monitoring/FeatureDrift.py +10 -6
- validmind/tests/ongoing_monitoring/PredictionAcrossEachFeature.py +31 -25
- validmind/tests/ongoing_monitoring/PredictionCorrelation.py +29 -21
- validmind/tests/ongoing_monitoring/TargetPredictionDistributionPlot.py +31 -23
- validmind/tests/prompt_validation/Bias.py +14 -11
- validmind/tests/prompt_validation/Clarity.py +16 -14
- validmind/tests/prompt_validation/Conciseness.py +7 -5
- validmind/tests/prompt_validation/Delimitation.py +23 -22
- validmind/tests/prompt_validation/NegativeInstruction.py +7 -5
- validmind/tests/prompt_validation/Robustness.py +12 -10
- validmind/tests/prompt_validation/Specificity.py +13 -11
- validmind/tests/prompt_validation/ai_powered_test.py +6 -0
- validmind/tests/run.py +68 -23
- validmind/unit_metrics/__init__.py +81 -144
- validmind/unit_metrics/classification/{sklearn/Accuracy.py → Accuracy.py} +1 -1
- validmind/unit_metrics/classification/{sklearn/F1.py → F1.py} +1 -1
- validmind/unit_metrics/classification/{sklearn/Precision.py → Precision.py} +1 -1
- validmind/unit_metrics/classification/{sklearn/ROC_AUC.py → ROC_AUC.py} +1 -2
- validmind/unit_metrics/classification/{sklearn/Recall.py → Recall.py} +1 -1
- validmind/unit_metrics/regression/{sklearn/AdjustedRSquaredScore.py → AdjustedRSquaredScore.py} +1 -1
- validmind/unit_metrics/regression/GiniCoefficient.py +1 -1
- validmind/unit_metrics/regression/HuberLoss.py +1 -1
- validmind/unit_metrics/regression/KolmogorovSmirnovStatistic.py +1 -1
- validmind/unit_metrics/regression/{sklearn/MeanAbsoluteError.py → MeanAbsoluteError.py} +1 -1
- validmind/unit_metrics/regression/MeanAbsolutePercentageError.py +1 -1
- validmind/unit_metrics/regression/MeanBiasDeviation.py +1 -1
- validmind/unit_metrics/regression/{sklearn/MeanSquaredError.py → MeanSquaredError.py} +1 -1
- validmind/unit_metrics/regression/QuantileLoss.py +1 -1
- validmind/unit_metrics/regression/{sklearn/RSquaredScore.py → RSquaredScore.py} +1 -1
- validmind/unit_metrics/regression/{sklearn/RootMeanSquaredError.py → RootMeanSquaredError.py} +1 -1
- validmind/utils.py +4 -0
- validmind/vm_models/dataset/dataset.py +2 -0
- validmind/vm_models/figure.py +5 -0
- validmind/vm_models/test/metric.py +1 -0
- validmind/vm_models/test/result_wrapper.py +143 -158
- validmind/vm_models/test/threshold_test.py +1 -0
- {validmind-2.5.8.dist-info → validmind-2.5.18.dist-info}/METADATA +4 -3
- validmind-2.5.18.dist-info/RECORD +324 -0
- validmind/tests/data_validation/ANOVAOneWayTable.py +0 -138
- validmind/tests/data_validation/BivariateFeaturesBarPlots.py +0 -142
- validmind/tests/data_validation/BivariateHistograms.py +0 -117
- validmind/tests/data_validation/HeatmapFeatureCorrelations.py +0 -124
- validmind/tests/data_validation/MissingValuesRisk.py +0 -88
- validmind/tests/model_validation/ModelMetadataComparison.py +0 -59
- validmind/tests/model_validation/sklearn/FeatureImportanceComparison.py +0 -83
- validmind/tests/model_validation/statsmodels/JarqueBera.py +0 -73
- validmind/tests/model_validation/statsmodels/LJungBox.py +0 -66
- validmind/tests/model_validation/statsmodels/RegressionCoeffsPlot.py +0 -135
- validmind/tests/model_validation/statsmodels/RegressionModelsCoeffs.py +0 -103
- validmind/tests/model_validation/statsmodels/RunsTest.py +0 -71
- validmind-2.5.8.dist-info/RECORD +0 -318
- {validmind-2.5.8.dist-info → validmind-2.5.18.dist-info}/LICENSE +0 -0
- {validmind-2.5.8.dist-info → validmind-2.5.18.dist-info}/WHEEL +0 -0
- {validmind-2.5.8.dist-info → validmind-2.5.18.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,172 @@
|
|
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
|
+
import json
|
6
|
+
import sys
|
7
|
+
|
8
|
+
import matplotlib.pyplot as plt
|
9
|
+
import pandas as pd
|
10
|
+
from fairlearn.metrics import (
|
11
|
+
MetricFrame,
|
12
|
+
count,
|
13
|
+
demographic_parity_ratio,
|
14
|
+
equalized_odds_ratio,
|
15
|
+
false_negative_rate,
|
16
|
+
false_positive_rate,
|
17
|
+
true_positive_rate,
|
18
|
+
)
|
19
|
+
from fairlearn.postprocessing import ThresholdOptimizer, plot_threshold_optimizer
|
20
|
+
|
21
|
+
from validmind import tags, tasks
|
22
|
+
from validmind.logging import get_logger
|
23
|
+
|
24
|
+
logger = get_logger(__name__)
|
25
|
+
|
26
|
+
|
27
|
+
@tags("bias_and_fairness")
|
28
|
+
@tasks("classification", "regression")
|
29
|
+
def ProtectedClassesThresholdOptimizer(
|
30
|
+
dataset, pipeline=None, protected_classes=None, X_train=None, y_train=None
|
31
|
+
):
|
32
|
+
"""
|
33
|
+
Obtains a classifier by applying group-specific thresholds to the provided estimator.
|
34
|
+
|
35
|
+
### Purpose
|
36
|
+
|
37
|
+
This test aims to optimize the fairness of a machine learning model by applying different
|
38
|
+
classification thresholds for different protected groups. It helps in mitigating bias and
|
39
|
+
achieving more equitable outcomes across different demographic groups.
|
40
|
+
|
41
|
+
### Test Mechanism
|
42
|
+
|
43
|
+
The test uses Fairlearn's ThresholdOptimizer to:
|
44
|
+
1. Fit an optimizer on the training data, considering protected classes.
|
45
|
+
2. Apply optimized thresholds to make predictions on the test data.
|
46
|
+
3. Calculate and report various fairness metrics.
|
47
|
+
4. Visualize the optimized thresholds.
|
48
|
+
|
49
|
+
### Signs of High Risk
|
50
|
+
|
51
|
+
- Large disparities in fairness metrics (e.g., Demographic Parity Ratio, Equalized Odds Ratio)
|
52
|
+
across different protected groups.
|
53
|
+
- Significant differences in False Positive Rates (FPR) or True Positive Rates (TPR) between groups.
|
54
|
+
- Thresholds that vary widely across different protected groups.
|
55
|
+
|
56
|
+
### Strengths
|
57
|
+
|
58
|
+
- Provides a post-processing method to improve model fairness without modifying the original model.
|
59
|
+
- Allows for balancing multiple fairness criteria simultaneously.
|
60
|
+
- Offers visual insights into the threshold optimization process.
|
61
|
+
|
62
|
+
### Limitations
|
63
|
+
|
64
|
+
- May lead to a decrease in overall model performance while improving fairness.
|
65
|
+
- Requires access to protected attribute information at prediction time.
|
66
|
+
- The effectiveness can vary depending on the chosen fairness constraint and objective.
|
67
|
+
"""
|
68
|
+
|
69
|
+
if sys.version_info < (3, 9):
|
70
|
+
raise RuntimeError("This test requires Python 3.9 or higher.")
|
71
|
+
|
72
|
+
if (
|
73
|
+
pipeline is None
|
74
|
+
or protected_classes is None
|
75
|
+
or X_train is None
|
76
|
+
or y_train is None
|
77
|
+
):
|
78
|
+
logger.warning(
|
79
|
+
"Missing required parameters. Please provide pipeline, protected_classes, X_train, and y_train."
|
80
|
+
)
|
81
|
+
return pd.DataFrame()
|
82
|
+
|
83
|
+
test_df = dataset.df
|
84
|
+
|
85
|
+
threshold_optimizer = initialize_and_fit_optimizer(
|
86
|
+
pipeline, X_train, y_train, X_train[protected_classes]
|
87
|
+
)
|
88
|
+
|
89
|
+
fig = plot_thresholds(threshold_optimizer)
|
90
|
+
|
91
|
+
target = dataset.target_column
|
92
|
+
y_pred_opt = make_predictions(threshold_optimizer, test_df, protected_classes)
|
93
|
+
|
94
|
+
fairness_metrics = calculate_fairness_metrics(
|
95
|
+
test_df, target, y_pred_opt, protected_classes
|
96
|
+
)
|
97
|
+
|
98
|
+
return (
|
99
|
+
{"DPR and EOR Table": fairness_metrics.reset_index()},
|
100
|
+
fig,
|
101
|
+
)
|
102
|
+
|
103
|
+
|
104
|
+
def initialize_and_fit_optimizer(pipeline, X_train, y_train, protected_classes_df):
|
105
|
+
threshold_optimizer = ThresholdOptimizer(
|
106
|
+
estimator=pipeline,
|
107
|
+
objective="balanced_accuracy_score",
|
108
|
+
constraints="demographic_parity",
|
109
|
+
predict_method="predict_proba",
|
110
|
+
prefit=False,
|
111
|
+
)
|
112
|
+
threshold_optimizer.fit(X_train, y_train, sensitive_features=protected_classes_df)
|
113
|
+
return threshold_optimizer
|
114
|
+
|
115
|
+
|
116
|
+
def plot_thresholds(threshold_optimizer):
|
117
|
+
fig = plt.figure()
|
118
|
+
plot_threshold_optimizer(threshold_optimizer, show_plot=False)
|
119
|
+
return fig
|
120
|
+
|
121
|
+
|
122
|
+
def make_predictions(threshold_optimizer, test_df, protected_classes):
|
123
|
+
y_pred_opt = threshold_optimizer.predict(
|
124
|
+
test_df, sensitive_features=test_df[protected_classes]
|
125
|
+
)
|
126
|
+
return y_pred_opt
|
127
|
+
|
128
|
+
|
129
|
+
def calculate_fairness_metrics(test_df, target, y_pred_opt, protected_classes):
|
130
|
+
fairness_metrics = pd.DataFrame(
|
131
|
+
columns=protected_classes,
|
132
|
+
index=["demographic parity ratio", "equal odds ratio"],
|
133
|
+
)
|
134
|
+
|
135
|
+
for feature in protected_classes:
|
136
|
+
dpr = demographic_parity_ratio(
|
137
|
+
y_true=test_df[target],
|
138
|
+
y_pred=y_pred_opt,
|
139
|
+
sensitive_features=test_df[[feature]],
|
140
|
+
)
|
141
|
+
eor = equalized_odds_ratio(
|
142
|
+
y_true=test_df[target],
|
143
|
+
y_pred=y_pred_opt,
|
144
|
+
sensitive_features=test_df[[feature]],
|
145
|
+
)
|
146
|
+
fairness_metrics[feature] = [round(dpr, 2), round(eor, 2)]
|
147
|
+
|
148
|
+
return fairness_metrics
|
149
|
+
|
150
|
+
|
151
|
+
def calculate_group_metrics(test_df, target, y_pred_opt, protected_classes):
|
152
|
+
metrics = {
|
153
|
+
"fpr": false_positive_rate,
|
154
|
+
"tpr": true_positive_rate,
|
155
|
+
"fnr": false_negative_rate,
|
156
|
+
"count": count,
|
157
|
+
}
|
158
|
+
mf = MetricFrame(
|
159
|
+
metrics=metrics,
|
160
|
+
y_true=test_df[target],
|
161
|
+
y_pred=y_pred_opt,
|
162
|
+
sensitive_features=test_df[protected_classes],
|
163
|
+
)
|
164
|
+
group_metrics = mf.by_group
|
165
|
+
return group_metrics
|
166
|
+
|
167
|
+
|
168
|
+
def get_thresholds_by_group(threshold_optimizer):
|
169
|
+
threshold_rules = threshold_optimizer.interpolated_thresholder_.interpolation_dict
|
170
|
+
thresholds = json.dumps(threshold_rules, default=str, indent=4)
|
171
|
+
thresholds_df = pd.DataFrame.from_records(json.loads(thresholds))
|
172
|
+
return thresholds_df
|
@@ -10,41 +10,49 @@ from validmind.vm_models import Figure, Metric
|
|
10
10
|
|
11
11
|
class RollingStatsPlot(Metric):
|
12
12
|
"""
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
for
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
13
|
+
Evaluates the stationarity of time series data by plotting its rolling mean and standard deviation over a specified
|
14
|
+
window.
|
15
|
+
|
16
|
+
### Purpose
|
17
|
+
|
18
|
+
The `RollingStatsPlot` metric is employed to gauge the stationarity of time series data in a given dataset. This
|
19
|
+
metric specifically evaluates the rolling mean and rolling standard deviation of the dataset over a pre-specified
|
20
|
+
window size. The rolling mean provides an understanding of the average trend in the data, while the rolling
|
21
|
+
standard deviation gauges the volatility of the data within the window. It is critical in preparing time series
|
22
|
+
data for modeling as it reveals key insights into data behavior across time.
|
23
|
+
|
24
|
+
### Test Mechanism
|
25
|
+
|
26
|
+
This mechanism is comprised of two steps. Initially, the rolling mean and standard deviation for each of the
|
27
|
+
dataset's columns are calculated over a window size, which can be user-specified or by default set to 12 data
|
28
|
+
points. Then, the calculated rolling mean and standard deviation are visualized via separate plots, illustrating
|
29
|
+
the trends and volatility in the dataset. A straightforward check is conducted to ensure the existence of columns
|
30
|
+
in the dataset, and to verify that the given dataset has been indexed by its date and time—a necessary prerequisite
|
31
|
+
for time series analysis.
|
32
|
+
|
33
|
+
### Signs of High Risk
|
34
|
+
|
29
35
|
- The presence of non-stationary patterns in either the rolling mean or the rolling standard deviation plots, which
|
30
36
|
could indicate trends or seasonality in the data that may affect the performance of time series models.
|
31
37
|
- Missing columns in the dataset, which would prevent the execution of this metric correctly.
|
32
38
|
- The detection of NaN values in the dataset, which may need to be addressed before the metric can proceed
|
33
39
|
successfully.
|
34
40
|
|
35
|
-
|
36
|
-
|
41
|
+
### Strengths
|
42
|
+
|
43
|
+
- Offers visualizations of trending behavior and volatility within the data, facilitating a broader understanding
|
37
44
|
of the dataset's inherent characteristics.
|
38
|
-
- Checks of the dataset's integrity, such as existence of all required columns and the availability of a
|
39
|
-
index.
|
45
|
+
- Checks of the dataset's integrity, such as the existence of all required columns and the availability of a
|
46
|
+
datetime index.
|
40
47
|
- Adjusts to accommodate various window sizes, thus allowing accurate analysis of data with differing temporal
|
41
48
|
granularities.
|
42
49
|
- Considers each column of the data individually, thereby accommodating multi-feature datasets.
|
43
50
|
|
44
|
-
|
45
|
-
|
51
|
+
### Limitations
|
52
|
+
|
53
|
+
- For all columns, a fixed-size window is utilized. This may not accurately capture patterns in datasets where
|
46
54
|
different features may require different optimal window sizes.
|
47
|
-
- Requires the dataset to be indexed by date and time, hence it may not be
|
55
|
+
- Requires the dataset to be indexed by date and time, hence it may not be usable for datasets without a timestamp
|
48
56
|
index.
|
49
57
|
- Primarily serves for data visualization as it does not facilitate any quantitative measures for stationarity,
|
50
58
|
such as through statistical tests. Therefore, the interpretation is subjective and depends heavily on modeler
|
@@ -0,0 +1,72 @@
|
|
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
|
+
import pandas as pd
|
6
|
+
from statsmodels.sandbox.stats.runs import runstest_1samp
|
7
|
+
|
8
|
+
from validmind import tags, tasks
|
9
|
+
|
10
|
+
|
11
|
+
@tasks("classification", "regression")
|
12
|
+
@tags("tabular_data", "statistical_test", "statsmodels")
|
13
|
+
def RunsTest(dataset):
|
14
|
+
"""
|
15
|
+
Executes Runs Test on ML model to detect non-random patterns in output data sequence.
|
16
|
+
|
17
|
+
### Purpose
|
18
|
+
|
19
|
+
The Runs Test is a statistical procedure used to determine whether the sequence of data extracted from the ML model
|
20
|
+
behaves randomly or not. Specifically, it analyzes runs, sequences of consecutive positives or negatives, in the
|
21
|
+
data to check if there are more or fewer runs than expected under the assumption of randomness. This can be an
|
22
|
+
indication of some pattern, trend, or cycle in the model's output which may need attention.
|
23
|
+
|
24
|
+
### Test Mechanism
|
25
|
+
|
26
|
+
The testing mechanism applies the Runs Test from the statsmodels module on each column of the training dataset. For
|
27
|
+
every feature in the dataset, a Runs Test is executed, whose output includes a Runs Statistic and P-value. A low
|
28
|
+
P-value suggests that data arrangement in the feature is not likely to be random. The results are stored in a
|
29
|
+
dictionary where the keys are the feature names, and the values are another dictionary storing the test statistic
|
30
|
+
and the P-value for each feature.
|
31
|
+
|
32
|
+
### Signs of High Risk
|
33
|
+
|
34
|
+
- High risk is indicated when the P-value is close to zero.
|
35
|
+
- If the P-value is less than a predefined significance level (like 0.05), it suggests that the runs (series of
|
36
|
+
positive or negative values) in the model's output are not random and are longer or shorter than what is expected
|
37
|
+
under a random scenario.
|
38
|
+
- This would mean there's a high risk of non-random distribution of errors or model outcomes, suggesting potential
|
39
|
+
issues with the model.
|
40
|
+
|
41
|
+
### Strengths
|
42
|
+
|
43
|
+
- Straightforward and fast for detecting non-random patterns in data sequence.
|
44
|
+
- Validates assumptions of randomness, which is valuable for checking error distributions in regression models,
|
45
|
+
trendless time series data, and ensuring a classifier doesn't favor one class over another.
|
46
|
+
- Can be applied to both classification and regression tasks, making it versatile.
|
47
|
+
|
48
|
+
### Limitations
|
49
|
+
|
50
|
+
- Assumes that the data is independently and identically distributed (i.i.d.), which might not be the case for many
|
51
|
+
real-world datasets.
|
52
|
+
- The conclusion drawn from the low P-value indicating non-randomness does not provide information about the type
|
53
|
+
or the source of the detected pattern.
|
54
|
+
- Sensitive to extreme values (outliers), and overly large or small run sequences can influence the results.
|
55
|
+
- Does not provide model performance evaluation; it is used to detect patterns in the sequence of outputs only.
|
56
|
+
"""
|
57
|
+
|
58
|
+
df = dataset.df[dataset.feature_columns_numeric]
|
59
|
+
|
60
|
+
runs_test_values = {}
|
61
|
+
for col in df.columns:
|
62
|
+
runs_stat, runs_p_value = runstest_1samp(df[col].values)
|
63
|
+
runs_test_values[col] = {
|
64
|
+
"stat": runs_stat,
|
65
|
+
"pvalue": runs_p_value,
|
66
|
+
}
|
67
|
+
|
68
|
+
runs_test_df = pd.DataFrame.from_dict(runs_test_values, orient="index")
|
69
|
+
runs_test_df.reset_index(inplace=True)
|
70
|
+
runs_test_df.columns = ["feature", "stat", "pvalue"]
|
71
|
+
|
72
|
+
return runs_test_df
|
@@ -5,86 +5,71 @@
|
|
5
5
|
import matplotlib.pyplot as plt
|
6
6
|
import seaborn as sns
|
7
7
|
|
8
|
-
from validmind
|
8
|
+
from validmind import tags, tasks
|
9
9
|
|
10
10
|
|
11
|
-
|
11
|
+
@tags("tabular_data", "visualization")
|
12
|
+
@tasks("classification", "regression")
|
13
|
+
def ScatterPlot(dataset):
|
12
14
|
"""
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
- The
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
-
|
41
|
-
|
42
|
-
|
43
|
-
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
-
|
49
|
-
-
|
50
|
-
|
15
|
+
Assesses visual relationships, patterns, and outliers among features in a dataset through scatter plot matrices.
|
16
|
+
|
17
|
+
### Purpose
|
18
|
+
|
19
|
+
The ScatterPlot test aims to visually analyze a given dataset by constructing a scatter plot matrix of its
|
20
|
+
numerical features. The primary goal is to uncover relationships, patterns, and outliers across different features
|
21
|
+
to provide both quantitative and qualitative insights into multidimensional relationships within the dataset. This
|
22
|
+
visual assessment aids in understanding the efficacy of the chosen features for model training and their
|
23
|
+
suitability.
|
24
|
+
|
25
|
+
### Test Mechanism
|
26
|
+
|
27
|
+
Using the Seaborn library, the ScatterPlot function creates the scatter plot matrix. The process involves
|
28
|
+
retrieving all numerical columns from the dataset and generating a scatter matrix for these columns. The resulting
|
29
|
+
scatter plot provides visual representations of feature relationships. The function also adjusts axis labels for
|
30
|
+
readability and returns the final plot as a Matplotlib Figure object for further analysis and visualization.
|
31
|
+
|
32
|
+
### Signs of High Risk
|
33
|
+
|
34
|
+
- The emergence of non-linear or random patterns across different feature pairs, suggesting complex relationships
|
35
|
+
unsuitable for linear assumptions.
|
36
|
+
- Lack of clear patterns or clusters, indicating weak or non-existent correlations among features, which could
|
37
|
+
challenge certain model types.
|
38
|
+
- Presence of outliers, as visual outliers can adversely influence the model's performance.
|
39
|
+
|
40
|
+
### Strengths
|
41
|
+
|
42
|
+
- Provides insight into the multidimensional relationships among multiple features.
|
43
|
+
- Assists in identifying trends, correlations, and outliers that could affect model performance.
|
44
|
+
- Validates assumptions made during model creation, such as linearity.
|
45
|
+
- Versatile for application in both regression and classification tasks.
|
46
|
+
- Using Seaborn facilitates an intuitive and detailed visual exploration of data.
|
47
|
+
|
48
|
+
### Limitations
|
49
|
+
|
50
|
+
- Scatter plot matrices may become cluttered and hard to decipher as the number of features increases.
|
51
|
+
- Primarily reveals pairwise relationships and may fail to illuminate complex interactions involving three or more
|
52
|
+
features.
|
53
|
+
- Being a visual tool, precision in quantitative analysis might be compromised.
|
54
|
+
- Outliers not clearly visible in plots can be missed, affecting model performance.
|
55
|
+
- Assumes that the dataset can fit into the computer's memory, which might not be valid for extremely large
|
56
|
+
datasets.
|
51
57
|
"""
|
52
58
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
# rotate y axis labels
|
71
|
-
ax.set_ylabel(ax.get_ylabel(), rotation=45)
|
72
|
-
# set y labels alignment
|
73
|
-
ax.yaxis.get_label().set_horizontalalignment("right")
|
74
|
-
# Get the current figure
|
75
|
-
fig = plt.gcf()
|
76
|
-
|
77
|
-
figures = []
|
78
|
-
figures.append(
|
79
|
-
Figure(
|
80
|
-
for_object=self,
|
81
|
-
key=self.key,
|
82
|
-
figure=fig,
|
83
|
-
)
|
84
|
-
)
|
85
|
-
|
86
|
-
plt.close("all")
|
87
|
-
|
88
|
-
return self.cache_results(
|
89
|
-
figures=figures,
|
90
|
-
)
|
59
|
+
g = sns.pairplot(data=dataset.df, diag_kind="kde")
|
60
|
+
for ax in g.axes.flatten():
|
61
|
+
# rotate x axis labels
|
62
|
+
ax.set_xlabel(ax.get_xlabel(), rotation=45)
|
63
|
+
# rotate y axis labels
|
64
|
+
ax.set_ylabel(ax.get_ylabel(), rotation=45)
|
65
|
+
# set y labels alignment
|
66
|
+
ax.yaxis.get_label().set_horizontalalignment("right")
|
67
|
+
# Get the current figure
|
68
|
+
fig = plt.gcf()
|
69
|
+
|
70
|
+
figures = []
|
71
|
+
figures.append(fig)
|
72
|
+
|
73
|
+
plt.close("all")
|
74
|
+
|
75
|
+
return tuple(figures)
|
@@ -19,41 +19,45 @@ logger = get_logger(__name__)
|
|
19
19
|
|
20
20
|
class SeasonalDecompose(Metric):
|
21
21
|
"""
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
22
|
+
Assesses patterns and seasonality in a time series dataset by decomposing its features into foundational components.
|
23
|
+
|
24
|
+
### Purpose
|
25
|
+
|
26
|
+
The Seasonal Decompose test aims to decompose the features of a time series dataset into their fundamental
|
27
|
+
components: observed, trend, seasonal, and residuals. By utilizing the Seasonal Decomposition of Time Series by
|
28
|
+
Loess (STL) method, the test identifies underlying patterns, predominantly seasonality, in the dataset's features.
|
29
|
+
This aids in developing a more comprehensive understanding of the dataset, which in turn facilitates more effective
|
30
|
+
model validation.
|
31
|
+
|
32
|
+
### Test Mechanism
|
33
|
+
|
34
|
+
The testing process leverages the `seasonal_decompose` function from the `statsmodels.tsa.seasonal` library to
|
35
|
+
evaluate each feature in the dataset. It isolates each feature into four components—observed, trend, seasonal, and
|
36
|
+
residuals—and generates six subplot graphs per feature for visual interpretation. Prior to decomposition, the test
|
37
|
+
scrutinizes and removes any non-finite values, ensuring the reliability of the analysis.
|
38
|
+
|
39
|
+
### Signs of High Risk
|
40
|
+
|
41
|
+
- **Non-Finiteness**: Datasets with a high number of non-finite values may flag as high risk since these values are
|
38
42
|
omitted before conducting the seasonal decomposition.
|
39
|
-
- **Frequent Warnings**:
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
- **Seasonality Detection**:
|
46
|
-
- **Visualization**:
|
47
|
-
- **Unrestricted Usage**:
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
- **Dependence on Assumptions**:
|
52
|
-
frequency
|
53
|
-
- **Handling Non-
|
54
|
-
|
55
|
-
- **Unreliability with Noisy Datasets**:
|
56
|
-
|
43
|
+
- **Frequent Warnings**: Chronic failure to infer the frequency for a scrutinized feature indicates high risk.
|
44
|
+
- **High Seasonality**: A significant seasonal component could potentially render forecasts unreliable due to
|
45
|
+
overwhelming seasonal variation.
|
46
|
+
|
47
|
+
### Strengths
|
48
|
+
|
49
|
+
- **Seasonality Detection**: Accurately discerns hidden seasonality patterns in dataset features.
|
50
|
+
- **Visualization**: Facilitates interpretation and comprehension through graphical representations.
|
51
|
+
- **Unrestricted Usage**: Not confined to any specific regression model, promoting wide-ranging applicability.
|
52
|
+
|
53
|
+
### Limitations
|
54
|
+
|
55
|
+
- **Dependence on Assumptions**: Assumes that dataset features are periodically distributed. Features with no
|
56
|
+
inferable frequency are excluded from the test.
|
57
|
+
- **Handling Non-Finite Values**: Disregards non-finite values during analysis, potentially resulting in an
|
58
|
+
incomplete understanding of the dataset.
|
59
|
+
- **Unreliability with Noisy Datasets**: Produces unreliable results when used with datasets that contain heavy
|
60
|
+
noise.
|
57
61
|
"""
|
58
62
|
|
59
63
|
name = "seasonal_decompose"
|