{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Validate an application scorecard model\n",
    "\n",
    "Learn how to independently assess an application scorecard model developed using the ValidMind Library as a validator. You'll evaluate the development of the model by conducting thorough testing and analysis, including the use of challenger models to benchmark performance.\n",
    "\n",
    "An *application scorecard model* is a type of statistical model used in credit scoring to evaluate the creditworthiness of potential borrowers by generating a score based on various characteristics of an applicant such as credit history, income, employment status, and other relevant financial data.\n",
    "\n",
    " - This score assists lenders in making informed decisions about whether to approve or reject loan applications, as well as in determining the terms of the loan, including interest rates and credit limits.\n",
    " - Effective validation of application scorecard models ensures that lenders can manage risk efficiently while maintaining a fast and transparent loan application process for applicants.\n",
    "\n",
    "This interactive notebook provides a step-by-step guide for:\n",
    "\n",
    "- Verifying the data quality steps performed by the model development team\n",
    "- Independently replicating the champion model's results and conducting additional tests to assess performance, stability, and robustness\n",
    "- Setting up test inputs and challenger models for comparative analysis\n",
    "- Running validation tests, analyzing results, and logging findings to ValidMind"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "::: {.content-hidden when-format=\"html\"}\n",
    "## Contents    \n",
    "- [About ValidMind](#toc1_)    \n",
    "  - [Before you begin](#toc1_1_)    \n",
    "  - [New to ValidMind?](#toc1_2_)    \n",
    "  - [Key concepts](#toc1_3_)    \n",
    "- [Setting up](#toc2_)    \n",
    "  - [Register a sample model](#toc2_1_)    \n",
    "    - [Assign validator credentials](#toc2_1_1_)    \n",
    "  - [Install the ValidMind Library](#toc2_2_)    \n",
    "  - [Initialize the ValidMind Library](#toc2_3_)    \n",
    "    - [Get your code snippet](#toc2_3_1_)    \n",
    "  - [Importing the champion model](#toc2_4_)    \n",
    "  - [Load the sample dataset](#toc2_5_)    \n",
    "    - [Preprocess the dataset](#toc2_5_1_)    \n",
    "    - [Apply feature engineering to the dataset](#toc2_5_2_)    \n",
    "  - [Split the feature engineered dataset](#toc2_6_)    \n",
    "- [Developing potential challenger models](#toc3_)    \n",
    "  - [Train potential challenger models](#toc3_1_)    \n",
    "    - [Random forest classification model](#toc3_1_1_)    \n",
    "    - [Logistic regression model](#toc3_1_2_)    \n",
    "  - [Extract predicted probabilities](#toc3_2_)    \n",
    "    - [Compute binary predictions](#toc3_2_1_)    \n",
    "- [Initializing the ValidMind objects](#toc4_)    \n",
    "  - [Initialize the ValidMind datasets](#toc4_1_)    \n",
    "  - [Initialize the model objects](#toc4_2_)    \n",
    "  - [Assign predictions](#toc4_3_)    \n",
    "  - [Compute credit risk scores](#toc4_4_)    \n",
    "- [Run data quality tests](#toc5_)    \n",
    "  - [Run and log an individual data quality test](#toc5_1_)    \n",
    "  - [Log multiple data quality tests](#toc5_2_)    \n",
    "  - [Run data quality comparison tests](#toc5_3_)    \n",
    "- [Run performance tests](#toc6_)    \n",
    "  - [Identify performance tests](#toc6_1_)    \n",
    "  - [Run and log an individual performance test](#toc6_2_)    \n",
    "  - [Log multiple performance tests](#toc6_3_)    \n",
    "  - [Evaluate performance of the champion model](#toc6_4_)    \n",
    "  - [Evaluate performance of challenger models](#toc6_5_)    \n",
    "    - [Enable custom context for test descriptions](#toc6_5_1_)    \n",
    "    - [Run performance comparison tests](#toc6_5_2_)    \n",
    "- [Adjust a ValidMind test](#toc7_)    \n",
    "- [Run diagnostic tests](#toc8_)    \n",
    "- [Run feature importance tests](#toc9_)    \n",
    "- [Implement a custom test](#toc10_)    \n",
    "- [Verify test runs](#toc11_)    \n",
    "- [Next steps](#toc12_)    \n",
    "  - [Work with your validation report](#toc12_1_)    \n",
    "  - [Discover more learning resources](#toc12_2_)    \n",
    "- [Upgrade ValidMind](#toc13_)    \n",
    "\n",
    ":::\n",
    "<!-- jn-toc-notebook-config\n",
    "\tnumbering=false\n",
    "\tanchor=true\n",
    "\tflat=false\n",
    "\tminLevel=2\n",
    "\tmaxLevel=4\n",
    "\t/jn-toc-notebook-config -->\n",
    "<!-- THIS CELL WILL BE REPLACED ON TOC UPDATE. DO NOT WRITE YOUR TEXT IN THIS CELL -->"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc1_'></a>\n",
    "\n",
    "## About ValidMind\n",
    "\n",
    "ValidMind is a suite of tools for managing model risk, including risk associated with AI and statistical models.\n",
    "\n",
    "You use the ValidMind Library to automate comparison and other validation tests, and then use the ValidMind Platform to submit compliance assessments of champion models via comprehensive validation reports. Together, these products simplify model risk management, facilitate compliance with regulations and institutional standards, and enhance collaboration between yourself and model developers."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc1_1_'></a>\n",
    "\n",
    "### Before you begin\n",
    "\n",
    "This notebook assumes you have basic familiarity with Python, including an understanding of how functions work. If you are new to Python, you can still run the notebook but we recommend further familiarizing yourself with the language. \n",
    "\n",
    "If you encounter errors due to missing modules in your Python environment, install the modules with `pip install`, and then re-run the notebook. For more help, refer to [Installing Python Modules](https://docs.python.org/3/installing/index.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc1_2_'></a>\n",
    "\n",
    "### New to ValidMind?\n",
    "\n",
    "If you haven't already seen our documentation on the [ValidMind Library](https://docs.validmind.ai/developer/validmind-library.html), we recommend you begin by exploring the available resources in this section. There, you can learn more about documenting models and running tests, as well as find code samples and our Python Library API reference.\n",
    "\n",
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\"><span style=\"color: #083E44;\"><b>For access to all features available in this notebook, create a free ValidMind account.</b></span>\n",
    "<br></br>\n",
    "Signing up is FREE — <a href=\"https://docs.validmind.ai/guide/configuration/register-with-validmind.html\" style=\"color: #DE257E;\"><b>Register with ValidMind</b></a></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc1_3_'></a>\n",
    "\n",
    "### Key concepts\n",
    "\n",
    "**Validation report**: A comprehensive and structured assessment of a model’s development and performance, focusing on verifying its integrity, appropriateness, and alignment with its intended use. It includes analyses of model assumptions, data quality, performance metrics, outcomes of testing procedures, and risk considerations. The validation report supports transparency, regulatory compliance, and informed decision-making by documenting the validator’s independent review and conclusions.\n",
    "\n",
    "**Validation report template**: Serves as a standardized framework for conducting and documenting model validation activities. It outlines the required sections, recommended analyses, and expected validation tests, ensuring consistency and completeness across validation reports. The template helps guide validators through a systematic review process while promoting comparability and traceability of validation outcomes.\n",
    "\n",
    "**Tests**: A function contained in the ValidMind Library, designed to run a specific quantitative test on the dataset or model. Tests are the building blocks of ValidMind, used to evaluate and document models and datasets.\n",
    "\n",
    "**Metrics**: A subset of tests that do not have thresholds. In the context of this notebook, metrics and tests can be thought of as interchangeable concepts.\n",
    "\n",
    "**Custom metrics**: Custom metrics are functions that you define to evaluate your model or dataset. These functions can be registered with the ValidMind Library to be used in the ValidMind Platform.\n",
    "\n",
    "**Inputs**: Objects to be evaluated and documented in the ValidMind Library. They can be any of the following:\n",
    "\n",
    "  - **model**: A single model that has been initialized in ValidMind with [`vm.init_model()`](https://docs.validmind.ai/validmind/validmind.html#init_model).\n",
    "  - **dataset**: Single dataset that has been initialized in ValidMind with [`vm.init_dataset()`](https://docs.validmind.ai/validmind/validmind.html#init_dataset).\n",
    "  - **models**: A list of ValidMind models - usually this is used when you want to compare multiple models in your custom metric.\n",
    "  - **datasets**: A list of ValidMind datasets - usually this is used when you want to compare multiple datasets in your custom metric. (Learn more: [Run tests with multiple datasets](https://docs.validmind.ai/notebooks/how_to/run_tests_that_require_multiple_datasets.html))\n",
    "\n",
    "**Parameters**: Additional arguments that can be passed when running a ValidMind test, used to pass additional information to a metric, customize its behavior, or provide additional context.\n",
    "\n",
    "**Outputs**: Custom metrics can return elements like tables or plots. Tables may be a list of dictionaries (each representing a row) or a pandas DataFrame. Plots may be matplotlib or plotly figures."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_'></a>\n",
    "\n",
    "## Setting up"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_1_'></a>\n",
    "\n",
    "### Register a sample model\n",
    "\n",
    "In a usual model lifecycle, a champion model will have been independently registered in your model inventory and submitted to you for validation by your model development team as part of the effective challenge process. (**Learn more:** [Submit for approval](https://docs.validmind.ai/guide/model-documentation/submit-for-approval.html))\n",
    "\n",
    "For this notebook, we'll have you register a dummy model in the ValidMind Platform inventory and assign yourself as the validator to familiarize you with the ValidMind interface and circumvent the need for an existing model:\n",
    "\n",
    "1. In a browser, [log in to ValidMind](https://docs.validmind.ai/guide/configuration/log-in-to-validmind.html).\n",
    "\n",
    "2. In the left sidebar, navigate to **Inventory** and click **+ Register Model**.\n",
    "\n",
    "3. Enter the model details and click **Continue**. ([Need more help?](https://docs.validmind.ai/guide/model-inventory/register-models-in-inventory.html))\n",
    "\n",
    "   For example, to register a model for use with this notebook, select:\n",
    "\n",
    "    - Documentation template: `Credit Risk Scorecard`\n",
    "    - Use case: `Credit Risk — CECL`\n",
    "\n",
    "    You can fill in other options according to your preference."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_1_1_'></a>\n",
    "\n",
    "#### Assign validator credentials\n",
    "\n",
    "In order to log tests as a validator instead of as a developer, on the model details page that appears after you've successfully registered your sample model:\n",
    "\n",
    "1. Remove yourself as a model owner: \n",
    "\n",
    "    - Click on the **OWNERS** tile.\n",
    "    - Click the **x** next to your name to remove yourself from that model's role.\n",
    "    - Click **Save** to apply your changes to that role.\n",
    "\n",
    "2. Remove yourself as a developer: \n",
    "\n",
    "    - Click on the **DEVELOPERS** tile.\n",
    "    - Click the **x** next to your name to remove yourself from that model's role.\n",
    "    - Click **Save** to apply your changes to that role.\n",
    "\n",
    "3. Add yourself as a validator: \n",
    "\n",
    "    - Click on the **VALIDATORS** tile.\n",
    "    - Select your name from the drop-down menu.\n",
    "    - Click **Save** to apply your changes to that role."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_2_'></a>\n",
    "\n",
    "### Install the ValidMind Library\n",
    "\n",
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\"><span style=\"color: #083E44;\"><b>Recommended Python versions</b></span>\n",
    "<br></br>\n",
    "Python 3.8 <= x <= 3.11</div>\n",
    "\n",
    "To install the library:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install -q validmind"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_3_'></a>\n",
    "\n",
    "### Initialize the ValidMind Library\n",
    "\n",
    "ValidMind generates a unique _code snippet_ for each registered model to connect with your validation environment. You initialize the ValidMind Library with this code snippet, which ensures that your test results are uploaded to the correct model when you run the notebook."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_3_1_'></a>\n",
    "\n",
    "#### Get your code snippet\n",
    "\n",
    "1. In a browser, [log in to ValidMind](https://docs.validmind.ai/guide/configuration/log-in-to-validmind.html).\n",
    "\n",
    "2. In the left sidebar, navigate to **Inventory** and select the model you registered for this notebook.\n",
    "\n",
    "3. Go to **Getting Started** and click **Copy snippet to clipboard**.\n",
    "\n",
    "Next, [load your model identifier credentials from an `.env` file](https://docs.validmind.ai/developer/model-documentation/store-credentials-in-env-file.html) or replace the placeholder with your own code snippet:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load your model identifier credentials from an `.env` file\n",
    "\n",
    "%load_ext dotenv\n",
    "%dotenv .env\n",
    "\n",
    "# Or replace with your code snippet\n",
    "\n",
    "import validmind as vm\n",
    "\n",
    "vm.init(\n",
    "    # api_host=\"...\",\n",
    "    # api_key=\"...\",\n",
    "    # api_secret=\"...\",\n",
    "    # model=\"...\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_4_'></a>\n",
    "\n",
    "### Importing the champion model\n",
    "\n",
    "With the ValidMind Library set up and ready to go, let's go ahead and import the champion model submitted by the model development team in the format of a `.pkl` file: **[xgb_model_champion.pkl](xgb_model_champion.pkl)**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import xgboost as xgb\n",
    "\n",
    "#Load the saved model\n",
    "xgb_model = xgb.XGBClassifier()\n",
    "xgb_model.load_model(\"xgb_model_champion.pkl\")\n",
    "xgb_model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Ensure that we have to appropriate order in feature names from Champion model and dataset\n",
    "cols_when_model_builds = xgb_model.get_booster().feature_names"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_5_'></a>\n",
    "\n",
    "### Load the sample dataset\n",
    "\n",
    "Let's next import the public [Lending Club](https://www.kaggle.com/datasets/devanshi23/loan-data-2007-2014/data) dataset from Kaggle, which was used to develop the dummy champion model.\n",
    "\n",
    "- We'll use this dataset to review steps that should have been conducted during the initial development and documentation of the model to ensure that the model was built correctly.\n",
    "- By independently performing steps such as preprocessing and feature engineering, we can confirm whether the model was built using appropriate and properly processed data.\n",
    "\n",
    "To be able to use the dataset, you'll need to import the dataset and load it into a pandas [DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html), a two-dimensional tabular data structure that makes use of rows and columns:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from validmind.datasets.credit_risk import lending_club\n",
    "\n",
    "df = lending_club.load_data(source=\"offline\")\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_5_1_'></a>\n",
    "\n",
    "#### Preprocess the dataset\n",
    "\n",
    "We'll first quickly preprocess the dataset for data quality testing purposes using `lending_club.preprocess`. This function performs the following operations:\n",
    "\n",
    "- Filters the dataset to include only loans for debt consolidation or credit card purposes\n",
    "- Removes loans classified under the riskier grades \"F\" and \"G\"\n",
    "- Excludes uncommon home ownership types and standardizes employment length and loan terms into numerical formats\n",
    "- Discards unnecessary fields and any entries with missing information to maintain a clean and robust dataset for modeling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "preprocess_df = lending_club.preprocess(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_5_2_'></a>\n",
    "\n",
    "#### Apply feature engineering to the dataset\n",
    "\n",
    "Feature engineering improves the dataset's structure to better match what our model expects, and ensures that the model performs optimally by leveraging additional insights from raw data.\n",
    "\n",
    "We'll apply the following transformations using the `ending_club.feature_engineering()` function to optimize the dataset for predictive modeling in our application scorecard:\n",
    "\n",
    "- **WoE encoding**: Converts both numerical and categorical features into Weight of Evidence (WoE) values. WoE is a statistical measure used in scorecard modeling that quantifies the relationship between a predictor variable and the binary target variable. It calculates the ratio of the distribution of good outcomes to the distribution of bad outcomes for each category or bin of a feature. This transformation helps to ensure that the features are predictive and consistent in their contribution to the model.\n",
    "- **Integration of WoE bins**: Ensures that the WoE transformed values are integrated throughout the dataset, replacing the original feature values while excluding the target variable from this transformation. This transformation is used to maintain a consistent scale and impact of each variable within the model, which helps make the predictions more stable and accurate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fe_df = lending_club.feature_engineering(preprocess_df)\n",
    "fe_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc2_6_'></a>\n",
    "\n",
    "### Split the feature engineered dataset\n",
    "\n",
    "With our dummy model imported and our independently preprocessed and feature engineered dataset ready to go, let's now **spilt our dataset into train and test** to start the validation testing process.\n",
    "\n",
    "Splitting our dataset into training and testing is essential for proper validation testing, as this helps assess how well the model generalizes to unseen data:\n",
    "\n",
    "- We begin by dividing our data, which is based on Weight of Evidence (WoE) features, into training and testing sets (`train_df`, `test_df`).\n",
    "- With `lending_club.split`, we employ a simple random split, randomly allocating data points to each set to ensure a mix of examples in both."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Split the data\n",
    "train_df, test_df = lending_club.split(fe_df, test_size=0.2)\n",
    "\n",
    "x_train = train_df.drop(lending_club.target_column, axis=1)\n",
    "y_train = train_df[lending_club.target_column]\n",
    "\n",
    "x_test = test_df.drop(lending_club.target_column, axis=1)\n",
    "y_test = test_df[lending_club.target_column]\n",
    "\n",
    "# Now let's apply the order of features from the champion model construction\n",
    "x_train = x_train[cols_when_model_builds]\n",
    "x_test = x_test[cols_when_model_builds]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cols_use = ['annual_inc_woe',\n",
    " 'verification_status_woe',\n",
    " 'emp_length_woe',\n",
    " 'installment_woe',\n",
    " 'term_woe',\n",
    " 'home_ownership_woe',\n",
    " 'purpose_woe',\n",
    " 'open_acc_woe',\n",
    " 'total_acc_woe',\n",
    " 'int_rate_woe',\n",
    " 'sub_grade_woe',\n",
    " 'grade_woe','loan_status']\n",
    "\n",
    "\n",
    "train_df = train_df[cols_use]\n",
    "test_df = test_df[cols_use]\n",
    "test_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc3_'></a>\n",
    "\n",
    "## Developing potential challenger models"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc3_1_'></a>\n",
    "\n",
    "### Train potential challenger models\n",
    "\n",
    "We're curious how alternate models compare to our champion model, so let's train two challenger models as basis for our testing.\n",
    "\n",
    "Our selected options below offer decreased complexity in terms of implementation — such as lessened manual preprocessing — which can reduce the amount of risk for implementation. However, model risk is not calculated in isolation from a single factor, but rather in consideration with trade-offs in predictive performance, ease of interpretability, and overall alignment with business objectives."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc3_1_1_'></a>\n",
    "\n",
    "#### Random forest classification model\n",
    "\n",
    "A *random forest classification model* is an ensemble machine learning algorithm that uses multiple decision trees to classify data. In ensemble learning, multiple models are combined to improve prediction accuracy and robustness.\n",
    "\n",
    "Random forest classification models generally have higher accuracy because they capture complex, non-linear relationships, but as a result they lack transparency in their predictions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the Random Forest Classification model\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "\n",
    "# Create the model instance with 50 decision trees\n",
    "rf_model = RandomForestClassifier(\n",
    "    n_estimators=50,\n",
    "    random_state=42,\n",
    ")\n",
    "\n",
    "# Train the model\n",
    "rf_model.fit(x_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc3_1_2_'></a>\n",
    "\n",
    "#### Logistic regression model\n",
    "\n",
    "A *logistic regression model* is a statistical machine learning algorithm that uses a linear equation (straight-line relationship between variables) and the logistic function (or sigmoid function, which maps any real-valued number to a range between `0` and `1`) to classify data. In statistical modeling, a single equation is used to estimate the probability of an outcome based on input features.\n",
    "\n",
    "Logistic regression models are simple and interpretable because they provide clear probability estimates and feature coefficients (numerical value that represents the influence of a particular input feature on the model's prediction), but they may struggle with capturing complex, non-linear relationships in the data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import the Logistic Regression model\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "\n",
    "# Logistic Regression grid params\n",
    "log_reg_params = {\n",
    "    \"penalty\": [\"l1\", \"l2\"],\n",
    "    \"C\": [0.001, 0.01, 0.1, 1, 10, 100, 1000],\n",
    "    \"solver\": [\"liblinear\"],\n",
    "}\n",
    "\n",
    "# Grid search for Logistic Regression\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "grid_log_reg = GridSearchCV(LogisticRegression(), log_reg_params)\n",
    "grid_log_reg.fit(x_train, y_train)\n",
    "\n",
    "# Logistic Regression best estimator\n",
    "log_reg = grid_log_reg.best_estimator_\n",
    "log_reg"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc3_2_'></a>\n",
    "\n",
    "### Extract predicted probabilities\n",
    "\n",
    "With our challenger models trained, let's extract the predicted probabilities from our three models:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Champion — Application scorecard model\n",
    "train_xgb_prob = xgb_model.predict_proba(x_train)[:, 1]\n",
    "test_xgb_prob = xgb_model.predict_proba(x_test)[:, 1]\n",
    "\n",
    "# Challenger — Random forest classification model\n",
    "train_rf_prob = rf_model.predict_proba(x_train)[:, 1]\n",
    "test_rf_prob = rf_model.predict_proba(x_test)[:, 1]\n",
    "\n",
    "# Challenger — Logistic regression model\n",
    "train_log_prob = log_reg.predict_proba(x_train)[:, 1]\n",
    "test_log_prob = log_reg.predict_proba(x_test)[:, 1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc3_2_1_'></a>\n",
    "\n",
    "#### Compute binary predictions\n",
    "\n",
    "Next, we'll convert the probability predictions from our three models into a binary, based on a threshold of `0.3`:\n",
    "\n",
    "- If the probability is greater than `0.3`, the prediction becomes `1` (positive).\n",
    "- Otherwise, it becomes `0` (negative)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cut_off_threshold = 0.3\n",
    "\n",
    "# Champion — Application scorecard model\n",
    "train_xgb_binary_predictions = (train_xgb_prob > cut_off_threshold).astype(int)\n",
    "test_xgb_binary_predictions = (test_xgb_prob > cut_off_threshold).astype(int)\n",
    "\n",
    "# Challenger — Random forest classification model\n",
    "train_rf_binary_predictions = (train_rf_prob > cut_off_threshold).astype(int)\n",
    "test_rf_binary_predictions = (test_rf_prob > cut_off_threshold).astype(int)\n",
    "\n",
    "# Challenger — Logistic regression model\n",
    "train_log_binary_predictions = (train_log_prob > cut_off_threshold).astype(int)\n",
    "test_log_binary_predictions = (test_log_prob > cut_off_threshold).astype(int)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc4_'></a>\n",
    "\n",
    "## Initializing the ValidMind objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc4_1_'></a>\n",
    "\n",
    "### Initialize the ValidMind datasets\n",
    "\n",
    "Before you can run tests, you'll need to connect your data with a ValidMind `Dataset` object. **This step is always necessary every time you want to connect a dataset to documentation and produce test results through ValidMind,** but you only need to do it once per dataset.\n",
    "\n",
    "Initialize a ValidMind dataset object using the [`init_dataset` function](https://docs.validmind.ai/validmind/validmind.html#init_dataset) from the ValidMind (`vm`) module. For this example, we'll pass in the following arguments:\n",
    "\n",
    "- **`dataset`** — The raw dataset that you want to provide as input to tests.\n",
    "- **`input_id`** — A unique identifier that allows tracking what inputs are used when running each individual test.\n",
    "- **`target_column`** — A required argument if tests require access to true values. This is the name of the target column in the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the raw dataset\n",
    "vm_raw_dataset = vm.init_dataset(\n",
    "    dataset=df,\n",
    "    input_id=\"raw_dataset\",\n",
    "    target_column=lending_club.target_column,\n",
    ")\n",
    "\n",
    "# Initialize the preprocessed dataset\n",
    "vm_preprocess_dataset = vm.init_dataset(\n",
    "    dataset=preprocess_df,\n",
    "    input_id=\"preprocess_dataset\",\n",
    "    target_column=lending_club.target_column,\n",
    ")\n",
    "\n",
    "# Initialize the feature engineered dataset\n",
    "vm_fe_dataset = vm.init_dataset(\n",
    "    dataset=fe_df,\n",
    "    input_id=\"fe_dataset\",\n",
    "    target_column=lending_club.target_column,\n",
    ")\n",
    "\n",
    "# Initialize the training dataset\n",
    "vm_train_ds = vm.init_dataset(\n",
    "    dataset=train_df,\n",
    "    input_id=\"train_dataset\",\n",
    "    target_column=lending_club.target_column,\n",
    ")\n",
    "\n",
    "# Initialize the test dataset\n",
    "vm_test_ds = vm.init_dataset(\n",
    "    dataset=test_df,\n",
    "    input_id=\"test_dataset\",\n",
    "    target_column=lending_club.target_column,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After initialization, you can pass the ValidMind `Dataset` objects `vm_raw_dataset`, `vm_preprocess_dataset`, `vm_fe_dataset`, `vm_train_ds`, and `vm_test_ds` into any ValidMind tests."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc4_2_'></a>\n",
    "\n",
    "### Initialize the model objects\n",
    "\n",
    "You'll also need to initialize a ValidMind model object (`vm_model`) that can be passed to other functions for analysis and tests on the data for each of our three models.\n",
    "\n",
    "You simply initialize this model object with [`vm.init_model()`](https://docs.validmind.ai/validmind/validmind.html#init_model):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the champion application scorecard model\n",
    "vm_xgb_model = vm.init_model(\n",
    "    xgb_model,\n",
    "    input_id=\"xgb_model_developer_champion\",\n",
    ")\n",
    "\n",
    "# Initialize the challenger random forest classification model\n",
    "vm_rf_model = vm.init_model(\n",
    "    rf_model,\n",
    "    input_id=\"rf_model\",\n",
    ")\n",
    "\n",
    "# Initialize the challenger logistic regression model\n",
    "vm_log_model = vm.init_model(\n",
    "    log_reg,\n",
    "    input_id=\"log_model\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc4_3_'></a>\n",
    "\n",
    "### Assign predictions\n",
    "\n",
    "With our models registered, we'll move on to assigning both the predictive probabilities coming directly from each model's predictions, and the binary prediction after applying the cutoff threshold described in the Compute binary predictions step above.\n",
    "\n",
    "- The [`assign_predictions()` method](https://docs.validmind.ai/validmind/validmind/vm_models.html#VMDataset.assign_predictions) from the `Dataset` object can link existing predictions to any number of models.\n",
    "- This method links the model's class prediction values and probabilities to our `vm_train_ds` and `vm_test_ds` datasets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Champion — Application scorecard model\n",
    "vm_train_ds.assign_predictions(\n",
    "    model=vm_xgb_model,\n",
    "    prediction_values=train_xgb_binary_predictions,\n",
    "    prediction_probabilities=train_xgb_prob,\n",
    ")\n",
    "\n",
    "vm_test_ds.assign_predictions(\n",
    "    model=vm_xgb_model,\n",
    "    prediction_values=test_xgb_binary_predictions,\n",
    "    prediction_probabilities=test_xgb_prob,\n",
    ")\n",
    "\n",
    "# Challenger — Random forest classification model\n",
    "vm_train_ds.assign_predictions(\n",
    "    model=vm_rf_model,\n",
    "    prediction_values=train_rf_binary_predictions,\n",
    "    prediction_probabilities=train_rf_prob,\n",
    ")\n",
    "\n",
    "vm_test_ds.assign_predictions(\n",
    "    model=vm_rf_model,\n",
    "    prediction_values=test_rf_binary_predictions,\n",
    "    prediction_probabilities=test_rf_prob,\n",
    ")\n",
    "\n",
    "\n",
    "# Challenger — Logistic regression model\n",
    "vm_train_ds.assign_predictions(\n",
    "    model=vm_log_model,\n",
    "    prediction_values=train_log_binary_predictions,\n",
    "    prediction_probabilities=train_log_prob,\n",
    ")\n",
    "\n",
    "vm_test_ds.assign_predictions(\n",
    "    model=vm_log_model,\n",
    "    prediction_values=test_log_binary_predictions,\n",
    "    prediction_probabilities=test_log_prob,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc4_4_'></a>\n",
    "\n",
    "### Compute credit risk scores\n",
    "\n",
    "Finally, we'll translate model predictions into actionable scores using probability estimates generated by our trained model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Compute the scores\n",
    "train_xgb_scores = lending_club.compute_scores(train_xgb_prob)\n",
    "test_xgb_scores = lending_club.compute_scores(test_xgb_prob)\n",
    "train_rf_scores = lending_club.compute_scores(train_rf_prob)\n",
    "test_rf_scores = lending_club.compute_scores(test_rf_prob)\n",
    "train_log_scores = lending_club.compute_scores(train_log_prob)\n",
    "test_log_scores = lending_club.compute_scores(test_log_prob)\n",
    "\n",
    "# Assign scores to the datasets\n",
    "vm_train_ds.add_extra_column(\"xgb_scores\", train_xgb_scores)\n",
    "vm_test_ds.add_extra_column(\"xgb_scores\", test_xgb_scores)\n",
    "vm_train_ds.add_extra_column(\"rf_scores\", train_rf_scores)\n",
    "vm_test_ds.add_extra_column(\"rf_scores\", test_rf_scores)\n",
    "vm_train_ds.add_extra_column(\"log_scores\", train_log_scores)\n",
    "vm_test_ds.add_extra_column(\"log_scores\", test_log_scores)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc5_'></a>\n",
    "\n",
    "## Run data quality tests\n",
    "\n",
    "With everything ready to go, let's explore some of ValidMind's available tests. Using ValidMind’s repository of tests streamlines your validation testing, and helps you ensure that your models are being validated appropriately.\n",
    "\n",
    "We want to narrow down the tests we want to run from the selection provided by ValidMind, so we'll use the [`vm.tests.list_tasks_and_tags()` function](https://docs.validmind.ai/validmind/validmind/tests.html#list_tasks_and_tags) to list which `tags` are associated with each `task` type:\n",
    "\n",
    "- **`tasks`** represent the kind of modeling task associated with a test. Here we'll focus on `classification` tasks.\n",
    "- **`tags`** are free-form descriptions providing more details about the test, for example, what category the test falls into. Here we'll focus on the `data_quality` tag."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.list_tasks_and_tags()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we'll call [the `vm.tests.list_tests()` function](https://docs.validmind.ai/validmind/validmind/tests.html#list_tests) to list all the data quality tests for classification:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.list_tests(\n",
    "    tags=[\"data_quality\"], task=\"classification\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\"><span style=\"color: #083E44;\"><b>Want to learn more about navigating ValidMind tests?</b></span>\n",
    "<br></br>\n",
    "Refer to our notebook outlining the utilities available for viewing and understanding available ValidMind tests: <a href=\"https://docs.validmind.ai/notebooks/how_to/explore_tests.html\" style=\"color: #DE257E;\"><b>Explore tests</b></a></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc5_1_'></a>\n",
    "\n",
    "### Run and log an individual data quality test\n",
    "\n",
    "Next, we'll use our previously initialized preprocessed dataset (`vm_preprocess_dataset`) as input to run an individual test, then log the result to the ValidMind Platform.\n",
    "\n",
    "- You run validation tests by calling [the `run_test` function](https://docs.validmind.ai/validmind/validmind/tests.html#run_test) provided by the `validmind.tests` module.\n",
    "- Every test result returned by the `run_test()` function has a [`.log()` method](https://docs.validmind.ai/validmind/validmind/vm_models.html#TestResult.log) that can be used to send the test results to the ValidMind Platform.\n",
    "\n",
    "Here, we'll use the [`HighPearsonCorrelation` test](https://docs.validmind.ai/tests/data_validation/HighPearsonCorrelation.html) as an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.run_test(\n",
    "    test_id=\"validmind.data_validation.HighPearsonCorrelation\",\n",
    "    inputs={\n",
    "        \"dataset\": vm_preprocess_dataset\n",
    "    }\n",
    ").log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\"><span style=\"color: #083E44;\"><b>Note the output returned indicating that a test-driven block doesn't currently exist in your model's documentation for some test IDs. </b></span>\n",
    "<br></br>\n",
    "That's expected, as when we run validations tests the results logged need to be manually added to your report as part of your compliance assessment process within the ValidMind Platform. You'll continue to see this message throughout this notebook as we run and log more tests.</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc5_2_'></a>\n",
    "\n",
    "### Log multiple data quality tests\n",
    "\n",
    "Now that we understand how to run a test with ValidMind, we want to run all the tests that were returned for our `classification` tasks focusing on `data_quality`.\n",
    "\n",
    "We'll store the identified tests in `dq` in preparation for batch running these tests and logging their results to the ValidMind Platform:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dq = vm.tests.list_tests(tags=[\"data_quality\"], task=\"classification\",pretty=False)\n",
    "dq"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "With our data quality tests stored, let's run our first batch of tests using the same preprocessed dataset (`vm_preprocess_dataset`) and log their results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for test in dq:\n",
    "    vm.tests.run_test(\n",
    "        test,\n",
    "        inputs={\n",
    "            \"dataset\": vm_preprocess_dataset\n",
    "        }\n",
    "    ).log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc5_3_'></a>\n",
    "\n",
    "### Run data quality comparison tests\n",
    "\n",
    "Next, let's reuse the tests in `dq` to perform comparison tests between the raw (`vm_raw_dataset`) and preprocessed (`vm_preprocess_dataset`) dataset, again logging the results to the ValidMind Platform:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for test in dq:\n",
    "    vm.tests.run_test(\n",
    "        test,\n",
    "        input_grid={\n",
    "            \"dataset\": [vm_raw_dataset,vm_preprocess_dataset]\n",
    "        }\n",
    "    ).log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_'></a>\n",
    "\n",
    "## Run performance tests\n",
    "\n",
    "We'll also run some performance tests, beginning with independent testing of our champion application scorecard model, then moving on to our potential challenger models."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_1_'></a>\n",
    "\n",
    "### Identify performance tests\n",
    "\n",
    "Use `vm.tests.list_tests()` to this time identify all the model performance tests for classification:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "vm.tests.list_tests(tags=[\"model_performance\"], task=\"classification\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_2_'></a>\n",
    "\n",
    "### Run and log an individual performance test\n",
    "\n",
    "Before we run our batch of performance tests, we'll use our previously initialized testing dataset (`vm_test_ds`) as input to run an individual test, then log the result to the ValidMind Platform.\n",
    "\n",
    "When running individual tests, you can use a custom `result_id` to tag the individual result with a unique identifier by appending this `result_id` to the `test_id` with a `:` separator. We'll append an identifier for our champion model here (`xgboost_champion`):\n",
    "\n",
    "Here, we'll use the [`ClassifierPerformance` test](https://docs.validmind.ai/tests/model_validation/sklearn/ClassifierPerformance.html) as an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.run_test(\n",
    "    test_id=\"validmind.model_validation.sklearn.ClassifierPerformance:xgboost_champion\",\n",
    "    inputs={\n",
    "        \"dataset\": vm_test_ds, \"model\" : vm_xgb_model\n",
    "    }\n",
    ").log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_3_'></a>\n",
    "\n",
    "### Log multiple performance tests\n",
    "\n",
    "We only want to run a few other tests that were returned for our `classification` tasks focusing on `model_performance`, so we'll isolate the specific tests we want to batch run in `mpt`:\n",
    "\n",
    "- `ClassifierPerformance`\n",
    "- [`ConfusionMatrix`](https://docs.validmind.ai/tests/model_validation/sklearn/ConfusionMatrix.html)\n",
    "- [`MinimumAccuracy`](https://docs.validmind.ai/tests/model_validation/sklearn/MinimumAccuracy.html)\n",
    "- [`MinimumF1Score`](https://docs.validmind.ai/tests/model_validation/sklearn/MinimumF1Score.html)\n",
    "- [`ROCCurve`](https://docs.validmind.ai/tests/model_validation/sklearn/ROCCurve.html)\n",
    "\n",
    "Note the custom `result_id`s appended to the `test_id`s for our champion model (`xgboost_champion`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mpt = [\n",
    "    \"validmind.model_validation.sklearn.ClassifierPerformance:xgboost_champion\",\n",
    "    \"validmind.model_validation.sklearn.ConfusionMatrix:xgboost_champion\",\n",
    "    \"validmind.model_validation.sklearn.MinimumAccuracy:xgboost_champion\",\n",
    "    \"validmind.model_validation.sklearn.MinimumF1Score:xgboost_champion\",\n",
    "    \"validmind.model_validation.sklearn.ROCCurve:xgboost_champion\"\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_4_'></a>\n",
    "\n",
    "### Evaluate performance of the champion model\n",
    "\n",
    "Now, let's run and log our batch of model performance tests using our testing dataset (`vm_test_ds`) for our champion model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for test in mpt:\n",
    "    vm.tests.run_test(\n",
    "        test,\n",
    "        inputs={\n",
    "            \"dataset\": vm_test_ds, \"model\" : vm_xgb_model\n",
    "        },\n",
    "    ).log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_5_'></a>\n",
    "\n",
    "### Evaluate performance of challenger models\n",
    "\n",
    "We've now conducted similar tests as the model development team for our champion model, with the aim of verifying their test results.\n",
    "\n",
    "Next, let's see how our challenger models compare. We'll use the same batch of tests here as we did in `mpt`, but append a different `result_id` to indicate that these results should be associated with our challenger models:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mpt_chall = [\n",
    "    \"validmind.model_validation.sklearn.ClassifierPerformance:xgboost_champion_vs_challengers\",\n",
    "    \"validmind.model_validation.sklearn.ConfusionMatrix:xgboost_champion_vs_challengers\",\n",
    "    \"validmind.model_validation.sklearn.MinimumAccuracy:xgboost_champion_vs_challengers\",\n",
    "    \"validmind.model_validation.sklearn.MinimumF1Score:xgboost_champion_vs_challengers\",\n",
    "    \"validmind.model_validation.sklearn.ROCCurve:xgboost_champion_vs_challengers\"\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_5_1_'></a>\n",
    "\n",
    "#### Enable custom context for test descriptions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you run ValidMind tests, test descriptions are automatically generated with LLM using the test results, the test name, and the static test definitions provided in the test’s docstring. While this metadata offers valuable high-level overviews of tests, insights produced by the LLM-based descriptions may not always align with your specific use cases or incorporate organizational policy requirements.\n",
    "\n",
    "Before we run our next batch of tests, we'll include some custom use case context to focus on comparison testing going forward, improving the relevancy, insight, and format of the test descriptions returned. By default, custom context for LLM-generated descriptions is disabled, meaning that the output will not include any additional context. To enable custom use case context, set the `VALIDMIND_LLM_DESCRIPTIONS_CONTEXT_ENABLED` environment variable to `1`.\n",
    "\n",
    "This is a global setting that will affect all tests for your linked model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.environ[\"VALIDMIND_LLM_DESCRIPTIONS_CONTEXT_ENABLED\"] = \"1\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d1e90ba",
   "metadata": {},
   "source": [
    "Enabling use case context allows you to pass in additional context to the LLM-generated text descriptions within `context`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.environ[\"VALIDMIND_LLM_DESCRIPTIONS_CONTEXT_ENABLED\"] = \"1\"\n",
    "\n",
    "context = \"\"\"\n",
    "FORMAT FOR THE LLM DESCRIPTIONS: \n",
    "    **<Test Name>** is designed to <begin with a concise overview of what the test does and its primary purpose, \n",
    "    extracted from the test description>.\n",
    "\n",
    "    The test operates by <write a paragraph about the test mechanism, explaining how it works and what it measures. \n",
    "    Include any relevant formulas or methodologies mentioned in the test description.>\n",
    "\n",
    "    The primary advantages of this test include <write a paragraph about the test's strengths and capabilities, \n",
    "    highlighting what makes it particularly useful for specific scenarios.>\n",
    "\n",
    "    Users should be aware that <write a paragraph about the test's limitations and potential risks. \n",
    "    Include both technical limitations and interpretation challenges. \n",
    "    If the test description includes specific signs of high risk, incorporate these here.>\n",
    "\n",
    "    **Key Insights:**\n",
    "\n",
    "    The test results reveal:\n",
    "\n",
    "    - **<insight title>**: <comprehensive description of one aspect of the results>\n",
    "    - **<insight title>**: <comprehensive description of another aspect>\n",
    "    ...\n",
    "\n",
    "    Based on these results, <conclude with a brief paragraph that ties together the test results with the test's \n",
    "    purpose and provides any final recommendations or considerations.>\n",
    "\n",
    "ADDITIONAL INSTRUCTIONS:\n",
    "\n",
    "    The champion model as the basis for comparison is called \"xgb_model_developer_champion\" and emphasis should be on the following:\n",
    "    - The metrics for the champion model compared against the challenger models\n",
    "    - Which model potentially outperforms the champion model based on the metrics, this should be highlighted and emphasized\n",
    "\n",
    "\n",
    "    For each metric in the test results, include in the test overview:\n",
    "    - The metric's purpose and what it measures\n",
    "    - Its mathematical formula\n",
    "    - The range of possible values\n",
    "    - What constitutes good/bad performance\n",
    "    - How to interpret different values\n",
    "\n",
    "    Each insight should progressively cover:\n",
    "    1. Overall scope and distribution\n",
    "    2. Complete breakdown of all elements with specific values\n",
    "    3. Natural groupings and patterns\n",
    "    4. Comparative analysis between datasets/categories\n",
    "    5. Stability and variations\n",
    "    6. Notable relationships or dependencies\n",
    "\n",
    "    Remember:\n",
    "    - Champion model (xgb_model_developer_champion) is the selection and challenger models are used to challenge the selection\n",
    "    - Keep all insights at the same level (no sub-bullets or nested structures)\n",
    "    - Make each insight complete and self-contained\n",
    "    - Include specific numerical values and ranges\n",
    "    - Cover all elements in the results comprehensively\n",
    "    - Maintain clear, concise language\n",
    "    - Use only \"- **Title**: Description\" format for insights\n",
    "    - Progress naturally from general to specific observations\n",
    "\n",
    "\"\"\".strip()\n",
    "\n",
    "os.environ[\"VALIDMIND_LLM_DESCRIPTIONS_CONTEXT\"] = context"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\"><span style=\"color: #083E44;\"><b>Want to learn more about setting custom context for LLM-generated test descriptions?</b></span>\n",
    "<br></br>\n",
    "Refer to our extended walkthrough notebook: <a href=\"https://docs.validmind.ai/notebooks/how_to/add_context_to_llm_descriptions.html\" style=\"color: #DE257E;\"><b>Add context to LLM-generated test descriptions\n",
    "</b></a></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc6_5_2_'></a>\n",
    "\n",
    "#### Run performance comparison tests\n",
    "\n",
    "With the use case context set, we'll run each test in `mpt_chall` once for each model with the same `vm_test_ds` dataset to compare them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for test in mpt_chall:\n",
    "    vm.tests.run_test(\n",
    "        test,\n",
    "        input_grid={\n",
    "            \"dataset\": [vm_test_ds], \"model\" : [vm_xgb_model,vm_log_model,vm_rf_model]\n",
    "        }\n",
    "    ).log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\"><span style=\"color: #083E44;\"><b>Based on the performance metrics, we can conclude that the random forest classification model is not a viable candidate for our use case and can be disregarded in our tests going forward.</b></span>\n",
    "<br></br>\n",
    "In the next section, we'll dive a bit deeper into some tests comparing our champion application scorecard model and our remaining challenger logistic regression model, including tests that will allow us to customize parameters and thresholds for performance standards.</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc7_'></a>\n",
    "\n",
    "## Adjust a ValidMind test\n",
    "\n",
    "Let's dig deeper into the `MinimumF1Score` test we ran previously in Run performance tests to ensure that the models maintain a minimum acceptable balance between *precision* and *recall*. Precision refers to how many out of the positive predictions made by the model were actually correct, and recall refers to how many out of the actual positive cases did the model correctly identify.\n",
    "\n",
    "Use `run_test()` with our testing dataset (`vm_test_ds`) to run the test in isolation again for our two remaining models without logging the result to have the output to compare with a subsequent iteration:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.run_test(\n",
    "    \"validmind.model_validation.sklearn.MinimumF1Score:xgboost_champion_vs_challengers\",\n",
    "    input_grid={\n",
    "        \"dataset\": [vm_test_ds],\n",
    "        \"model\": [vm_xgb_model, vm_log_model]\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As `MinimumF1Score` allows us to customize parameters and thresholds for performance standards, let's adjust the threshold to see if it improves metrics:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = vm.tests.run_test(\n",
    "    \"validmind.model_validation.sklearn.MinimumF1Score:AdjThreshold\",\n",
    "    input_grid={\n",
    "        \"dataset\": [vm_test_ds],\n",
    "        \"model\": [vm_xgb_model, vm_log_model],\n",
    "        \"params\": {\"min_threshold\": 0.35}\n",
    "    },\n",
    ").log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc8_'></a>\n",
    "\n",
    "## Run diagnostic tests\n",
    "\n",
    "Next, we want to inspect the robustness and stability testing comparison between our champion and challenger model.\n",
    "\n",
    "Use `list_tests()` to list all available diagnosis tests applicable to classification tasks:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.list_tests(tags=[\"model_diagnosis\"], task=\"classification\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see if models suffer from any *overfit* potentials and also where there are potential sub-segments of issues with the [`OverfitDiagnosis` test](https://docs.validmind.ai/tests/model_validation/sklearn/OverfitDiagnosis.html). \n",
    "\n",
    "Overfitting occurs when a model learns the training data too well, capturing not only the true pattern but noise and random fluctuations resulting in excellent performance on the training dataset but poor generalization to new, unseen data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.run_test(\n",
    "    test_id=\"validmind.model_validation.sklearn.OverfitDiagnosis:Champion_vs_LogRegression\",\n",
    "    input_grid={\n",
    "        \"datasets\": [[vm_train_ds,vm_test_ds]],\n",
    "        \"model\" : [vm_xgb_model,vm_log_model]\n",
    "    }\n",
    ").log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's also conduct *robustness* and *stability* testing of the two models with the [`RobustnessDiagnosis` test](https://docs.validmind.ai/tests/model_validation/sklearn/RobustnessDiagnosis.html).\n",
    "\n",
    "Robustness refers to a model's ability to maintain consistent performance, and stability refers to a model's ability to produce consistent outputs over time across different data subsets.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vm.tests.run_test(\n",
    "    test_id=\"validmind.model_validation.sklearn.RobustnessDiagnosis:Champion_vs_LogRegression\",\n",
    "    input_grid={\n",
    "        \"datasets\": [[vm_train_ds,vm_test_ds]],\n",
    "        \"model\" : [vm_xgb_model,vm_log_model]\n",
    "    },\n",
    ").log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc9_'></a>\n",
    "\n",
    "## Run feature importance tests\n",
    "\n",
    "We also want to verify the relative influence of different input features on our models' predictions, as well as inspect the differences between our champion and challenger model to see if a certain model offers more understandable or logical importance scores for features.\n",
    "\n",
    "Use `list_tests()` to identify all the feature importance tests for classification:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Store the feature importance tests\n",
    "FI = vm.tests.list_tests(tags=[\"feature_importance\"], task=\"classification\",pretty=False)\n",
    "FI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Run and log our feature importance tests for both models for the testing dataset\n",
    "for test in FI:\n",
    "    vm.tests.run_test(\n",
    "        \"\".join((test,':Champion_vs_LogisticRegression')),\n",
    "        input_grid={\n",
    "            \"dataset\": [vm_test_ds], \"model\" : [vm_xgb_model,vm_log_model]\n",
    "        },\n",
    "    ).log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc10_'></a>\n",
    "\n",
    "## Implement a custom test\n",
    "\n",
    "Let's finish up testing by implementing a custom *inline test* that outputs a FICO score-type score. An inline test refers to a test written and executed within the same environment as the code being tested — in this case, right in this Jupyter Notebook —  without requiring a separate test file or framework.\n",
    "\n",
    "The [`@vm.test` wrapper](https://docs.validmind.ai/validmind/validmind.html#test) allows you to create a reusable test:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import plotly.graph_objects as go\n",
    "\n",
    "@vm.test(\"my_custom_tests.ScoreToOdds\")\n",
    "def score_to_odds_analysis(dataset, score_column='score', score_bands=[410, 440, 470]):\n",
    "    \"\"\"\n",
    "    Analyzes the relationship between score bands and odds (good:bad ratio).\n",
    "    Good odds = (1 - default_rate) / default_rate\n",
    "    \n",
    "    Higher scores should correspond to higher odds of being good.\n",
    "\n",
    "    If there are multiple scores provided through score_column, this means that there are two different models and the scores reflect each model\n",
    "\n",
    "    If there are more scores provided in the score_column then focus the assessment on the differences between the two scores and indicate through evidence which one is preferred.\n",
    "    \"\"\"\n",
    "    df = dataset.df\n",
    "    \n",
    "    # Create score bands\n",
    "    df['score_band'] = pd.cut(\n",
    "        df[score_column],\n",
    "        bins=[-np.inf] + score_bands + [np.inf],\n",
    "        labels=[f'<{score_bands[0]}'] + \n",
    "               [f'{score_bands[i]}-{score_bands[i+1]}' for i in range(len(score_bands)-1)] +\n",
    "               [f'>{score_bands[-1]}']\n",
    "    )\n",
    "    \n",
    "    # Calculate metrics per band\n",
    "    results = df.groupby('score_band').agg({\n",
    "        dataset.target_column: ['mean', 'count']\n",
    "    })\n",
    "    \n",
    "    results.columns = ['Default Rate', 'Total']\n",
    "    results['Good Count'] = results['Total'] - (results['Default Rate'] * results['Total'])\n",
    "    results['Bad Count'] = results['Default Rate'] * results['Total']\n",
    "    results['Odds'] = results['Good Count'] / results['Bad Count']\n",
    "    \n",
    "    # Create visualization\n",
    "    fig = go.Figure()\n",
    "    \n",
    "    # Add odds bars\n",
    "    fig.add_trace(go.Bar(\n",
    "        name='Odds (Good:Bad)',\n",
    "        x=results.index,\n",
    "        y=results['Odds'],\n",
    "        marker_color='blue'\n",
    "    ))\n",
    "    \n",
    "    fig.update_layout(\n",
    "        title='Score-to-Odds Analysis',\n",
    "        yaxis=dict(title='Odds Ratio (Good:Bad)'),\n",
    "        showlegend=False\n",
    "    )\n",
    "    \n",
    "    return fig"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With the custom test available, run and log the test for our champion and challenger models with our testing dataset (`vm_test_ds`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result = vm.tests.run_test(\n",
    "    \"my_custom_tests.ScoreToOdds:Champion_vs_Challenger\",\n",
    "    inputs={\n",
    "        \"dataset\": vm_test_ds,\n",
    "    },\n",
    "    param_grid={\n",
    "        \"score_column\": [\"xgb_scores\",\"log_scores\"],\n",
    "        \"score_bands\": [[500, 540, 570]],\n",
    "    },\n",
    ").log()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\"><span style=\"color: #083E44;\"><b>Want to learn more about custom tests?</b></span>\n",
    "<br></br>\n",
    "Refer to our in-depth introduction to custom tests: <a href=\"https://docs.validmind.ai/notebooks/code_samples/custom_tests/implement_custom_tests.html\" style=\"color: #DE257E;\"><b>Implement custom tests</b></a></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc11_'></a>\n",
    "\n",
    "## Verify test runs\n",
    "\n",
    "Our final task is to verify that all the tests provided by the model development team were run and reported accurately. Note the appended `result_ids` to delineate which dataset we ran the test with for the relevant tests.\n",
    "\n",
    "Here, we'll specify all the tests we'd like to independently rerun in a dictionary called `test_config`. **Note here that `inputs` and `input_grid` expect the `input_id` of the dataset or model as the value rather than the variable name we specified**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_config = {\n",
    "    # Run with the raw dataset\n",
    "    'validmind.data_validation.DatasetDescription:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'}\n",
    "    },\n",
    "    'validmind.data_validation.DescriptiveStatistics:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'}\n",
    "    },\n",
    "    'validmind.data_validation.MissingValues:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {'min_threshold': 1}\n",
    "    },\n",
    "    'validmind.data_validation.ClassImbalance:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {'min_percent_threshold': 10}\n",
    "    },\n",
    "    'validmind.data_validation.Duplicates:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {'min_threshold': 1}\n",
    "    },\n",
    "    'validmind.data_validation.HighCardinality:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {\n",
    "            'num_threshold': 100,\n",
    "            'percent_threshold': 0.1,\n",
    "            'threshold_type': 'percent'\n",
    "        }\n",
    "    },\n",
    "    'validmind.data_validation.Skewness:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {'max_threshold': 1}\n",
    "    },\n",
    "    'validmind.data_validation.UniqueRows:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {'min_percent_threshold': 1}\n",
    "    },\n",
    "    'validmind.data_validation.TooManyZeroValues:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {'max_percent_threshold': 0.03}\n",
    "    },\n",
    "    'validmind.data_validation.IQROutliersTable:raw_data': {\n",
    "        'inputs': {'dataset': 'raw_dataset'},\n",
    "        'params': {'threshold': 5}\n",
    "    },\n",
    "    # Run with the preprocessed dataset\n",
    "    'validmind.data_validation.DescriptiveStatistics:preprocessed_data': {\n",
    "        'inputs': {'dataset': 'preprocess_dataset'}\n",
    "    },\n",
    "    'validmind.data_validation.TabularDescriptionTables:preprocessed_data': {\n",
    "        'inputs': {'dataset': 'preprocess_dataset'}\n",
    "    },\n",
    "    'validmind.data_validation.MissingValues:preprocessed_data': {\n",
    "        'inputs': {'dataset': 'preprocess_dataset'},\n",
    "        'params': {'min_threshold': 1}\n",
    "    },\n",
    "    'validmind.data_validation.TabularNumericalHistograms:preprocessed_data': {\n",
    "        'inputs': {'dataset': 'preprocess_dataset'}\n",
    "    },\n",
    "    'validmind.data_validation.TabularCategoricalBarPlots:preprocessed_data': {\n",
    "        'inputs': {'dataset': 'preprocess_dataset'}\n",
    "    },\n",
    "    'validmind.data_validation.TargetRateBarPlots:preprocessed_data': {\n",
    "        'inputs': {'dataset': 'preprocess_dataset'},\n",
    "        'params': {'default_column': 'loan_status'}\n",
    "    },\n",
    "    # Run with the training and test datasets\n",
    "    'validmind.data_validation.DescriptiveStatistics:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']}\n",
    "    },\n",
    "    'validmind.data_validation.TabularDescriptionTables:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']}\n",
    "    },\n",
    "    'validmind.data_validation.ClassImbalance:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']},\n",
    "        'params': {'min_percent_threshold': 10}\n",
    "    },\n",
    "    'validmind.data_validation.UniqueRows:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']},\n",
    "        'params': {'min_percent_threshold': 1}\n",
    "    },\n",
    "    'validmind.data_validation.TabularNumericalHistograms:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']}\n",
    "    },\n",
    "    'validmind.data_validation.MutualInformation:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']},\n",
    "        'params': {'min_threshold': 0.01}\n",
    "    },\n",
    "    'validmind.data_validation.PearsonCorrelationMatrix:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']}\n",
    "    },\n",
    "    'validmind.data_validation.HighPearsonCorrelation:development_data': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset']},\n",
    "        'params': {'max_threshold': 0.3, 'top_n_correlations': 10}\n",
    "    },\n",
    "    'validmind.model_validation.ModelMetadata': {\n",
    "        'input_grid': {'model': ['xgb_model_developer_champion', 'rf_model']}\n",
    "    },\n",
    "    'validmind.model_validation.sklearn.ModelParameters': {\n",
    "        'input_grid': {'model': ['xgb_model_developer_champion', 'rf_model']}\n",
    "    },\n",
    "    'validmind.model_validation.sklearn.ROCCurve': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset'], 'model': ['xgb_model_developer_champion']}\n",
    "    },\n",
    "    'validmind.model_validation.sklearn.MinimumROCAUCScore': {\n",
    "        'input_grid': {'dataset': ['train_dataset', 'test_dataset'], 'model': ['xgb_model_developer_champion']},\n",
    "        'params': {'min_threshold': 0.5}\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then batch run and log our tests in `test_config`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for t in test_config:\n",
    "    print(t)\n",
    "    try:\n",
    "        # Check if test has input_grid\n",
    "        if 'input_grid' in test_config[t]:\n",
    "            # For tests with input_grid, pass the input_grid configuration\n",
    "            if 'params' in test_config[t]:\n",
    "                vm.tests.run_test(t, input_grid=test_config[t]['input_grid'], params=test_config[t]['params']).log()\n",
    "            else:\n",
    "                vm.tests.run_test(t, input_grid=test_config[t]['input_grid']).log()\n",
    "        else:\n",
    "            # Original logic for regular inputs\n",
    "            if 'params' in test_config[t]:\n",
    "                vm.tests.run_test(t, inputs=test_config[t]['inputs'], params=test_config[t]['params']).log()\n",
    "            else:\n",
    "                vm.tests.run_test(t, inputs=test_config[t]['inputs']).log()\n",
    "    except Exception as e:\n",
    "        print(f\"Error running test {t}: {str(e)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc12_'></a>\n",
    "\n",
    "## Next steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc12_1_'></a>\n",
    "\n",
    "### Work with your validation report\n",
    "\n",
    "Now that you've logged all your test results and verified the work done by the model development team, head to the ValidMind Platform to wrap up your validation report:\n",
    "\n",
    "1. From the **Inventory** in the ValidMind Platform, go to the model you connected to earlier.\n",
    "\n",
    "2. In the left sidebar that appears for your model, click **Validation Report**.\n",
    "\n",
    "Include your logged test results as evidence, create risk assessment notes, add findings, and assess compliance, then submit your report for review when it's ready. **Learn more:** [Preparing validation reports](https://docs.validmind.ai/guide/model-validation/preparing-validation-reports.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc12_2_'></a>\n",
    "\n",
    "### Discover more learning resources\n",
    "\n",
    "All notebook samples can be found in the following directories of the ValidMind Library GitHub repository:\n",
    "\n",
    "- [Code samples](https://github.com/validmind/validmind-library/tree/main/notebooks/code_samples)\n",
    "- [How-to guides](https://github.com/validmind/validmind-library/tree/main/notebooks/how_to)\n",
    "\n",
    "Or, visit our [documentation](https://docs.validmind.ai/) to learn more about ValidMind."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='toc13_'></a>\n",
    "\n",
    "## Upgrade ValidMind\n",
    "\n",
    "<div class=\"alert alert-block alert-info\" style=\"background-color: #B5B5B510; color: black; border: 1px solid #083E44; border-left-width: 5px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);border-radius: 5px;\">After installing ValidMind, you’ll want to periodically make sure you are on the latest version to access any new features and other enhancements.</div>\n",
    "\n",
    "Retrieve the information for the currently installed version of ValidMind:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip show validmind"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the version returned is lower than the version indicated in our [production open-source code](https://github.com/validmind/validmind-library/blob/prod/validmind/__version__.py), restart your notebook and run:\n",
    "\n",
    "```bash\n",
    "%pip install --upgrade validmind\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You may need to restart your kernel after running the upgrade package for changes to be applied."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "ValidMind Library",
   "language": "python",
   "name": "validmind"
  },
  "language_info": {
   "name": "python",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
