validmind 2.13.6__tar.gz → 2.13.7__tar.gz
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-2.13.6 → validmind-2.13.7}/PKG-INFO +1 -1
- {validmind-2.13.6 → validmind-2.13.7}/pyproject.toml +1 -1
- validmind-2.13.7/validmind/__version__.py +1 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/CalibrationCurve.py +10 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ConfusionMatrix.py +10 -5
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/OverfitDiagnosis.py +41 -1
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/PopulationStabilityIndex.py +161 -23
- validmind-2.13.7/validmind/tests/model_validation/sklearn/PrecisionRecallCurve.py +204 -0
- validmind-2.13.7/validmind/tests/model_validation/sklearn/ROCCurve.py +227 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/RobustnessDiagnosis.py +43 -3
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/SHAPGlobalImportance.py +40 -19
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/WeakspotsDiagnosis.py +9 -0
- validmind-2.13.7/validmind/tests/model_validation/sklearn/_diagnosis_metrics.py +126 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/GINITable.py +89 -2
- validmind-2.13.6/validmind/__version__.py +0 -1
- validmind-2.13.6/validmind/tests/model_validation/sklearn/PrecisionRecallCurve.py +0 -96
- validmind-2.13.6/validmind/tests/model_validation/sklearn/ROCCurve.py +0 -112
- {validmind-2.13.6 → validmind-2.13.7}/.gitignore +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/LICENSE +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/README.pypi.md +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/ai/test_descriptions.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/ai/utils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/api_client.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/client.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/client_config.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/credentials_store.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/classification/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/classification/config.json +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/classification/customer_churn.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/classification/datasets/bank_customer_churn.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/classification/datasets/taiwan_credit.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/classification/taiwan_credit.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/cluster/digits.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/credit_risk/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/credit_risk/datasets/lending_club_biased.csv.gz +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/credit_risk/datasets/lending_club_loan_data_2007_2014_clean.csv.gz +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/credit_risk/lending_club.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/credit_risk/lending_club_bias.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/agent_dataset.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/rag/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_1.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_2.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_3.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_4.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_5.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/llm/rag/rfp.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/nlp/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/nlp/cnn_dailymail.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/nlp/datasets/Covid_19.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/nlp/datasets/cnn_dailymail_100_with_predictions.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/nlp/datasets/cnn_dailymail_500_with_predictions.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/nlp/datasets/sentiments_with_predictions.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/nlp/twitter_covid_19.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/california_housing.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/california_housing.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/CPIAUCSL.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/CSUSHPISA.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/DRSFRMACBS.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/FEDFUNDS.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/GDP.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/GDPC1.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/GS10.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/GS3.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/GS5.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/MORTGAGE30US.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred/UNRATE.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred_loan_rates.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred_loan_rates_test_1.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred_loan_rates_test_2.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred_loan_rates_test_3.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred_loan_rates_test_4.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/fred_loan_rates_test_5.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/datasets/leanding_club_loan_rates.csv +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/fred.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/fred_timeseries.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/generate_california_housing_csv.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/datasets/regression/lending_club.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/errors.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/experimental/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/experimental/agents.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/html_templates/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/html_templates/content_blocks.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/input_registry.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/logging.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/foundation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/function.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/huggingface.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/metadata.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/pipeline.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/pytorch.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/r_model.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/models/sklearn.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/oidc_device.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/AbsoluteError.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/BrierScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/CalibrationError.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/ClassBalance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/Confidence.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/Correctness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/LogLoss.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/OutlierScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/ProbabilityError.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/Uncertainty.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/classification/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/AnswerRelevancy.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/ArgumentCorrectness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/Bias.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/ContextualPrecision.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/ContextualRecall.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/ContextualRelevancy.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/Faithfulness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/GEval.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/Hallucination.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/PlanAdherence.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/PlanQuality.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/Summarization.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/TaskCompletion.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/ToolCorrectness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/scorers/llm/deepeval/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/template.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/classifier.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/cluster.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/embeddings.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/llm.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/nlp.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/parameters_optimization.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/regression.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/statsmodels_timeseries.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/summarization.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/tabular_datasets.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/text_data.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/test_suites/time_series.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/__types__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/_store.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/comparison.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ACFandPACFPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ADF.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/AutoAR.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/AutoMA.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/AutoStationarity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/BivariateScatterPlots.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/BoxPierce.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ChiSquaredFeaturesTable.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ClassImbalance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/DatasetDescription.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/DatasetSplit.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/DescriptiveStatistics.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/DickeyFullerGLS.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/Duplicates.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/EngleGrangerCoint.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/FeatureTargetCorrelationPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/HighCardinality.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/HighPearsonCorrelation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/IQROutliersBarPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/IQROutliersTable.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/IsolationForestOutliers.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/JarqueBera.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/KPSS.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/LJungBox.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/LaggedCorrelationHeatmap.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/MissingValues.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/MissingValuesBarPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/MutualInformation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/PearsonCorrelationMatrix.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/PhillipsPerronArch.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ProtectedClassesCombination.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ProtectedClassesDescription.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ProtectedClassesDisparity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ProtectedClassesThresholdOptimizer.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/RollingStatsPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/RunsTest.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ScatterPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ScoreBandDefaultRates.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/SeasonalDecompose.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ShapiroWilk.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/Skewness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/SpreadPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TabularCategoricalBarPlots.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TabularDateTimeHistograms.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TabularDescriptionTables.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TabularNumericalHistograms.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TargetRateBarPlots.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TimeSeriesDescription.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TimeSeriesDescriptiveStatistics.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TimeSeriesFrequency.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TimeSeriesHistogram.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TimeSeriesLinePlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TimeSeriesMissingValues.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TimeSeriesOutliers.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/TooManyZeroValues.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/UniqueRows.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/WOEBinPlots.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/WOEBinTable.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/ZivotAndrewsArch.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/CommonWords.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/Hashtags.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/LanguageDetection.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/Mentions.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/PolarityAndSubjectivity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/Punctuations.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/Sentiment.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/StopWords.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/TextDescription.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/Toxicity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/data_validation/nlp/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/decorator.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/load.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/BertScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/BleuScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ClusterSizeDistribution.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ContextualRecall.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/FeaturesAUC.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/MeteorScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ModelMetadata.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ModelPredictionResiduals.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/RegardScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/RegressionResidualsPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/RougeScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/TimeSeriesPredictionWithCI.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/TimeSeriesPredictionsPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/TimeSeriesR2SquareBySegments.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/TokenDisparity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ToxicityScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/ClusterDistribution.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/CosineSimilarityComparison.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/CosineSimilarityDistribution.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/CosineSimilarityHeatmap.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/DescriptiveAnalytics.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/EmbeddingsVisualization2D.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/EuclideanDistanceComparison.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/EuclideanDistanceHeatmap.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/PCAComponentsPairwisePlots.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/StabilityAnalysisKeyword.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/StabilityAnalysisRandomNoise.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/StabilityAnalysisSynonyms.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/StabilityAnalysisTranslation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/TSNEComponentsPairwisePlots.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/embeddings/utils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/AnswerCorrectness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/AspectCritic.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/ContextEntityRecall.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/ContextPrecision.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/ContextPrecisionWithoutReference.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/ContextRecall.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/Faithfulness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/NoiseSensitivity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/ResponseRelevancy.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/SemanticSimilarity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/ragas/utils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/AdjustedMutualInformation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/AdjustedRandIndex.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ClassifierPerformance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ClassifierThresholdOptimization.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ClusterCosineSimilarity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ClusterPerformanceMetrics.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/CompletenessScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/FeatureImportance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/FowlkesMallowsScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/HomogeneityScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/HyperParametersTuning.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/KMeansClustersOptimization.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/MinimumAccuracy.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/MinimumF1Score.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/MinimumROCAUCScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ModelParameters.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ModelsPerformanceComparison.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/PermutationFeatureImportance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/RegressionErrors.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/RegressionErrorsComparison.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/RegressionPerformance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/RegressionR2Square.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/RegressionR2SquareComparison.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ScoreProbabilityAlignment.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/SilhouettePlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/TrainingTestDegradation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/VMeasure.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/AutoARIMA.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/CumulativePredictionProbabilities.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/DurbinWatsonTest.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/KolmogorovSmirnov.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/Lilliefors.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/PredictionProbabilitiesHistogram.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/RegressionCoeffs.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/RegressionFeatureSignificance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/RegressionModelForecastPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/RegressionModelForecastPlotLevels.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/RegressionModelSensitivityPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/RegressionModelSummary.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/RegressionPermutationFeatureImportance.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/ScorecardHistogram.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/statsmodels/statsutils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/CalibrationCurveDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/ClassDiscriminationDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/ClassImbalanceDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/ClassificationAccuracyDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/ConfusionMatrixDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/CumulativePredictionProbabilitiesDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/FeatureDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/PredictionAcrossEachFeature.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/PredictionCorrelation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/PredictionProbabilitiesHistogramDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/PredictionQuantilesAcrossFeatures.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/ROCCurveDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/ScoreBandsDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/ScorecardHistogramDrift.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/ongoing_monitoring/TargetPredictionDistributionPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/output.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/plots/BoxPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/plots/CorrelationHeatmap.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/plots/HistogramPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/plots/ViolinPlot.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/plots/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/Bias.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/Clarity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/Conciseness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/Delimitation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/NegativeInstruction.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/Robustness.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/Specificity.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/prompt_validation/ai_powered_test.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/run.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/stats/CorrelationAnalysis.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/stats/DescriptiveStats.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/stats/NormalityTests.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/stats/OutlierDetection.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/stats/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/test_providers.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/tests/utils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/classification/Accuracy.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/classification/F1.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/classification/Precision.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/classification/ROC_AUC.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/classification/Recall.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/AdjustedRSquaredScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/GiniCoefficient.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/HuberLoss.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/KolmogorovSmirnovStatistic.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/MeanAbsoluteError.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/MeanAbsolutePercentageError.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/MeanBiasDeviation.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/MeanSquaredError.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/QuantileLoss.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/RSquaredScore.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/unit_metrics/regression/RootMeanSquaredError.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/utils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/dataset/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/dataset/dataset.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/dataset/utils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/figure.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/html_progress.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/html_renderer.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/input.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/model.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/result/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/result/pii_filter.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/result/result.jinja +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/result/result.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/result/utils.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/test_suite/__init__.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/test_suite/runner.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/test_suite/summary.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/test_suite/test.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/test_suite/test_suite.py +0 -0
- {validmind-2.13.6 → validmind-2.13.7}/validmind/vm_models/text_generation_summary.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: validmind
|
|
3
|
-
Version: 2.13.
|
|
3
|
+
Version: 2.13.7
|
|
4
4
|
Summary: ValidMind Library
|
|
5
5
|
Author-email: Andres Rodriguez <andres@validmind.ai>, Juan Martinez <juan@validmind.ai>, Anil Sorathiya <anil@validmind.ai>, Luis Pallares <luis@validmind.ai>, John Walz <john@validmind.ai>
|
|
6
6
|
License: DUAL LICENSE NOTICE
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.13.7"
|
{validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/CalibrationCurve.py
RENAMED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
from typing import Tuple
|
|
6
6
|
|
|
7
|
+
import numpy as np
|
|
7
8
|
import plotly.graph_objects as go
|
|
8
9
|
from sklearn.calibration import calibration_curve
|
|
9
10
|
|
|
10
11
|
from validmind import tags, tasks
|
|
12
|
+
from validmind.errors import SkipTestError
|
|
11
13
|
from validmind.vm_models import VMDataset, VMModel
|
|
12
14
|
from validmind.vm_models.result import RawData
|
|
13
15
|
|
|
@@ -70,6 +72,14 @@ def CalibrationCurve(
|
|
|
70
72
|
- Assumes bin boundaries are appropriate for the problem
|
|
71
73
|
- May be affected by class imbalance
|
|
72
74
|
"""
|
|
75
|
+
# Binary-only by design: sklearn's calibration_curve raises a cryptic
|
|
76
|
+
# "pos_label is not specified" error on multiclass targets, so skip cleanly
|
|
77
|
+
# like ROCCurve/PrecisionRecallCurve rather than crashing.
|
|
78
|
+
if len(np.unique(dataset.y)) > 2:
|
|
79
|
+
raise SkipTestError(
|
|
80
|
+
"Calibration Curve is only supported for binary classification models"
|
|
81
|
+
)
|
|
82
|
+
|
|
73
83
|
prob_true, prob_pred = calibration_curve(
|
|
74
84
|
dataset.y, dataset.y_prob(model), n_bins=n_bins
|
|
75
85
|
)
|
{validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/ConfusionMatrix.py
RENAMED
|
@@ -72,15 +72,20 @@ def ConfusionMatrix(
|
|
|
72
72
|
- It mainly serves as a descriptive tool and does not offer the capability for statistical hypothesis testing.
|
|
73
73
|
- Risks of misinterpretation exist because the matrix doesn't directly provide precision, recall, or F1-score data.
|
|
74
74
|
These metrics have to be computed separately.
|
|
75
|
+
- The `threshold` parameter only applies to binary classification (it splits a single positive-class probability
|
|
76
|
+
into two classes). For multiclass targets the model's argmax class predictions are used and `threshold` is ignored.
|
|
75
77
|
"""
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
+
# The `threshold` only has a meaning for binary classification (it splits a
|
|
79
|
+
# single positive-class probability into two classes). For multiclass we use
|
|
80
|
+
# the model's argmax class predictions directly, since thresholding a
|
|
81
|
+
# single probability column would silently produce wrong labels.
|
|
82
|
+
n_classes = len(np.unique(dataset.y))
|
|
83
|
+
if n_classes == 2 and hasattr(model.model, "predict_proba"):
|
|
78
84
|
y_prob = dataset.y_prob(model)
|
|
79
85
|
# Handle both 1D and 2D probability arrays
|
|
80
86
|
if y_prob.ndim == 2:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
y_pred = (y_prob > threshold).astype(int)
|
|
87
|
+
y_prob = y_prob[:, 1]
|
|
88
|
+
y_pred = (y_prob > threshold).astype(int)
|
|
84
89
|
else:
|
|
85
90
|
y_pred = dataset.y_pred(model)
|
|
86
91
|
|
{validmind-2.13.6 → validmind-2.13.7}/validmind/tests/model_validation/sklearn/OverfitDiagnosis.py
RENAMED
|
@@ -15,6 +15,8 @@ from validmind import RawData, tags, tasks
|
|
|
15
15
|
from validmind.logging import get_logger
|
|
16
16
|
from validmind.vm_models import VMDataset, VMModel
|
|
17
17
|
|
|
18
|
+
from ._diagnosis_metrics import bind_averaging, full_labels, multiclass_auc
|
|
19
|
+
|
|
18
20
|
logger = get_logger(__name__)
|
|
19
21
|
|
|
20
22
|
# TODO: A couple of improvements here could be to:
|
|
@@ -96,6 +98,10 @@ def _compute_metrics(
|
|
|
96
98
|
feature_column: str,
|
|
97
99
|
metric: str,
|
|
98
100
|
is_classification: bool,
|
|
101
|
+
average: str = None,
|
|
102
|
+
pos_label=None,
|
|
103
|
+
labels: list = None,
|
|
104
|
+
is_multiclass: bool = False,
|
|
99
105
|
) -> None:
|
|
100
106
|
results["slice"].append(str(region))
|
|
101
107
|
results["shape"].append(df_region.shape[0])
|
|
@@ -115,11 +121,25 @@ def _compute_metrics(
|
|
|
115
121
|
if len(np.unique(y_true)) == 1:
|
|
116
122
|
return results[metric].append(0)
|
|
117
123
|
|
|
124
|
+
# The library retains only a single probability column, so a
|
|
125
|
+
# probability-based multiclass ROC AUC is not possible; fall back to the
|
|
126
|
+
# label-binarize convention used elsewhere for multiclass targets.
|
|
127
|
+
if is_multiclass:
|
|
128
|
+
return results[metric].append(
|
|
129
|
+
multiclass_auc(y_true, df_region[pred_column].values, labels)
|
|
130
|
+
)
|
|
131
|
+
|
|
118
132
|
return results[metric].append(
|
|
119
133
|
metric_func(y_true, df_region[prob_column].values)
|
|
120
134
|
)
|
|
121
135
|
|
|
122
|
-
|
|
136
|
+
# Bind averaging so precision/recall/F1 handle multiclass targets and binary
|
|
137
|
+
# targets encoded outside {0, 1}; accuracy and regression metrics pass through.
|
|
138
|
+
return results[metric].append(
|
|
139
|
+
bind_averaging(metric_func, average, pos_label)(
|
|
140
|
+
y_true, df_region[pred_column].values
|
|
141
|
+
)
|
|
142
|
+
)
|
|
123
143
|
|
|
124
144
|
|
|
125
145
|
def _plot_overfit_regions(
|
|
@@ -253,6 +273,18 @@ def OverfitDiagnosis(
|
|
|
253
273
|
train_df[prob_column] = datasets[0].y_prob(model)
|
|
254
274
|
test_df[prob_column] = datasets[1].y_prob(model)
|
|
255
275
|
|
|
276
|
+
# Resolve the label space once so every feature slice is scored consistently:
|
|
277
|
+
# multiclass targets use macro averaging (and label-binarize AUC), binary
|
|
278
|
+
# targets keep the positive label so non-{0, 1} encodings don't break.
|
|
279
|
+
if is_classification:
|
|
280
|
+
labels = full_labels(datasets, model)
|
|
281
|
+
is_multiclass = len(labels) > 2
|
|
282
|
+
average, pos_label = (
|
|
283
|
+
("macro", None) if is_multiclass else ("binary", labels[-1])
|
|
284
|
+
)
|
|
285
|
+
else:
|
|
286
|
+
labels, is_multiclass, average, pos_label = None, False, None, None
|
|
287
|
+
|
|
256
288
|
test_results = []
|
|
257
289
|
figures = []
|
|
258
290
|
results_headers = ["slice", "shape", "feature", metric]
|
|
@@ -277,6 +309,10 @@ def OverfitDiagnosis(
|
|
|
277
309
|
pred_column=pred_column,
|
|
278
310
|
metric=metric,
|
|
279
311
|
is_classification=is_classification,
|
|
312
|
+
average=average,
|
|
313
|
+
pos_label=pos_label,
|
|
314
|
+
labels=labels,
|
|
315
|
+
is_multiclass=is_multiclass,
|
|
280
316
|
)
|
|
281
317
|
df_test_region = test_df[
|
|
282
318
|
(test_df[feature_column] > region.left)
|
|
@@ -292,6 +328,10 @@ def OverfitDiagnosis(
|
|
|
292
328
|
pred_column=pred_column,
|
|
293
329
|
metric=metric,
|
|
294
330
|
is_classification=is_classification,
|
|
331
|
+
average=average,
|
|
332
|
+
pos_label=pos_label,
|
|
333
|
+
labels=labels,
|
|
334
|
+
is_multiclass=is_multiclass,
|
|
295
335
|
)
|
|
296
336
|
|
|
297
337
|
results = _prepare_results(results_train, results_test, metric)
|
|
@@ -7,6 +7,7 @@ from typing import Dict, List, Tuple
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import pandas as pd
|
|
9
9
|
import plotly.graph_objects as go
|
|
10
|
+
from plotly.subplots import make_subplots
|
|
10
11
|
|
|
11
12
|
from validmind import RawData, tags, tasks
|
|
12
13
|
from validmind.errors import SkipTestError
|
|
@@ -15,6 +16,8 @@ from validmind.vm_models import VMDataset, VMModel
|
|
|
15
16
|
|
|
16
17
|
logger = get_logger(__name__)
|
|
17
18
|
|
|
19
|
+
_PSI_PALETTE = ["#DE257E", "#1F77B4", "#2CA02C", "#FF7F0E", "#9467BD", "#8C564B"]
|
|
20
|
+
|
|
18
21
|
|
|
19
22
|
def calculate_psi(score_initial, score_new, num_bins=10, mode="fixed"):
|
|
20
23
|
"""
|
|
@@ -76,6 +79,152 @@ def calculate_psi(score_initial, score_new, num_bins=10, mode="fixed"):
|
|
|
76
79
|
return psi_df.to_dict(orient="records")
|
|
77
80
|
|
|
78
81
|
|
|
82
|
+
def _psi_table_rows(psi_results):
|
|
83
|
+
"""Append the summed 'Total' row and format PSI records as table rows."""
|
|
84
|
+
total_psi = {
|
|
85
|
+
key: sum(d.get(key, 0) for d in psi_results)
|
|
86
|
+
for key in psi_results[0].keys()
|
|
87
|
+
if isinstance(psi_results[0][key], (int, float))
|
|
88
|
+
}
|
|
89
|
+
rows_with_total = psi_results + [total_psi]
|
|
90
|
+
|
|
91
|
+
table_rows = [
|
|
92
|
+
{
|
|
93
|
+
"Bin": (
|
|
94
|
+
i if i < (len(rows_with_total) - 1) else "Total"
|
|
95
|
+
), # The last bin is the "Total" bin
|
|
96
|
+
"Count Initial": values["initial"],
|
|
97
|
+
"Percent Initial (%)": values["percent_initial"] * 100,
|
|
98
|
+
"Count New": values["new"],
|
|
99
|
+
"Percent New (%)": values["percent_new"] * 100,
|
|
100
|
+
"PSI": values["psi"],
|
|
101
|
+
}
|
|
102
|
+
for i, values in enumerate(rows_with_total)
|
|
103
|
+
]
|
|
104
|
+
return rows_with_total, table_rows
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _multiclass_psi(datasets, model, classes, num_bins, mode):
|
|
108
|
+
"""One-vs-rest PSI for a multiclass model.
|
|
109
|
+
|
|
110
|
+
PSI needs a 1-D score distribution to compare across the two datasets. The
|
|
111
|
+
stored single probability column cannot represent every class, so we ask the
|
|
112
|
+
underlying estimator for the full per-class probability matrix (mirroring the
|
|
113
|
+
ROC/PR curve tests). Models without a usable ``predict_proba`` (metadata-only
|
|
114
|
+
/ precomputed single-column predictions) are skipped rather than crashed.
|
|
115
|
+
"""
|
|
116
|
+
raw_model = getattr(model, "model", None)
|
|
117
|
+
proba_fn = getattr(raw_model, "predict_proba", None)
|
|
118
|
+
if not callable(proba_fn):
|
|
119
|
+
raise SkipTestError(
|
|
120
|
+
"Multiclass Population Stability Index requires per-class "
|
|
121
|
+
"probabilities from the underlying model's predict_proba, which is "
|
|
122
|
+
"not available for this model (e.g. metadata-only / precomputed "
|
|
123
|
+
"predictions). Skipping."
|
|
124
|
+
)
|
|
125
|
+
try:
|
|
126
|
+
prob_initial = np.asarray(proba_fn(datasets[0].x_df()))
|
|
127
|
+
prob_new = np.asarray(proba_fn(datasets[1].x_df()))
|
|
128
|
+
except Exception as e:
|
|
129
|
+
raise SkipTestError(
|
|
130
|
+
"Multiclass Population Stability Index could not compute per-class "
|
|
131
|
+
f"probabilities ({type(e).__name__}). Skipping."
|
|
132
|
+
) from e
|
|
133
|
+
|
|
134
|
+
n_classes = len(classes)
|
|
135
|
+
for prob in (prob_initial, prob_new):
|
|
136
|
+
if prob.ndim != 2 or prob.shape[1] != n_classes:
|
|
137
|
+
raise SkipTestError(
|
|
138
|
+
"Multiclass Population Stability Index requires a per-class "
|
|
139
|
+
f"probability matrix with one column per class (got shape "
|
|
140
|
+
f"{getattr(prob, 'shape', None)} for {n_classes} classes). Skipping."
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# predict_proba columns are ordered by sorted class label == np.unique.
|
|
144
|
+
fig = make_subplots(
|
|
145
|
+
rows=n_classes,
|
|
146
|
+
cols=1,
|
|
147
|
+
specs=[[{"secondary_y": True}] for _ in range(n_classes)],
|
|
148
|
+
subplot_titles=[f"Class {cls}" for cls in classes],
|
|
149
|
+
vertical_spacing=0.08,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
tables = {}
|
|
153
|
+
raw_per_class = {}
|
|
154
|
+
for i, cls in enumerate(classes):
|
|
155
|
+
psi_results = calculate_psi(
|
|
156
|
+
prob_initial[:, i].copy(),
|
|
157
|
+
prob_new[:, i].copy(),
|
|
158
|
+
num_bins=num_bins,
|
|
159
|
+
mode=mode,
|
|
160
|
+
)
|
|
161
|
+
x = list(range(len(psi_results)))
|
|
162
|
+
color = _PSI_PALETTE[i % len(_PSI_PALETTE)]
|
|
163
|
+
fig.add_trace(
|
|
164
|
+
go.Bar(
|
|
165
|
+
x=x,
|
|
166
|
+
y=[d["percent_initial"] for d in psi_results],
|
|
167
|
+
name="Initial",
|
|
168
|
+
marker=dict(color="#DE257E"),
|
|
169
|
+
showlegend=i == 0,
|
|
170
|
+
legendgroup="initial",
|
|
171
|
+
),
|
|
172
|
+
row=i + 1,
|
|
173
|
+
col=1,
|
|
174
|
+
secondary_y=False,
|
|
175
|
+
)
|
|
176
|
+
fig.add_trace(
|
|
177
|
+
go.Bar(
|
|
178
|
+
x=x,
|
|
179
|
+
y=[d["percent_new"] for d in psi_results],
|
|
180
|
+
name="New",
|
|
181
|
+
marker=dict(color="#E8B1F8"),
|
|
182
|
+
showlegend=i == 0,
|
|
183
|
+
legendgroup="new",
|
|
184
|
+
),
|
|
185
|
+
row=i + 1,
|
|
186
|
+
col=1,
|
|
187
|
+
secondary_y=False,
|
|
188
|
+
)
|
|
189
|
+
fig.add_trace(
|
|
190
|
+
go.Scatter(
|
|
191
|
+
x=x,
|
|
192
|
+
y=[d["psi"] for d in psi_results],
|
|
193
|
+
name="PSI",
|
|
194
|
+
line=dict(color=color),
|
|
195
|
+
showlegend=i == 0,
|
|
196
|
+
legendgroup="psi",
|
|
197
|
+
),
|
|
198
|
+
row=i + 1,
|
|
199
|
+
col=1,
|
|
200
|
+
secondary_y=True,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
rows_with_total, table_rows = _psi_table_rows(psi_results)
|
|
204
|
+
table_title = (
|
|
205
|
+
f"Population Stability Index for Class {cls} "
|
|
206
|
+
f"({datasets[0].input_id} vs {datasets[1].input_id})"
|
|
207
|
+
)
|
|
208
|
+
tables[table_title] = table_rows
|
|
209
|
+
raw_per_class[str(cls)] = rows_with_total
|
|
210
|
+
|
|
211
|
+
fig.update_layout(
|
|
212
|
+
title="Population Stability Index (PSI) — one-vs-rest per class",
|
|
213
|
+
barmode="group",
|
|
214
|
+
height=300 * n_classes,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
tables,
|
|
219
|
+
fig,
|
|
220
|
+
RawData(
|
|
221
|
+
psi_raw=raw_per_class,
|
|
222
|
+
model=model.input_id,
|
|
223
|
+
datasets=[datasets[0].input_id, datasets[1].input_id],
|
|
224
|
+
),
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
79
228
|
@tags(
|
|
80
229
|
"sklearn", "binary_classification", "multiclass_classification", "model_performance"
|
|
81
230
|
)
|
|
@@ -132,10 +281,18 @@ def PopulationStabilityIndex(
|
|
|
132
281
|
lead to misinterpretations. Any changes in PSI could be due to shifts in the model (model drift), changes in the
|
|
133
282
|
relationships between features and the target variable (concept drift), or both. However, distinguishing between
|
|
134
283
|
these causes is non-trivial.
|
|
284
|
+
- For multiclass models the PSI is computed one-vs-rest (one table/plot per class), which requires per-class
|
|
285
|
+
probabilities from the model's `predict_proba`. Models that cannot produce a full per-class probability matrix
|
|
286
|
+
(e.g. metadata-only models, or predictions supplied as a single precomputed probability column) are skipped for
|
|
287
|
+
the multiclass case.
|
|
135
288
|
"""
|
|
136
289
|
if model.library in ["statsmodels", "pytorch", "catboost"]:
|
|
137
290
|
raise SkipTestError(f"Skiping PSI for {model.library} models")
|
|
138
291
|
|
|
292
|
+
classes = np.unique(datasets[0].y)
|
|
293
|
+
if len(classes) > 2:
|
|
294
|
+
return _multiclass_psi(datasets, model, classes, num_bins, mode)
|
|
295
|
+
|
|
139
296
|
psi_results = calculate_psi(
|
|
140
297
|
datasets[0].y_prob(model).copy(),
|
|
141
298
|
datasets[1].y_prob(model).copy(),
|
|
@@ -182,35 +339,16 @@ def PopulationStabilityIndex(
|
|
|
182
339
|
),
|
|
183
340
|
)
|
|
184
341
|
|
|
185
|
-
# sum up the PSI values to get the total values
|
|
186
|
-
|
|
187
|
-
key: sum(d.get(key, 0) for d in psi_results)
|
|
188
|
-
for key in psi_results[0].keys()
|
|
189
|
-
if isinstance(psi_results[0][key], (int, float))
|
|
190
|
-
}
|
|
191
|
-
psi_results.append(total_psi)
|
|
342
|
+
# sum up the PSI values to get the total values and format the table rows
|
|
343
|
+
rows_with_total, table_rows = _psi_table_rows(psi_results)
|
|
192
344
|
|
|
193
345
|
table_title = f"Population Stability Index for {datasets[0].input_id} and {datasets[1].input_id} Datasets"
|
|
194
346
|
|
|
195
347
|
return (
|
|
196
|
-
{
|
|
197
|
-
table_title: [
|
|
198
|
-
{
|
|
199
|
-
"Bin": (
|
|
200
|
-
i if i < (len(psi_results) - 1) else "Total"
|
|
201
|
-
), # The last bin is the "Total" bin
|
|
202
|
-
"Count Initial": values["initial"],
|
|
203
|
-
"Percent Initial (%)": values["percent_initial"] * 100,
|
|
204
|
-
"Count New": values["new"],
|
|
205
|
-
"Percent New (%)": values["percent_new"] * 100,
|
|
206
|
-
"PSI": values["psi"],
|
|
207
|
-
}
|
|
208
|
-
for i, values in enumerate(psi_results)
|
|
209
|
-
],
|
|
210
|
-
},
|
|
348
|
+
{table_title: table_rows},
|
|
211
349
|
fig,
|
|
212
350
|
RawData(
|
|
213
|
-
psi_raw=
|
|
351
|
+
psi_raw=rows_with_total,
|
|
214
352
|
model=model.input_id,
|
|
215
353
|
datasets=[datasets[0].input_id, datasets[1].input_id],
|
|
216
354
|
),
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Copyright © 2023-2026 ValidMind Inc. All rights reserved.
|
|
2
|
+
# Refer to 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 Tuple
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import plotly.graph_objects as go
|
|
9
|
+
from sklearn.metrics import average_precision_score, precision_recall_curve
|
|
10
|
+
from sklearn.preprocessing import label_binarize
|
|
11
|
+
|
|
12
|
+
from validmind import RawData, tags, tasks
|
|
13
|
+
from validmind.errors import SkipTestError
|
|
14
|
+
from validmind.models import FoundationModel
|
|
15
|
+
from validmind.vm_models import VMDataset, VMModel
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@tags(
|
|
19
|
+
"sklearn",
|
|
20
|
+
"binary_classification",
|
|
21
|
+
"multiclass_classification",
|
|
22
|
+
"model_performance",
|
|
23
|
+
"visualization",
|
|
24
|
+
)
|
|
25
|
+
@tasks("classification", "text_classification")
|
|
26
|
+
def PrecisionRecallCurve(
|
|
27
|
+
model: VMModel, dataset: VMDataset
|
|
28
|
+
) -> Tuple[go.Figure, RawData]:
|
|
29
|
+
"""
|
|
30
|
+
Evaluates the precision-recall trade-off for binary classification models and visualizes the Precision-Recall curve.
|
|
31
|
+
|
|
32
|
+
### Purpose
|
|
33
|
+
|
|
34
|
+
The Precision Recall Curve metric is intended to evaluate the trade-off between precision and recall in
|
|
35
|
+
classification models, particularly binary classification models. It assesses the model's capacity to produce
|
|
36
|
+
accurate results (high precision), as well as its ability to capture a majority of all positive instances (high
|
|
37
|
+
recall).
|
|
38
|
+
|
|
39
|
+
### Test Mechanism
|
|
40
|
+
|
|
41
|
+
The test extracts ground truth labels and prediction probabilities from the model's test dataset. It applies the
|
|
42
|
+
`precision_recall_curve` method from the sklearn metrics module to these extracted labels and predictions, which
|
|
43
|
+
computes a precision-recall pair for each possible threshold. This calculation results in an array of precision and
|
|
44
|
+
recall scores that can be plotted against each other to form the Precision-Recall Curve. This curve is then
|
|
45
|
+
visually represented by using Plotly's scatter plot.
|
|
46
|
+
|
|
47
|
+
### Signs of High Risk
|
|
48
|
+
|
|
49
|
+
- A lower area under the Precision-Recall Curve signifies high risk.
|
|
50
|
+
- This corresponds to a model yielding a high amount of false positives (low precision) and/or false negatives (low
|
|
51
|
+
recall).
|
|
52
|
+
- If the curve is closer to the bottom left of the plot, rather than being closer to the top right corner, it can
|
|
53
|
+
be a sign of high risk.
|
|
54
|
+
|
|
55
|
+
### Strengths
|
|
56
|
+
|
|
57
|
+
- This metric aptly represents the balance between precision (minimizing false positives) and recall (minimizing
|
|
58
|
+
false negatives), which is especially critical in scenarios where both values are significant.
|
|
59
|
+
- Through the graphic representation, it enables an intuitive understanding of the model's performance across
|
|
60
|
+
different threshold levels.
|
|
61
|
+
|
|
62
|
+
### Limitations
|
|
63
|
+
|
|
64
|
+
- For multiclass models the curve is computed one-vs-rest (one curve per class plus a micro-average), which
|
|
65
|
+
requires per-class probabilities from the model's `predict_proba`. Models that cannot produce a full per-class
|
|
66
|
+
probability matrix (e.g. Foundation/metadata-only models, or predictions supplied as a single precomputed
|
|
67
|
+
probability column) are skipped for the multiclass case.
|
|
68
|
+
- It may not fully represent the overall accuracy of the model if the cost of false positives and false negatives
|
|
69
|
+
are extremely different, or if the dataset is heavily imbalanced.
|
|
70
|
+
"""
|
|
71
|
+
if isinstance(model, FoundationModel):
|
|
72
|
+
raise SkipTestError("Skipping PrecisionRecallCurve for Foundation models")
|
|
73
|
+
|
|
74
|
+
y_true = dataset.y
|
|
75
|
+
classes = np.unique(y_true)
|
|
76
|
+
|
|
77
|
+
if len(classes) > 2:
|
|
78
|
+
return _multiclass_pr_curve(model, dataset, classes)
|
|
79
|
+
|
|
80
|
+
precision, recall, _ = precision_recall_curve(y_true, dataset.y_prob(model))
|
|
81
|
+
|
|
82
|
+
fig = go.Figure(
|
|
83
|
+
data=[
|
|
84
|
+
go.Scatter(
|
|
85
|
+
x=recall,
|
|
86
|
+
y=precision,
|
|
87
|
+
mode="lines",
|
|
88
|
+
name="Precision-Recall Curve",
|
|
89
|
+
line=dict(color="#DE257E"),
|
|
90
|
+
)
|
|
91
|
+
],
|
|
92
|
+
layout=go.Layout(
|
|
93
|
+
title="Precision-Recall Curve",
|
|
94
|
+
xaxis=dict(title="Recall"),
|
|
95
|
+
yaxis=dict(title="Precision"),
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return fig, RawData(
|
|
100
|
+
precision=precision,
|
|
101
|
+
recall=recall,
|
|
102
|
+
model=model.input_id,
|
|
103
|
+
dataset=dataset.input_id,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _multiclass_pr_curve(
|
|
108
|
+
model: VMModel, dataset: VMDataset, classes: np.ndarray
|
|
109
|
+
) -> Tuple[go.Figure, RawData]:
|
|
110
|
+
"""One-vs-rest precision-recall curves for a multiclass model.
|
|
111
|
+
|
|
112
|
+
Needs the full per-class probability matrix, which the stored single
|
|
113
|
+
probability column cannot provide, so we ask the model for it directly.
|
|
114
|
+
Models without a usable ``predict_proba`` (Foundation/metadata-only,
|
|
115
|
+
precomputed single-column probabilities) are skipped rather than crashed.
|
|
116
|
+
"""
|
|
117
|
+
# The VMModel wrapper's predict_proba is binary-only (it returns just the
|
|
118
|
+
# positive-class column), so reach the underlying estimator for the full
|
|
119
|
+
# per-class probability matrix.
|
|
120
|
+
raw_model = getattr(model, "model", None)
|
|
121
|
+
proba_fn = getattr(raw_model, "predict_proba", None)
|
|
122
|
+
if not callable(proba_fn):
|
|
123
|
+
raise SkipTestError(
|
|
124
|
+
"Multiclass Precision-Recall Curve requires per-class probabilities "
|
|
125
|
+
"from the underlying model's predict_proba, which is not available "
|
|
126
|
+
"for this model (e.g. Foundation / metadata-only / precomputed "
|
|
127
|
+
"predictions). Skipping."
|
|
128
|
+
)
|
|
129
|
+
try:
|
|
130
|
+
y_prob = np.asarray(proba_fn(dataset.x_df()))
|
|
131
|
+
except Exception as e:
|
|
132
|
+
raise SkipTestError(
|
|
133
|
+
"Multiclass Precision-Recall Curve could not compute per-class "
|
|
134
|
+
f"probabilities ({type(e).__name__}). Skipping."
|
|
135
|
+
) from e
|
|
136
|
+
|
|
137
|
+
n_classes = len(classes)
|
|
138
|
+
if y_prob.ndim != 2 or y_prob.shape[1] != n_classes:
|
|
139
|
+
raise SkipTestError(
|
|
140
|
+
"Multiclass Precision-Recall Curve requires a per-class probability "
|
|
141
|
+
f"matrix with one column per class (got shape "
|
|
142
|
+
f"{getattr(y_prob, 'shape', None)} for {n_classes} classes). Skipping."
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# One-hot the true labels in the same class order predict_proba columns use
|
|
146
|
+
# (sklearn orders predict_proba columns by sorted class label == np.unique).
|
|
147
|
+
y_bin = label_binarize(dataset.y.flatten(), classes=classes)
|
|
148
|
+
|
|
149
|
+
traces = []
|
|
150
|
+
raw_precision = {}
|
|
151
|
+
raw_recall = {}
|
|
152
|
+
raw_ap = {}
|
|
153
|
+
palette = ["#DE257E", "#1F77B4", "#2CA02C", "#FF7F0E", "#9467BD", "#8C564B"]
|
|
154
|
+
for i, cls in enumerate(classes):
|
|
155
|
+
precision, recall, _ = precision_recall_curve(y_bin[:, i], y_prob[:, i])
|
|
156
|
+
ap = average_precision_score(y_bin[:, i], y_prob[:, i])
|
|
157
|
+
key = str(cls)
|
|
158
|
+
raw_precision[key] = precision
|
|
159
|
+
raw_recall[key] = recall
|
|
160
|
+
raw_ap[key] = ap
|
|
161
|
+
traces.append(
|
|
162
|
+
go.Scatter(
|
|
163
|
+
x=recall,
|
|
164
|
+
y=precision,
|
|
165
|
+
mode="lines",
|
|
166
|
+
name=f"Class {key} (AP = {ap:.2f})",
|
|
167
|
+
line=dict(color=palette[i % len(palette)]),
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Micro-average across all one-vs-rest decisions.
|
|
172
|
+
micro_precision, micro_recall, _ = precision_recall_curve(
|
|
173
|
+
y_bin.ravel(), y_prob.ravel()
|
|
174
|
+
)
|
|
175
|
+
micro_ap = average_precision_score(y_bin, y_prob, average="micro")
|
|
176
|
+
raw_precision["micro"] = micro_precision
|
|
177
|
+
raw_recall["micro"] = micro_recall
|
|
178
|
+
raw_ap["micro"] = micro_ap
|
|
179
|
+
traces.append(
|
|
180
|
+
go.Scatter(
|
|
181
|
+
x=micro_recall,
|
|
182
|
+
y=micro_precision,
|
|
183
|
+
mode="lines",
|
|
184
|
+
name=f"Micro-average (AP = {micro_ap:.2f})",
|
|
185
|
+
line=dict(color="black", dash="dot"),
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
fig = go.Figure(
|
|
190
|
+
data=traces,
|
|
191
|
+
layout=go.Layout(
|
|
192
|
+
title=f"Precision-Recall Curve (one-vs-rest) for {model.input_id} on {dataset.input_id}",
|
|
193
|
+
xaxis=dict(title="Recall"),
|
|
194
|
+
yaxis=dict(title="Precision"),
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return fig, RawData(
|
|
199
|
+
precision=raw_precision,
|
|
200
|
+
recall=raw_recall,
|
|
201
|
+
average_precision=raw_ap,
|
|
202
|
+
model=model.input_id,
|
|
203
|
+
dataset=dataset.input_id,
|
|
204
|
+
)
|