diff --git a/notebooks/Classification_simulation_example_Facet.ipynb b/notebooks/Classification_simulation_example_Facet.ipynb new file mode 100644 index 000000000..35feccb72 --- /dev/null +++ b/notebooks/Classification_simulation_example_Facet.ipynb @@ -0,0 +1,524 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "raw_mimetype": "text/html" + }, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Classification with FACET\n", + "\n", + "***\n", + "\n", + "**Robust and impactful Data Science with FACET**\n", + "\n", + "FACET enables us to perform a number of critical steps in best practice Data Science work flow easily, efficiently and reproducibly:\n", + "\n", + "1. Create a robust pipeline for learner selection using LearnerRanker and enabling the use of bootstrap cross-validation.\n", + "\n", + "2. Enhance our model inspection to understand drivers of predictions using local explanations of features via [SHAP values](http://papers.nips.cc/paper/7062-a-unified-approach-to-interpreting-model-predictions) by applying a novel methodology that decomposes SHAP values into measures of synergy, redundancy, and independence between each pair of features.\n", + "\n", + "3. Quickly apply historical simulation to gain key insights into feature values that minimize or maximize the predicted outcome.\n", + "\n", + "***\n", + "\n", + "**Context**\n", + "\n", + "With the advaced capabilities FACET provides by extending SHAP-based model inspection, it is important to gain some intution for how the newly introduced measures for feature redundancy and synergy can vary. As SHAP values represent post-processing after data preparation, feature engineering, preprocessing and model selection/tuning, minimal simulation studies offer a way to make the connection as direct as possible." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this FACET tutorial we will conduct two simulation studies to gain intuition about synergy and redundancy:\n", + "\n", + "- explore patterns in synergy and redundancy as a function of the individual and joint contribution of two continuous features in predicting a binary target where the features have varying degrees of correlation.\n", + "- explore synergy and redundancy as a function of regularization of a random forest by varying the `max_depth` parameter.\n", + "\n", + "***\n", + "\n", + "**Tutorial outline**\n", + "\n", + "1. [Redundancy and Synergy](#Redundancy-and-Synergy)\n", + "2. [Data simulation](#Data-simulation)\n", + "3. [How redundancy and synergy change with feature correlation and interaction](#How-redundancy-and-synergy-change-with-feature-correlation-and-interaction)\n", + "4. [How redundancy and synergy change with regularization in a Random Forest](#How-redundancy-and-synergy-change-with-regularization-in-a-Random-Forest)\n", + "5. [Summary](#Summary)\n", + "6. [What can you do next?](#What-can-you-do-next?)\n", + "7. [Appendix](#Appendix)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# standard imports\n", + "import numpy as np\n", + "import pandas as pd\n", + "from scipy.linalg import toeplitz\n", + "import matplotlib.pyplot as plt\n", + "import shap\n", + "import itertools\n", + "import seaborn as sns\n", + "\n", + "# FACET imports\n", + "from facet import Sample\n", + "from facet.crossfit import LearnerCrossfit\n", + "from facet.inspection import LearnerInspector\n", + "from facet.selection import LearnerRanker, LearnerGrid\n", + "from facet.validation import BootstrapCV\n", + "\n", + "# sklearndf imports\n", + "from sklearndf.pipeline import PipelineDF, ClassifierPipelineDF\n", + "from sklearndf.classification import RandomForestClassifierDF" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Redundancy, Synergy and SHAP\n", + "\n", + "Redundancy and synergy are part of the key extensions FACET makes to using SHAP values to understand model predictions. \n", + "\n", + "The [SHAP approach](http://papers.nips.cc/paper/7062-a-unified-approach-to-interpreting-model-predictions) has become the standard method for model inspection. SHAP values are used to explain the additive contribution of each feature to the prediction for a given observation. SHAP values are computed for every feature and observation.\n", + "\n", + "The FACET `LearnerInspector` computes SHAP values for each crossfit (i.e., a CV fold or bootstrap resample) using the best model identified by the `LearnerRanker`. The FACET `LearnerInspector` then provides advanced model inspection through new SHAP-based summary metrics for understanding feature redundancy and synergy.\n", + "\n", + "The definitions are as follows:\n", + "\n", + "1. **Redundancy** represents how much information is shared between two features contributions to model predictions. In our example we might expect redundancy between BMI and waist circumference as a higher BMI will tend to lead to a larger waist circumference and vice versa. This means just knowing one or the other is likely to provide similar predictive performance.\n", + "\n", + "\n", + "2. **Synergy** represents how much the combined information of two features contributes to the model predictions. In our example we could hypothesize that knowing both gender and BMI provides greater accuracy in predicting prediabetes risk than either alone.\n", + "\n", + "In breif, redundancy represents the shared information between two features and synergy represents the degree to which one feature combines with another to generate a prediction. It is also important to recognize:\n", + "\n", + "- that any pair of features may have both redundancy and synergy\n", + "- that SHAP values are dependent upon the model, so under- or over-fitting will influence redundancy and synergy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Data simulation\n", + "\n", + "For the simulation studies we generate data as follows:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "$$ (X_1, X_2) \\sim N\\left[\\left(\\begin{array}{c} 0\\\\0 \\end{array}\\right), \\left(\\begin{array}{cc} 1 & \\rho\\\\ \\rho & 1 \\end{array}\\right)\\right]$$\n", + " \n", + " \n", + "$$p = \\cfrac{1}{1 + exp(-[\\beta_0 + \\beta_1 X_1 + \\beta_2 X_2 + \\beta_3 X_1 X_2])}$$\n", + " \n", + " \n", + "$$U \\sim \\textrm{U}(0,1)$$\n", + " \n", + " \n", + "$$y = \\begin{cases}\n", + "1 & U < p \\\\\n", + "0 & U \\geq p\n", + "\\end{cases}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Importantly we use the correlation ($\\rho$) between features as a way to induce redundancy, and the balance between an interaction ($\\beta_3$) and main effects ($\\beta_1, \\beta_2$) to induce synergy. So for example, as the correlation gets higher we expect higher redundancy, and as the interaction gets stronger and the main effects get weaker, we expect higher synergy.\n", + "\n", + "The function used to simulate data accoring to the above specifications is `sim_interaction()` and can be found in the [Appendix](#Data-simulation-code)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How redundancy and synergy change with feature correlation and interaction" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this first simulation case study, we use the following parameters for data generation:\n", + "\n", + "- intercept ($\\beta_0$) = `[0]`\n", + "- main effects ($\\beta_1, \\beta_2$) = `[0, 1, 2, 3]`\n", + "- interaction ($\\beta_3$) = `[1, 2, 3]`\n", + "- correlation ($\\rho$) = `[0, 0.2, 0.4, 0.6, 0.8]`\n", + "\n", + "For each combination of parameters above we simulate 20 datasets with 2000 observations. Model fitting is performed using 10 replicates of Bootstrap CV. The classifier used is a Random Forest with default hyper-parameters.\n", + "\n", + "The code used to generate the data presented is shown in the [Appendix](#Simulation-study-1-code). You can experiment with the code and perform your own simulation studies, just be aware that it may take some time to run." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# load simulation study data\n", + "sns.set_style(\"darkgrid\")\n", + "sim_data = pd.read_csv('sphinx/source/tutorial/classification_sim1.csv').set_index(['main effects', 'interaction', 'correlation'])\n", + "long_sim = sim_data[['redundancy', 'synergy']].stack().reset_index()\n", + "long_sim.rename(columns={'level_3':'FACET metric', 0:'Redundany / Synergy'}, inplace=True)\n", + "\n", + "# create summary plot\n", + "sns.set_palette([\"#30c1d7\", \"#295e7e\"])\n", + "g = sns.FacetGrid(long_sim, col=\"main effects\", row=\"interaction\", hue='FACET metric', margin_titles=True)\n", + "g.map(sns.lineplot, \"correlation\", \"Redundany / Synergy\", estimator='mean', marker=\"o\", ci=None)\n", + "g.add_legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are several interesting patterns we can observe from the plot:\n", + "\n", + "1. In general the larger the interaction the higher the synergy.\n", + "2. The greater the individual contributions of the features the lower the synergy.\n", + "3. As the correlation increases they redundancy increases and the synergy reduces.\n", + "4. Redundancy increases with increasing individual contributions of the features." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How redundancy and synergy change with regularization in a Random Forest\n", + "\n", + "In this second simulation study we are going to explore the values of Synergy and Redundancy as a function of regularization in a random forest. The main regularization parameter is the `max_depth`, which controls the tree depth. In general, the deeper the tree the more likely we are to overfit the data.\n", + "\n", + "For this second simulation case study, we use the following parameters for data generation:\n", + "\n", + "- intercept ($\\beta_0$) = `[0]`\n", + "- main effects ($\\beta_1, \\beta_2$) = `[1]`\n", + "- interaction ($\\beta_3$) = `[3]`\n", + "- correlation ($\\rho$) = `[0.5]`\n", + "\n", + "We simulate 20 datasets with 1000 observations. The classifier used is a Random Forest with default hyper-parameters, except as follows:\n", + "\n", + "- `max_depth = [2, 4, 8, 16, 32]`\n", + "- `n_estimators = [250]`\n", + "\n", + "For each combination of parameters above we perform model fitting using 10 replicates of Bootstrap CV for each of the 20 simulated datasets.\n", + "\n", + "The code used to generate the data presented is shown in the [Appendix](#Simulation-study-2-code). You can experiment with that code and perform your own simulation studies, just be aware that it may take some time to run." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# load simulation study data\n", + "sns.set_style(\"darkgrid\")\n", + "sim_data = pd.read_csv('sphinx/source/tutorial/classification_sim2.csv').set_index(['max_depth', 'n_estimators'])\n", + "long_sim = sim_data[['redundancy', 'synergy']].stack().reset_index()\n", + "long_sim.rename(columns={'level_2':'FACET metric', 0:'Redundany / Synergy'}, inplace=True)\n", + "\n", + "# create summary plot\n", + "sns.set_palette([\"#30c1d7\", \"#295e7e\"])\n", + "sns.lineplot(\"max_depth\", \"Redundany / Synergy\", data=long_sim, hue='FACET metric', estimator='mean', marker=\"o\", ci=None)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can observe the following from the figure above:\n", + "\n", + "1. As `max_depth` increased so did synergy. Synergy changed from an initial value of 0.30 with a `max_depth` of 2, and increased to 0.55 (almost doubling) by the time we reach a `max_depth` of 32.\n", + "2. As `max_depth` increased, redundancy decreased. Redundancy changed from an initial value of 0.27 with a `max_depth` of 2, and decreased to 0.22 by the time we reach a `max_depth` of 32.\n", + "3. This suggests for a pair of moderately correlated features with a moderate interaction and limited individual contributions, overfitting might cause us to over-estimate synergy and under-estimate redundnancy. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Summary\n", + "\n", + "We conducted two simulation studies using a simple controlled setting where we knew the amount of correlation, individual and combined contributions to a binary target.\n", + "\n", + "- In the first simulation study we saw that the amount of correlation between two features as well as the strength of interaction and degree of independent contributions drives the balance between synergy and redudnacy. \n", + "- In the second simulation study we saw how both synergy and redundancy changed as a function of the `max_depth` parameter of our Random Forest classifier. In particular, for a pari of features with correlation and interaction, how as `max_depth` increased synery increased and redundancy decreased." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# What can you do next?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are a number of next steps that could be taken to gain further intuition regarding the capabilities of FACET:\n", + " \n", + "1. Explore further values of main-effects, interactions and correlation between the two features used in the simulation studies.\n", + "2. Add further features to the simulation and explore what happends when you have features that are correlated but only one contributes to prediction (i.e., a purely redundant feature).\n", + "3. Try different learners and hyper-parameters and see how the redundancy and synergy results change. Remember, the contributions of features to individual predictions is through the \"eyes\" of the model." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Appendix" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data simulation code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "def sim_interaction(\n", + " n: int = 2000,\n", + " intercept: float = None,\n", + " coef_1: float = None,\n", + " coef_2: float = None,\n", + " coef_3: float = None,\n", + " corr: float = 0\n", + "):\n", + "\n", + " # two standard normal features for interaction term in the linear predictor\n", + " # note np function for MVN takes sigma but as we use standard normal \n", + " corr = np.array([[1, corr], [corr, 1]])\n", + " mu = [0, 0]\n", + " tmp_data = pd.DataFrame(\n", + " np.random.multivariate_normal(mu, corr, size=n),\n", + " columns=[\"feature_1\", \"feature_2\"],\n", + " )\n", + "\n", + " # linear predictor\n", + " lp = (\n", + " intercept\n", + " + coef_1 * tmp_data.feature_1\n", + " + coef_2 * tmp_data.feature_2\n", + " + coef_3 * tmp_data.feature_1 * tmp_data.feature_2\n", + " )\n", + "\n", + " # convert to probability\n", + " prob = 1 / (1 + np.exp(-lp))\n", + "\n", + " # create target\n", + " tmp_data[\"target\"] = np.where(prob <= np.random.uniform(size=n), 0, 1)\n", + "\n", + " return tmp_data\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simulation study 1 code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\n", + "# conditions to iterate over\n", + "main_effects = [0, 1, 2, 3]\n", + "interaction = [1, 2, 3]\n", + "corr = [0, 0.2, 0.4, 0.6, 0.8]\n", + "conditions = list(itertools.product(*[main_effects, interaction, corr]))\n", + "n_sims = 20\n", + "n_conditions = len(conditions)\n", + "full_results = pd.DataFrame([])\n", + "\n", + "# iterate over conditions\n", + "for i in range(n_conditions):\n", + " \n", + " # number of iterations for a set of conditions\n", + " for j in range(n_sims):\n", + " \n", + " # simulate data\n", + " sim_df = sim_interaction(intercept=0,\n", + " coef_1=conditions[i][0],\n", + " coef_2=conditions[i][0],\n", + " coef_3=conditions[i][1],\n", + " corr=conditions[i][2])\n", + " \n", + " # run crossfit\n", + " crossfit = LearnerCrossfit(\n", + " pipeline=ClassifierPipelineDF(classifier=RandomForestClassifierDF(random_state=42)),\n", + " cv=BootstrapCV(n_splits=10, random_state=42),\n", + " n_jobs=-1,\n", + " ).fit(sample = Sample(\n", + " observations=sim_df,\n", + " features=['feature_1', 'feature_2'],\n", + " target='target'\n", + " ))\n", + "\n", + " # do a straight crossfit with fit inspector\n", + " inspector = LearnerInspector(n_jobs=-1).fit(crossfit=crossfit)\n", + "\n", + " # obtain synergy and redundancy\n", + " redundancy_matrix = inspector.feature_redundancy_matrix()\n", + " synergy_matrix = inspector.feature_synergy_matrix()\n", + " \n", + " # assemble results\n", + " tmp_results = pd.Series({'coef_1': conditions[i][0],\n", + " 'coef_2': conditions[i][0],\n", + " 'interaction': conditions[i][1],\n", + " 'correlation': conditions[i][2],\n", + " 'redundancy': redundancy_matrix.loc['feature_1', 'feature_2'],\n", + " 'synergy': synergy_matrix.loc['feature_1', 'feature_2'],\n", + " 'y_mean': sim_df.target.mean()})\n", + " \n", + " full_results = full_results.append(tmp_results, ignore_index=True)\n", + " \n", + "full_results['main effects'] = \"(\" + full_results['coef_1'].astype(str) + \", \" + full_results['coef_2'].astype(str) + \")\"\n", + "\n", + "# output to a csv file - and use in generating notebook\n", + "full_results.to_csv('sphinx/source/tutorial/classification_sim1.csv', index=False)\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simulation study 2 code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "max_depth = [2, 4, 8, 16, 32]\n", + "n_estimators = [250]\n", + "parm_grid = list(itertools.product(*[max_depth, n_estimators]))\n", + "n_sims = 20\n", + "n_parms = len(parm_grid)\n", + "full_results = pd.DataFrame([])\n", + "\n", + "# number of iterations for a set of conditions\n", + "for j in range(n_sims):\n", + " \n", + " # simulate data\n", + " sim_df = sim_interaction(n=1000,\n", + " intercept=0,\n", + " coef_1=1,\n", + " coef_2=1,\n", + " coef_3=3,\n", + " corr=0.5)\n", + " \n", + " # split into train and test so we can estimate test error as well\n", + " print(j)\n", + " \n", + " # iterate over hyper-parameters\n", + " for i in range(n_parms):\n", + " \n", + " # create classifier with required hyper-parameters\n", + " clf = ClassifierPipelineDF(\n", + " classifier=RandomForestClassifierDF(\n", + " random_state=42,\n", + " max_depth=parm_grid[i][0],\n", + " n_estimators=parm_grid[i][1]\n", + " )\n", + " )\n", + " \n", + " # run crossfit\n", + " crossfit = LearnerCrossfit(\n", + " pipeline=clf,\n", + " cv=BootstrapCV(n_splits=10, random_state=42),\n", + " n_jobs=-1,\n", + " ).fit(sample = Sample(\n", + " observations=sim_df,\n", + " features=['feature_1', 'feature_2'],\n", + " target='target'\n", + " ))\n", + "\n", + " # do a straight crossfit with fit inspector\n", + " inspector = LearnerInspector(n_jobs=-1).fit(crossfit=crossfit)\n", + "\n", + " # obtain synergy and redundancy\n", + " redundancy_matrix = inspector.feature_redundancy_matrix()\n", + " synergy_matrix = inspector.feature_synergy_matrix()\n", + " \n", + " # assemble results\n", + " tmp_results = pd.Series({'max_depth': parm_grid[i][0],\n", + " 'n_estimators': parm_grid[i][1],\n", + " 'redundancy': redundancy_matrix.loc['feature_1', 'feature_2'],\n", + " 'synergy': synergy_matrix.loc['feature_1', 'feature_2'],\n", + " 'y_mean': sim_df.target.mean()})\n", + " \n", + " full_results = full_results.append(tmp_results, ignore_index=True)\n", + " \n", + "# output to a csv file - and use in generating notebook\n", + "full_results.to_csv('sphinx/source/tutorial/classification_sim2.csv', index=False)\n", + "```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.8" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/notebooks/Classification_with_Facet.ipynb b/notebooks/Classification_with_Facet.ipynb new file mode 100644 index 000000000..8a111d0c9 --- /dev/null +++ b/notebooks/Classification_with_Facet.ipynb @@ -0,0 +1,982 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "raw_mimetype": "text/html" + }, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Classification with FACET\n", + "\n", + "***\n", + "\n", + "**Robust and impactful Data Science with FACET**\n", + "\n", + "FACET enables us to perform a number of critical steps in best practice Data Science work flow easily, efficiently and reproducibly:\n", + "\n", + "1. Create a robust pipeline for learner selection using LearnerRanker and enabling the use of bootstrap cross-validation.\n", + "\n", + "2. Enhance our model inspection to understand drivers of predictions using local explanations of features via [SHAP values](http://papers.nips.cc/paper/7062-a-unified-approach-to-interpreting-model-predictions) by applying a novel methodology that decomposes SHAP values into measures of synergy, redundancy, and independence between each pair of features.\n", + "\n", + "3. Quickly apply historical simulation to gain key insights into feature values that minimize or maximize the predicted outcome.\n", + "\n", + "***\n", + "\n", + "**Context**\n", + "\n", + "Prediabetes is a treatable condition that leads to many health complications and eventually type 2 diabetes. Identification of individuals at risk of prediabetes can improve early intervention and provide insights into those interventions that work best.\n", + "Using a cohort of healthy (n=2847) and prediabetic (n=1509) patients derived \n", + "from the [NHANES 2013-14 U.S. cross-sectional survey](https://wwwn.cdc.gov/nchs/nhanes/Search/DataPage.aspx?Component=Examination&CycleBeginYear=2013) we aim to create a classifier for prediabetes. For further details on data sources, definitions and the study cohort please see the Appendix ([Data source and study cohort](#Data-source-and-study-cohort)).\n", + "\n", + "Utilizing FACET we will do the following:\n", + "\n", + "- create a pipeline to find identify a well-performing classifier\n", + "- perform model inspection and simulation to gain understanding and insight into key factors predictive of prediabetes.\n", + "\n", + "***\n", + "\n", + "**Tutorial outline**\n", + "\n", + "1. [Preprocessing and initial feature selection](#Preprocessing-and-initial-feature-selection)\n", + "2. [Selecting a learner using FACET ranker](#Selecting-a-learner-using-FACET-ranker)\n", + "3. [Using the FACET inspector for model inspection](#Using-the-FACET-inspector-for-model-inspection)\n", + "4. [FACET univariate simulator: the impact of waist to height ratio](#FACET-univariate-simulator:-the-impact-of-waist-to-height-ratio)\n", + "5. [Summary](#Summary)\n", + "6. [What can you do next?](#What-can-you-do-next?)\n", + "7. [Appendix](#Appendix)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# standard imports\n", + "import numpy as np\n", + "import pandas as pd\n", + "from scipy.linalg import toeplitz\n", + "import matplotlib.pyplot as plt\n", + "import shap\n", + "\n", + "# couple of extra packages to make EDA easier\n", + "import seaborn as sns\n", + "from tableone import TableOne\n", + "\n", + "# sklearn\n", + "from sklearn.compose import make_column_selector\n", + "\n", + "# FACET imports\n", + "from facet import Sample\n", + "from facet.inspection import LearnerInspector\n", + "from facet.selection import LearnerRanker, LearnerGrid\n", + "from facet.validation import BootstrapCV\n", + "from facet.simulation.partition import ContinuousRangePartitioner\n", + "from facet.simulation import UnivariateProbabilitySimulator\n", + "from facet.simulation.viz import SimulationDrawer\n", + "\n", + "# sklearndf imports\n", + "from sklearndf.pipeline import PipelineDF, ClassifierPipelineDF\n", + "from sklearndf.classification import RandomForestClassifierDF\n", + "from sklearndf.classification.extra import LGBMClassifierDF\n", + "from sklearndf.transformation import (\n", + " ColumnTransformerDF,\n", + " OneHotEncoderDF,\n", + " SimpleImputerDF,\n", + ")\n", + "from sklearndf.transformation.extra import BorutaDF\n", + "\n", + "# pytools\n", + "from pytools.viz.dendrogram import DendrogramDrawer, LinkageTree\n", + "from pytools.viz.matrix import MatrixDrawer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Preprocessing and initial feature selection" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to load our prediabetes data and create a simple preprocessing pipeline. For those interested some initial EDA can be found in the Appendix ([Exploratory Data Analysis](#Exploratory-Data-Analysis-(EDA)))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# load the prepared dataframe\n", + "prediab_df = pd.read_csv('sphinx/source/tutorial/pre_diab_nhanes.csv')\n", + "\n", + "# create a couple of new interesting features\n", + "prediab_df['SBP_to_DBP'] = prediab_df['Average_SBP']/prediab_df['Average_DBP']\n", + "prediab_df['Waist_to_hgt'] = prediab_df['Waist_Circumference']/prediab_df['Standing_Height']\n", + "\n", + "# make clear based on dtypes these two features are categorical\n", + "prediab_df['General_health'] = prediab_df['General_health'].astype('object')\n", + "prediab_df['Healthy_diet'] = prediab_df['Healthy_diet'].astype('object')\n", + "\n", + "# have a look\n", + "prediab_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "raw_mimetype": "text/markdown" + }, + "source": [ + "Using FACET we create a sample object, which carries information used in other FACET functions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create a FACET sample object\n", + "prediab = Sample(\n", + " observations=prediab_df,\n", + " features=prediab_df.drop(columns=['Pre_diab']).columns,\n", + " target='Pre_diab'\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "raw_mimetype": "text/markdown" + }, + "source": [ + "Next we create a minimum preprocessing pipeline which based on our initial EDA ([Exploratory Data Analysis](#Exploratory-Data-Analysis-(EDA))) needs to address the following:\n", + "\n", + "1. Simple imputation for missing values in both continuous and categorical features\n", + "2. One-hot encoding for categorical features" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# for categorical features we will use the mode as the imputation value and also one-hot encode\n", + "preprocessing_categorical = PipelineDF(\n", + " steps=[\n", + " (\"imputer\", SimpleImputerDF(strategy=\"most_frequent\", fill_value=\"\")), \n", + " (\"one-hot\", OneHotEncoderDF(sparse=False, handle_unknown=\"ignore\"))\n", + " ]\n", + ")\n", + "\n", + "# for numeric features we will impute using the median\n", + "preprocessing_numerical = SimpleImputerDF(strategy=\"median\")\n", + "\n", + "# put the pipeline together\n", + "preprocessing = ColumnTransformerDF(\n", + " transformers=[\n", + " ('categorical', preprocessing_categorical, make_column_selector(dtype_include=object)),\n", + " ('numerical', preprocessing_numerical, make_column_selector(dtype_include=np.number))\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next is some initial feature selection using Boruta, a recent approach shown to have quite good performance. The Boruta algorithm removes features that are no more predictive than random noise. If you are interested further please see this [article](https://www.jstatsoft.org/article/view/v036i11).\n", + "\n", + "For settings, a max_depth of between 3 and 7 is typically recommended. However, as this depends on the number of features and the complexity of interactions one could also explore the sensitivity of feature selection to this parameter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# create the pipeline for Boruta\n", + "boruta_pipeline = PipelineDF(\n", + " steps=[\n", + " ('preprocess', preprocessing),\n", + " ('boruta', BorutaDF(\n", + " estimator=RandomForestClassifierDF(max_depth=5, n_jobs=-3, random_state=42), \n", + " n_estimators=\"auto\", \n", + " random_state=42,\n", + " verbose=False\n", + " )),\n", + " ]\n", + ")\n", + "\n", + "# run feature selection using Boruta and report those selected\n", + "boruta_pipeline.fit(X=prediab.features, y=prediab.target)\n", + "selected = boruta_pipeline.features_out.to_list()\n", + "selected" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Boruta identified 19 features (out of a potential 47) that we will retain for classification. Note that this feature selection process could be included in a general preprocessing pipeline, however due to the computation involved, we have utilized Boruta here as an initial one-off processing step to narrow down the features for our classifier development." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# update FACET sample object to only those features Boruta identified as useful\n", + "prediab = prediab.keep(selected)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Selecting a learner using FACET ranker\n", + "\n", + "FACET implements Bootstrap CV which uses resampling to create a training set. This re-sampling procedure is repeated many times to get an estimate of average model performance and the variability of that performance. This is an important extension of the native scikit-learn cross-validators which do not support sampling with replacement.\n", + "\n", + "The following learners and hyper-parameter ranges will be assessed using the cross-validated bootstrap:\n", + "\n", + "\n", + "1. **Random forest**: with hyper-parameters\n", + " - max_leaf_nodes: [5, 10, 20]\n", + " - n_estimators: [50, 100, 200] \n", + " \n", + " \n", + "2. **Light gradient boosting**: with hyper-parameters\n", + " - max_depth: [5, 10]\n", + " - num_leaves: [20]\n", + " - learning_rate: [0.2, 0.1]\n", + " - subsample: [0.7]\n", + " - feature_fraction:[0.8]\n", + "\n", + "Note if you want to see a list of hyper-parameters you can use `classifier_name().get_params().keys()` where `classifier_name` could be for example `RandomForestClassifierDF` and if you want to see the default values, just use `classifier_name().get_params()`.\n", + "\n", + "Finally, for this exercise we will use AUC as the performance metric for scoring and ranking our classifiers. Note that ranking uses the average performance minus two times the standard deviation, so that we take into account both the average performance and variability when selecting a classifier." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# 1. Random forest learner\n", + "rf_pipeline=ClassifierPipelineDF(\n", + " classifier=RandomForestClassifierDF(random_state=42),\n", + " preprocessing=preprocessing,\n", + ")\n", + "rf_grid=LearnerGrid(\n", + " pipeline=rf_pipeline,\n", + " learner_parameters={'max_leaf_nodes': [5, 10, 20],\n", + " 'n_estimators': [50, 100, 200]}\n", + ")\n", + "\n", + "# 2. Light gradient boosting learner\n", + "gb_pipeline=ClassifierPipelineDF(\n", + " classifier=LGBMClassifierDF(random_state=42),\n", + " preprocessing=preprocessing,\n", + ")\n", + "gb_grid=LearnerGrid(\n", + " pipeline=gb_pipeline,\n", + " learner_parameters={'max_depth': [5, 10],\n", + " 'num_leaves': [20],\n", + " 'learning_rate': [0.2, 0.1],\n", + " 'subsample': [0.7],\n", + " 'feature_fraction':[0.8]}\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# instigate ranker and fit. Note one can use n_splits argument in BootstrapCV to set the number of times we create a \n", + "# re-sampled dataset for training. Please note this may take some time to run.\n", + "\n", + "ranker=LearnerRanker(\n", + " grids=[rf_grid, gb_grid],\n", + " cv=BootstrapCV(random_state=42),\n", + " n_jobs=-3,\n", + " scoring='roc_auc'\n", + ").fit(prediab)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# Let's look at performance\n", + "print(ranker.summary_report(5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see based on our learner ranker, we have selected a Random Forest algorithm that achieved a mean ROC AUC of 0.73 with a SD of 0.010." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using the FACET inspector for model inspection\n", + "\n", + "The [SHAP approach](http://papers.nips.cc/paper/7062-a-unified-approach-to-interpreting-model-predictions) has become the standard method for model inspection. SHAP values are used to explain the additive contribution of each feature to the prediction for a given observation. SHAP values are computed for every feature and observation.\n", + "\n", + "The FACET `LearnerInspector` computes these SHAP values for each bootstrap resample using the best model identified by the `LearnerRanker`. The FACET `LearnerInspector` then provides advanced model inspection through new SHAP-based summary metrics for understanding feature redundancy and synergy.\n", + "\n", + "Briefly, the definitions are as follows:\n", + "\n", + "1. **Redundancy** represents how much information is shared between two features contributions to model predictions. In our example we might expect redundancy between BMI and waist circumference as a higher BMI will tend to lead to a larger waist circumference and vice versa. This means just knowing one or the other is likely to provide similar predictive performance.\n", + "2. **Synergy** represents how much the combined information of two features contributes to the model predictions. In our example we could hypothesize that knowing both gender and BMI provides greater accuracy in predicting prediabetes risk than either alone. \n", + "\n", + "SHAP values from the `LearnerInspector` can also be used with the SHAP package plotting functions for sample and observation level SHAP visualizations, such as SHAP distribution plots, dependency plots, force plots and waterfall plots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# run inspector\n", + "# TIP: the number used in resize() determines how many of the crossfits to calculate SHAP values for. As SHAP value\n", + "# calculation can be time consuming using a lower value initially can help efficiency before using all crossfits in a\n", + "# final run.\n", + "\n", + "inspector=LearnerInspector(\n", + " n_jobs=-3,\n", + " verbose=10,\n", + ").fit(crossfit=ranker.best_model_crossfit.resize(20))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# obtain FACET feature importance, as well as synergy and redundancy matrices\n", + "f_importance = inspector.feature_importance()\n", + "redundancy_matrix = inspector.feature_redundancy_matrix()\n", + "synergy_matrix = inspector.feature_synergy_matrix()\n", + "dd_redundancy = inspector.feature_redundancy_linkage()\n", + "\n", + "# also let's get some info for standard SHAP plots!\n", + "shap_values = inspector.shap_values().to_numpy()\n", + "rf_pipeline.preprocessing.fit(X=prediab.features)\n", + "X_train = rf_pipeline.preprocessing.transform(X=prediab.features)\n", + "X_train = X_train.reset_index()[prediab.features.columns]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Feature importance\n", + "\n", + "Feature importance has many different ways of being measured. Here we utilize the FACET implementation based on the `LearnerInspector`. Each feature is ranked according to the mean SHAP value for that feature. This plot is paired with a standard SHAP distribution plot for features to see if there is any directional tendency for the associations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# FACET feature importance\n", + "plt.subplot(1, 2, 1)\n", + "f_importance.sort_values().plot.barh()\n", + "\n", + "# standard SHAP summary plot using the SHAP package\n", + "plt.subplot(1, 2, 2)\n", + "shap.summary_plot(shap_values, X_train, show=False, plot_size=(16.0, 8.0))\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Based on the feature importances we can see the top five features are age, waist to height ratio, waist circumference, uric acid and average systolic blood pressure. Inspection of the SHAP value distributions does not provide any indication of a general direction of association for any features. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Synergy and redundancy\n", + "\n", + "Synergy and redundancy are part of the key extensions FACET makes to using SHAP values to understand model predictions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# synergy heatmap\n", + "MatrixDrawer(style=\"matplot%\").draw(synergy_matrix, title=\"Feature synergies\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Synergy represents the degree to which one feature combines with another to generate a prediction.* In the above heatmap we can see the off-diagonal values never exceed 10%. This would suggest that no two features have a strong degree of synergy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# redundancy heatmap\n", + "MatrixDrawer(style=\"matplot%\").draw(redundancy_matrix, title=\"Feature redundancies\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Redundancy represents the shared information between two features.* In the above heatmap we can see a high value of 72% (`Waist_circumference` and `Waist_to_hgt`), and two moderate values of 55% (`Waist_circumference` and `BMI`) and 52% (`BMI` and `Waist_to_hgt`). Another way to look at redundancy is using a dendrogram." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# redundancy dendrogram\n", + "DendrogramDrawer().draw(title=\"HD set features\", data=dd_redundancy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The dendrogram represents the extent of clustering among the features. Taking the `Waist_circumference` and `Waist_to_hgt` features which have the highest redundancy, we can see these features cluster together earliest in the dendrogram. Ideally we want to see features only start to cluster as close to the right-hand side of the dendrogram as possible. This implies all features in the model are contributing uniquely to our predictions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**What might we infer from the above information?**\n", + "\n", + "1. BMI, waist circumference and waist to height ratio form a small cluster of redundant features. This seems reasonable:\n", + " * waist circumference is included in the calculation of waist to height ratio\n", + " * we might expect BMI to capture similar information about excess body mass as higher waist circumference and waist to height ratio\n", + "2. We saw little synergy between features. We might have expected apriori to find some interesting synergies between diet, exercise, sleep and body composition. Of course, the model needs to identify these relationships from them to be reflected in the synergy metric(s).\n", + "\n", + "**What action(s) might we take?**\n", + "\n", + "1. Given the redundancy that appears between BMI, waist circumference and waist to height ratio, we could look to eliminate one or two of these features from the model." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Removing redundant features\n", + "\n", + "Recall the redundancy dendogram above where we saw a clear cluster of features with redundancy; `Waist_to_hgt`, `BMI`, and `Waist_Circumference`.\n", + "\n", + "- assess if the features of the model are unique, i.e. not redundant with other features\n", + "- decide which features to discard, combine, or modify to increase the uniqueness of important features in the model\n", + "\n", + "Before we proceed to looking at SHAP values for individual predictions and perform a univariate simulation, let's eliminate two partially redundant features - we will choose to keep `Waist_to_hgt` ratio and drop `BMI` and `Waist_Circumference`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# drop redundant features from our FACET sample object\n", + "prediab_new = prediab.drop(['BMI', 'Waist_Circumference'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# re-run ranker without redundant features\n", + "ranker = LearnerRanker(\n", + " grids=[rf_grid, gb_grid],\n", + " cv=BootstrapCV(random_state=42),\n", + " n_jobs=-3,\n", + " scoring='roc_auc'\n", + ").fit(prediab_new)\n", + "\n", + "# run inspector\n", + "inspector = LearnerInspector(\n", + " n_jobs=-3,\n", + " verbose=10,\n", + ").fit(\n", + " crossfit=ranker.best_model_crossfit.resize(20)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# obtain FACET feature importance, as well as synergy and redundancy matrices\n", + "f_importance = inspector.feature_importance()\n", + "redundancy_matrix = inspector.feature_redundancy_matrix()\n", + "synergy_matrix = inspector.feature_synergy_matrix()\n", + "dd_redundancy = inspector.feature_redundancy_linkage()\n", + "\n", + "# also get some info for standard SHAP plots!\n", + "shap_values = inspector.shap_values().to_numpy()\n", + "rf_pipeline.preprocessing.fit(X=prediab_new.features)\n", + "X_train = rf_pipeline.preprocessing.transform(X=prediab_new.features)\n", + "X_train = X_train.reset_index()[prediab_new.features.columns]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# redundancy dendogram\n", + "DendrogramDrawer().draw(title=\"HD set features\", data=dd_redundancy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now with the removal of `BMI` and `Waist_Circumference` we can see the feature clustering starts much further to the right." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Individual contributions to predictions\n", + "\n", + "With SHAP values we can also look at how features contribute to individual predictions, so let us look at a patient at high risk of prediabetes using Waterfall plots. Note a similar understanding could be obtained from looking at force plots which also allows for a logit option to present probabilities.\n", + "For example: `shap.force_plot(base_value=base_value, shap_values=shap_values[2366,:], features=X_train.iloc[2366,:].round(2), matplotlib=True)`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# waterfall plot to understand individual predictions\n", + "base_value = np.log(prediab_new.target.mean()/(1-prediab_new.target.mean()))\n", + "shap.waterfall_plot(base_value, shap_values[2366,:], feature_names=X_train.columns.values, max_display=10, show=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# get feature values for context of top three contributors to risk\n", + "pd.concat([X_train[['Age', 'Waist_to_hgt', 'Uric_acid']].iloc[2366,:],\n", + " X_train[['Age', 'Waist_to_hgt', 'Uric_acid']].mean()],\n", + " axis = 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Based on the waterfall plot for this patient we can see the largest contributions to increased risk of prediabetes are a higher than average age, waist to height ratio, and uric acid levels." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# FACET univariate simulator: the impact of waist to height ratio\n", + "\n", + "The second advantage offered by FACET is the ability to quickly instigate and run univariate simulation. \n", + "Simulation enables us to gain insight into what value(s) of this ratio might minimize the likelihood of prediabetes. Further, because FACET can use bootstrap cross validation, we utilize the crossfit from our previous LearnerRanker to perform the simulation and to also quantify the uncertainty by using bootstrap confidence intervals." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# set-up and run a simulation\n", + "sim_feature = \"Waist_to_hgt\"\n", + "simulator = UnivariateProbabilitySimulator(crossfit=ranker.best_model_crossfit, n_jobs=-1)\n", + "partitioner = ContinuousRangePartitioner()\n", + "univariate_simulation = simulator.simulate_feature(name=sim_feature, partitioner=partitioner)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# visualize the results\n", + "SimulationDrawer().draw(data=univariate_simulation, title=sim_feature)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# can also get a print out of simulation results\n", + "SimulationDrawer(\"text\").draw(data=univariate_simulation, title=sim_feature)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see the simulation shows that higher levels increase up to certain point." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Summary\n", + "\n", + "With the capabilities offered by FACET we were able to:\n", + "\n", + "1. Identify a learner using bootstrap CV with performance comparable to models in the literature.\n", + "2. Utilize advanced the SHAP value capabilities (synergy and redundancy) to identify additional features that could be removed (i.e., BMi and waist circumference remvoed in favor of waist to height ratio) and whether or not any features had strong synergistic effects - which they did not.\n", + "3. Simulate the effect of changes in waist to height ratio on the likelihood of being prediabetic." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# What can you do next?\n", + "\n", + "There are a number of next/alternative steps that could be taken:\n", + "\n", + "1. Utilize methods to deal with class imbalance and see if it improves the model.\n", + "2. Adding more features! The NHANES data is a treasure trove of information.\n", + "3. Retain diabetic patients and convert it into a multi-class learning problem.\n", + "4. What would happen if we applied survey weights when constructing a learner?\n", + "5. Further investigation of feature engineering. One could also look at different sets of measurements such as the bio-profile and perform dimension reduction first via PCA or some other method.\n", + "6. Other learners such as SVC, LDA, Elastic-Net, CNN.\n", + "7. More sophisticated imputation for missing values: the assumption of MAR might not hold, as those with worse health and thus more at risk of prediabetes may be more likely not to disclose poor health characteristics. Methods enabled by IterativeImputer could be used or even KNNImputer. Also feature engineering could be done post imputation in the pipeline, so values such as ratios are consistent. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Appendix" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data source and study cohort" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Introduction** \n", + "Prediabetes is a treatable condition that leads to many health complications, including eventually type 2 diabetes. Prediabetes has become an epidemic worldwide and is increasing in prevalence. Due to being a largely asymptomatic condition, screening for prediabetes can be extremely challenging. However, early intervention, especially with lifestyle changes has been shown as effective in treating prediabetes. Accurate prediction/identification of those individuals at risk of prediabetes can improve early intervention and may provide insights into those interventions that work best. The current standard of care is a CDC prediabetes risk [screening tool](https://www.cdc.gov/diabetes/prevention/pdf/Prediabetes-Risk-Test-Final.pdf). \n", + "\n", + "**Data source** \n", + "The dataset used in this tutorial is derived from the [National Health and Nutrition Examination Survey (NHANES) 2013-14 cross-sectional survey](https://wwwn.cdc.gov/nchs/nhanes/Search/DataPage.aspx?Component=Examination&CycleBeginYear=2013). In brief, NHANES collects demographic, socioeconomic, dietary, health, medical, dental, physiological and laboratory data on a nationally representative sample of noninstitutionalized, civilian United States residents. Please note the set-up for this data loosely follows the approach in [De Silva et al](https://pubmed.ncbi.nlm.nih.gov/31889178/).\n", + "\n", + "**Patient cohort** \n", + "In the NHANES data sub-sets of those surveyed may undergo a plasma glucose (FPG) test, oral glucose tolerance\n", + "test (OGTT), or have glycated hemoglobin (HbA1c) measured. Diabetic patients were defined as those with any of the following: FPG >= 126 mg/dl, OGTT > 200 mg/dl, HbA1c > 6.4% or a Doctor diagnosed diabetes. The created dataset contains selected information for 4356 patients aged 20 years or over who were not considered diabetic or who were not pregnant or suspected to be pregnant at the time of the survey.\n", + "\n", + "**Learning target: prediabetes status** \n", + "Using any of the available FPG, OGTT and HbA1c tests we defined patients as prediabetic where any of the following was satisfied: FPG 100\u2013125 mg/dl, OGTT 140\u2013200 mg/dl, or HbA1c 5.7\u20136.4%. Among this cohort 35% were pre-diabetic (n=1509).\n", + "\n", + "**Initial features** \n", + "The following tables provides an overview of the 37 features included in the example dataset.\n", + "\n", + "|Instrument\t|Data File Name (File)\t| NHANES Field\t| Description | Dataset name | Type |\n", + "| :-- | :-- | :-- | :-- | :-- | :-- |\n", + "|Demographics|Demographic Variables, Sample Weights (DEMO_H)|RIDAGEYR|Age in years at screening|Age|Numeric|\n", + "|Demographics|Demographic Variables, Sample Weights (DEMO_H)|RIAGENDR|Gender|Gender| Categorical|\n", + "|Examination|Body Measures (BMX_H)|BMXWT|Weight (kg)|Weight|Numeric|\n", + "|Examination|Body Measures (BMX_H)|BMXHT|Standing Height (cm)|Standing_Height|Numeric|\n", + "|Examination|Body Measures (BMX_H)|BMXWAIST|Waist Circumference (cm)|Waist_Circumference|Numeric|\n", + "|Examination|Body Measures (BMX_H)|BMXBMI|Body Mass Index (kg/m^2)|BMI|Numeric|\n", + "|Examination|Blood Pressure (BPX_H)|BPXSY1 to 4|Systolic: Blood pres mm Hg|Average_SBP| Numeric|\n", + "|Examination|Blood Pressure (BPX_H)|BPXDI1 to 4|Diastolic: Blood pres mm Hg|Average_DBP| Numeric|\n", + "|Questionnaire|Blood Pressure & Cholesterol (BPQ_H)|BPQ020|Ever told you had high blood pressure|High_BP| Categorical|\n", + "|Questionnaire|Diet Behavior & Nutrition (DBQ_H)|DBQ700|How healthy is the diet|Healthy_diet| Categorical|\n", + "|Questionnaire|Diabetes (DIQ_H)|DIQ175A|Family history|Family_hist_diab| Categorical|\n", + "|Questionnaire|Diabetes (DIQ_H)|DIQ172|Feel could be at risk for diabetes|Feel_at_risk_diab| Categorical|\n", + "|Questionnaire|Current Health Status (HSQ_H)|HSD010|General health condition|General_health| Categorical|\n", + "|Questionnaire|Medical Conditions (MCQ_H)|MCQ080|Doctor ever said you were overweight|Told_overweight| Categorical|\n", + "|Questionnaire|Physical Activity (PAQ_H)|PAQ605|Vigorous work activity|Vigorous_work_activity| Categorical|\n", + "|Questionnaire|Physical Activity (PAQ_H)|PAQ620|Moderate work activity|Moderate_work_activity| Categorical|\n", + "|Questionnaire|Physical Activity (PAQ_H)|PAQ635|Walk or bicycle|Walk_or_bicycle| Categorical|\n", + "|Questionnaire|Physical Activity (PAQ_H)|PAQ650|Vigorous recreational activities|Vigorous_rec_activity| Categorical|\n", + "|Questionnaire|Physical Activity (PAQ_H)|PAQ665|Moderate recreational activities|Moderate_rec_activity| Categorical|\n", + "|Questionnaire|Sleep Disorders (SLQ_H)|SLD010H|How much sleep do you get (hours)?|Sleep_hours| Numeric|\n", + "|Questionnaire|Sleep Disorders (SLQ_H)|SLQ050|Ever told doctor had trouble sleeping?|Trouble_sleeping| Categorical|\n", + "|Questionnaire|Sleep Disorders (SLQ_H)|SLQ060|Ever told by doctor have sleep disorder?|Sleep_disorder| Categorical|\n", + "|Questionnaire|Weight History (WHQ_H)|WHQ070|Tried to lose weight in past year|Tried_weight_loss_past_year| Categorical|\n", + "|Laboratory|Cholesterol HDL (HDL_H)|LBDHDD|Direct HDL-Cholesterol (mg/dL)|HDL_Cholesterol| Numeric|\n", + "|Laboratory|Cholesterol Total (TCHOL_H)|LBXTC|Total Cholesterol(mg/dL)|Total_Cholesterol| Numeric|\n", + "|Laboratory|Complete Blood Count (CBC_H)|LBXWBCSI|White blood cell count (1000 cells/uL)|WBC_count| Numeric|\n", + "|Laboratory|Complete Blood Count (CBC_H)|LBXRBCSI|Red blood cell count (million cells/uL)|RBC_count| Numeric|\n", + "|Laboratory|Complete Blood Count (CBC_H)|LBXHCT|Hematocrit (%)|Hematocrit| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSTR|Triglycerides (mg/dL)|Triglycerides| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSUA|Uric acid (mg/dL)|Uric_acid| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSOSSI|Osmolality (mmol/Kg)|Osmolality| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSNASI|Sodium (mmol/L)|Sodium| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSKSI|Potassium (mmol/L)|Potassium| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSGTSI|Gamma glutamyl transferase (U/L)|Gamma_glutamyl_transferase| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSCA|Total calcium (mg/dL)|Calcium| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSATSI|Alanine aminotransferase ALT (IU/L)|Alanine_aminotransferase| Numeric|\n", + "|Laboratory|Biochemistry Profile (BIOPRO_H)|LBXSASSI|Aspartate aminotransferase AST (IU/L)|Aspartate_aminotransferase| Numeric|" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exploratory Data Analysis (EDA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's begin by doing some brief exploratory data anaylsis to assess the impact features might have on the likelihood someone is pre-diabetic and to also determine what will need to be addressed in a pre-processing pipeline." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# load the prepared dataframe\n", + "prediab_eda = pd.read_csv('sphinx/source/tutorial/pre_diab_nhanes.csv')\n", + "prediab_eda.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We might also consider some rudimentary feature engineering as well, such as the ratio of waist circumference to height or the ratio of systolic to diastolic blood pressure. Let's create these two features as well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prediab_eda['SBP_to_DBP'] = prediab_eda['Average_SBP']/prediab_eda['Average_DBP']\n", + "prediab_eda['Waist_to_hgt'] = prediab_eda['Waist_Circumference']/prediab_eda['Standing_Height']\n", + "prediab_eda.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First a quick look at features overall - remove .head() to see all features\n", + "prediab_eda.describe().T" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Missingness\n", + "miss_count = prediab_eda.isna().sum()\n", + "miss_pct = miss_count[miss_count>0]/len(prediab_df)\n", + "miss_pct.sort_values().plot.barh()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# those variables that are complete\n", + "miss_count[miss_count==0]/len(prediab_eda)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Look at correlations\n", + "# Heatmap view\n", + "df_cor = prediab_eda.corr()\n", + "sns.heatmap(df_cor, \n", + " xticklabels=df_cor.columns,\n", + " yticklabels=df_cor.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's do a table comparing features by the target\n", + "categorical = ['Gender', 'High_BP', 'Trouble_sleeping', 'Sleep_disorder', 'Told_overweight', 'General_health',\n", + " 'Family_hist_diab', 'Feel_at_risk_diab', 'Vigorous_work_activity', 'Moderate_work_activity',\n", + " 'Walk_or_bicycle', 'Vigorous_rec_activity', 'Moderate_rec_activity', 'Tried_weight_loss_past_year',\n", + " 'Healthy_diet']\n", + "\n", + "mytable = TableOne(prediab_eda,\n", + " columns=prediab_df.columns.drop('Pre_diab').to_list(),\n", + " categorical=categorical,\n", + " groupby='Pre_diab',\n", + " pval=True,\n", + " remarks=False,\n", + " overall=False)\n", + "print(mytable)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# KDE plots by prediabetes status as well for those continuous features\n", + "distn_vars = ['Age', 'Waist_Circumference', 'Weight', 'Standing_Height', 'BMI', 'Average_SBP', 'Average_DBP',\n", + " 'HDL_Cholesterol', 'Total_Cholesterol', 'Sleep_hours', 'WBC_count', 'RBC_count', 'Hematocrit',\n", + " 'Triglycerides', 'Uric_acid', 'Osmolality', 'Sodium', 'Potassium', 'Gamma_glutamyl_transferase',\n", + " 'Calcium', 'Alanine_aminotransferase', 'Aspartate_aminotransferase', 'SBP_to_DBP', 'Waist_to_hgt']\n", + "\n", + "df_kde = pd.melt(prediab_eda[distn_vars + ['Pre_diab']], 'Pre_diab', distn_vars)\n", + "g = sns.FacetGrid(df_kde, col=\"variable\", hue=\"Pre_diab\", col_wrap=5, sharex=False, sharey=False)\n", + "g.map(sns.kdeplot, \"value\", shade=True)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Quick EDA summary:**\n", + "\n", + "Missingness\n", + "\n", + "- Our target and 10 features were complete.\n", + "- The other 29 features had levels of missing ranging from 0.02% to 11.5%, and 22 of the 29 were <3%.\n", + "- Most extreme cases of missingness were for tried weight loss in the past year (11.5%) and general health (7.8%).\n", + "\n", + "Correlations\n", + "\n", + "- There is a wide range of correlation among features, where in particular we can see that for example RBC count, hematocrit and standing height are all moderately negatively correlated with gender (i.e., females are shorter), and that body measurements for weight, height, BMI, and waist circumference are all strongly positively correlated. \n", + "\n", + "Associations\n", + "\n", + "- Some features already appear to not to be strongly associated based on univariate tests, such as: average DBP, trouble sleeping, vigorous work activity, moderate work activity, tried weight loss in the past year, healthy diet, WBC count, and calcium levels.\n", + "- Features associated with an increased risk of prediabetes include: older age, being male, increased waist circumference, decreased standing height, increased weight, increased BMI, increased average SBP, lower HDL cholesterol, increased total cholesterol, having high BP, increased sleep hours, having a sleep disorder, being told you are overweight, poorer general health, family history of diabetes, feeling at risk for diabetes, reduced walking or cycling, less vigorous or moderate recreational activity, higher RBC count, higher hematocrit, increased triglycerides, increased uric acid, higher osmolality, increased sodium, increased potassium, increased gamma glutamyl transferase, increased alanine aminotransferase, increased aspartate aminotransferase, increased SBP to DBP ratio, increased waist to height ratio.\n", + "\n", + "Distributions of numeric features\n", + "\n", + "- Many of the continuous features have been flagged as potentially non-normal/multi-modal and with potential outliers. This can be seen in the plots where many biomarkers have positive skewed distributions and in the case of sodium, some modality which could also be related to measurement." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.8" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/notebooks/Predictive_Maintenance_Regression_with_Facet.ipynb b/notebooks/Predictive_Maintenance_Regression_with_Facet.ipynb new file mode 100644 index 000000000..ed54cef6b --- /dev/null +++ b/notebooks/Predictive_Maintenance_Regression_with_Facet.ipynb @@ -0,0 +1,1070 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "raw_mimetype": "text/html" + }, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Regression with FACET\n", + "\n", + "***\n", + "\n", + "**Robust and impactful Data Science with FACET**\n", + "\n", + "FACET enables us to perform a number of critical steps in best practice Data Science work flow easily, efficiently and reproducibly:\n", + "\n", + "1. Create a robust pipeline for learner selection using LearnerRanker and enabling the use of bootstrap cross-validation.\n", + "\n", + "2. Enhance our model inspection to understand drivers of predictions using local explanations of features via SHAP values by applying a novel methodology that decomposes SHAP values into measures of synergy, redundancy, and independence between each pair of features.\n", + "\n", + "3. Quickly apply historical simulation to gain key insights into feature values that minimize or maximize the predicted outcome.\n", + "\n", + "***\n", + "\n", + "**Context**\n", + "\n", + "The data are from simulated experiments of a naval vessel (Frigate) Gas Turbine (GT) propulsion plant. The simulator considers the performance decay over time of the GT components such as GT compressor and turbines. One observation in this dataset represents the current decay states of the compressor and the gas turbine along with several sensor readings of the vessel at that point in time. The decay state is a performance metric [0, 1] where 1 means delivering 100% of nominal performance. We want to determine the machine settings which maximize the gas turbine decay state coefficient.\n", + "\n", + "Utilizing FACET we will: \n", + "\n", + "1. Predict the decay state of the gas turbine as accurately as possible\n", + "2. Understand which parameters drive the decay state of the turbine\n", + "3. Analyze how these drivers interact with each other and the target\n", + "\n", + "While we can solve questions 1 and parts of question 2 with commonly used machine learning packages, `facet` will enable us to make better inferences about the way some of the features share or complement information and help us to figure out the optimal settings of the vessel to minimize the equipment degradation at a variety of ship speeds.\n", + "\n", + "***\n", + "\n", + "**Tutorial outline**\n", + "\n", + "1. [Preprocessing and initial feature selection](#Preprocessing-and-initial-feature-selection)\n", + "2. [Selecting a learner using FACET ranker](#Selecting-a-learner-using-FACET-ranker)\n", + "3. [Using the FACET inspector for model inspection](#Using-the-FACET-inspector-for-model-inspection)\n", + "4. [FACET univariate simulator: the impact of waist to height ratio](#FACET-univariate-simulator:-the-impact-of-waist-to-height-ratio)\n", + "5. [Appendix](#Appendix)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TL;DR" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% raw\n" + }, + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + "- `facet.Sample` wraps the features and the target\n", + "- `facet.inspection.LearnerInspector` helps explaining what a learner (regressor or classifier) has learnt\n", + "- `facet.selection.LearnerRanker` helps ranking different models and hyperparameter configurations in a pipeline\n", + "- `facet.validation.BootStrapCV` generates cross-validation splits by random sampling with replacement\n", + "- `facet.simulation.partition.ConitnuousRangePartitioner` Selects relevant partitioning of values of a feature to be simulated\n", + "- `facet.simulation.UnivariateUpliftSimulator` identifies values of a feature that maximize or minimize the target variable\n", + "- `facet.simulation.viz.SimulationDrawer` visualizes simulation results in an informative chart\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-27T13:10:25.031514Z", + "start_time": "2020-08-27T13:10:25.029576Z" + } + }, + "source": [ + "# Required Imports" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to run this notebook, we will import not only the `facet` package, but also a number of other packages useful to solve this task. Overall, we can break down the imports into three categories: \n", + "1. Common packages (pandas, matplotlib, etc.)\n", + "2. Required `facet` classes (inpsection, selection, validation, simulation, etc.)\n", + "3. Other `gamma` packages which simplify pipelining with `sklearn` and provide some visualization utils" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Conventional imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:29:37.518624Z", + "start_time": "2020-08-28T14:29:36.540501Z" + } + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from pathlib import Path\n", + "import seaborn as sns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Gamma Facet imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:29:38.013412Z", + "start_time": "2020-08-28T14:29:37.520802Z" + } + }, + "outputs": [], + "source": [ + "from facet import Sample\n", + "from facet.inspection import LearnerInspector\n", + "from facet.selection import LearnerRanker, LearnerGrid\n", + "from facet.validation import BootstrapCV\n", + "from facet.simulation.partition import ContinuousRangePartitioner\n", + "from facet.simulation import UnivariateUpliftSimulator\n", + "from facet.simulation.viz import SimulationDrawer" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-18T14:15:20.686543Z", + "start_time": "2020-08-18T14:15:20.683573Z" + } + }, + "source": [ + "Sklearndf imports\n", + "\n", + "Instead of using the \"regular\" scikit-learn package, we are using the `sklearndf` (see on [GitHub](https://github.com/orgs/BCG-Gamma/sklearndf/)) wrapper which keeps metadata such as column names when passing the data through the scikit-learn learners. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:29:38.175010Z", + "start_time": "2020-08-28T14:29:38.014809Z" + } + }, + "outputs": [], + "source": [ + "# sklearndf\n", + "from sklearndf.pipeline import PipelineDF, RegressorPipelineDF\n", + "from sklearndf.regression import RandomForestRegressorDF\n", + "from sklearndf.regression.extra import LGBMRegressorDF\n", + "from sklearndf.transformation.extra import BorutaDF\n", + "from sklearndf.transformation import SimpleImputerDF\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:29:38.184383Z", + "start_time": "2020-08-28T14:29:38.176913Z" + } + }, + "outputs": [], + "source": [ + "from pytools.viz.dendrogram import DendrogramDrawer, DendrogramReportStyle\n", + "from pytools.viz.distribution import ECDFDrawer\n", + "from pytools.viz.matrix import MatrixDrawer" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-05T10:40:59.547062Z", + "start_time": "2020-08-05T10:40:59.544794Z" + } + }, + "source": [ + "# Preprocessing and initial feature selection" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to load our turbine decay data and create a simple preprocessing pipeline. For those interested initial EDA can be found in the Appendix [Exploratory Data Analysis](#Exploratory-Data-Analysis)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# load the prepared dataframe\n", + "decay_df = pd.read_csv(\"sphinx/source/tutorial/gas_turbine_data.txt\", delim_whitespace=True)\n", + "\n", + "# assign human-readable labels\n", + "decay_df.columns = [\n", + " 'Lever Position',\n", + " 'Ship Speed', \n", + " 'Turbine Shaft Torque (kN m)', \n", + " 'Turbine Rate of Revolutions (rpm)', \n", + " 'Generator Rate of Revolutions (rpm)', \n", + " 'Starboard Propeller Torque (kN)', \n", + " 'Port Propeller Torque (kN)', \n", + " 'HP Turbine exit temp (C)', \n", + " 'GT Compressor inlet air temp (C)', \n", + " 'GT Compressor outlet air temp (C)', \n", + " 'Turbine exit pressure (bar)', \n", + " 'Compressor inlet air pressure (bar)', \n", + " 'Compressor outlet air pressure (bar)', \n", + " 'Turbine exhaust gas pressure (bar)', \n", + " 'Turbine injection control', \n", + " 'Fuel flow', \n", + " 'GT Compressor decay state coeff', \n", + " 'GT Turbine decay state coeff']\n", + "\n", + "# need to drop the other target\n", + "decay_df.drop(\"GT Compressor decay state coeff\", inplace=True, axis=1)\n", + "\n", + "# have a look\n", + "decay_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For easier management of the data we are using in this example, we are using FACET's `Sample` class, which allows to do a number of things: \n", + "\n", + "- Quickly access the target vs. features\n", + "- Pass the sample into `sklearndf` data pipelines\n", + "- Assign weight vectors to the sample which are propagated down to the learners (given that they support sample weighting)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "TARGET = \"GT Turbine decay state coeff\"\n", + "sample = Sample(observations=decay_df, target=TARGET)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we should create a minimum preprocessing pipeline. However, based on our EDA ([Exploratory Data Analysis](#Exploratory-Data-Analysis-(EDA))) we have no missing values or a need to manage categorical variables etc. However, while it is not needed we will create a simple imputation preprocessing pipeline using [sklearndf's](https://github.com/BCG-Gamma/sklearndf) `SimpleImputerDF` to demonstrate how such a pipeline is created and included in subsequent analytic steps." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "preprocessing_pipeline = PipelineDF(\n", + " steps = [\n", + " (\"impute\", SimpleImputerDF())\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we perform some initial feature selection using the [Boruta](https://www.jstatsoft.org/article/view/v036i11) algorithm, a smart feature selection method to eliminate features whose predictive power is not better than random noise.\n", + "\n", + "The BorutaDF transformer in our [sklearndf](https://github.com/BCG-Gamma/sklearndf) package provides easy access to this powerful method. The approach relies on a tree-based learner, usually a random forest.\n", + "\n", + "For the random forest, we rely on default parameters but set the maximum tree depth to 5 (for Boruta, setting a depth between 3 and 7 is highly recommended and depends on the number of features and expected complexity of the feature/target interactions). The number of trees is automatically managed by the Boruta feature selector (argument n_estimators=\u201dauto\u201d).\n", + "\n", + "We also use parallelization for the random forest using `n_jobs` to accelerate the Boruta iterations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create the Boruta object\n", + "boruta = BorutaDF(\n", + " estimator = RandomForestRegressorDF(max_depth=5, random_state=42, n_jobs=3), \n", + " n_estimators=\"auto\", \n", + " max_iter=50,\n", + " random_state=42, \n", + " verbose=False\n", + ")\n", + "\n", + "# combine Boruta with the preprocessing pipeline\n", + "selection_pipeline = PipelineDF(\n", + " steps = [\n", + " (\"preprocess\", preprocessing_pipeline),\n", + " (\"feature selection\", boruta)\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since [sklearndf](https://github.com/BCG-Gamma/sklearndf) closely follows the `scikit-learn` syntax, we can fit this pipeline on the `sample.features` and `sample.target` properties." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# fit pipeline and print selected features\n", + "selection_pipeline.fit(X=sample.features, y=sample.target)\n", + "print(f\"Selected features: {selection_pipeline.features_out.tolist()}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "start_time": "2020-08-05T10:51:12.659Z" + } + }, + "source": [ + "Boruta selected 9 features which we will now keep in our FACET sample object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:32:16.589723Z", + "start_time": "2020-08-28T14:32:16.585993Z" + } + }, + "outputs": [], + "source": [ + "# update FACET sample object to only those features Boruta identified as useful\n", + "sample_selected = sample.keep(features=selection_pipeline.features_out)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Selecting a learner using FACET ranker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "raw_mimetype": "text/restructuredtext" + }, + "source": [ + "We will use a simple [bootstrap](https://en.wikipedia.org/wiki/Bootstrapping_(statistics)) here as this will give us reliable estimates of our model's accuracy. The `facet.validation` module provides a convenient implementation of this important cross-validation strategy: `facet.validation.BootstrapCV`. \n", + "\n", + "Note that if we were given a time series dataset here (i.e. if we had timestamps of the GT readings) we could use a stationary bootstrap here using `facet.validation.StationaryBootstrapCV`). \n", + "\n", + "The bootstrap is an important extension of scikit-learn, as scikit-learn\u2019s native cross-validators do not support sampling with replacement." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:32:16.594237Z", + "start_time": "2020-08-28T14:32:16.591677Z" + } + }, + "outputs": [], + "source": [ + "cv = BootstrapCV(n_splits=10, random_state=42)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`sklearndf` and `facet` implement a number of additional useful wrappers which further simplify comparing and tuning a larger number of models and configurations: \n", + "\n", + "- `facet.selection.LearnerGrid`: allows to pass a Regressor pipeline and a set of hyperparameters\n", + "- `facet.selection.LearnerRanker`: multiple `LearnerGrid`s can be passed into the this class as a list - this allows tuning hyperparameters both across different types of learners in a single step and ranks the resulting models accordingly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:32:16.599454Z", + "start_time": "2020-08-28T14:32:16.596341Z" + } + }, + "outputs": [], + "source": [ + "rf_pipeline = RegressorPipelineDF(\n", + " regressor=RandomForestRegressorDF(n_estimators=500, random_state=42),\n", + ")\n", + "\n", + "lgbm_pipeline = RegressorPipelineDF(\n", + " regressor=LGBMRegressorDF(random_state=42),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, we want to tune two sets of hyperparameters for each learner and cross-validate them using the Bootstrap method. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:32:16.606273Z", + "start_time": "2020-08-28T14:32:16.601757Z" + } + }, + "outputs": [], + "source": [ + "grid = [\n", + " LearnerGrid(\n", + " pipeline=rf_pipeline, \n", + " learner_parameters={ \n", + " \"min_samples_leaf\": [8, 16], \n", + " \"n_estimators\": [20, 50, 100]\n", + " } \n", + " ),\n", + " LearnerGrid(\n", + " pipeline=lgbm_pipeline, \n", + " learner_parameters={ \n", + " \"min_data_in_leaf\": [8, 16], \n", + " \"subsample\": [0.8, 1], \n", + " \"boosting_type\": [\"gbdt\"]\n", + " }\n", + " )\n", + "\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now fit the `grid` defined above using the `facet.selection.LeanerRanker`, which will run a gridsearch (or random search if defined) using the bootstrapped cross-validation on our selected set of features from Boruta. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:33:24.495845Z", + "start_time": "2020-08-28T14:32:16.609006Z" + } + }, + "outputs": [], + "source": [ + "ranker = LearnerRanker(\n", + " grids=grid,\n", + " cv=cv,\n", + " n_jobs=-3\n", + ").fit(sample=sample_selected)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T11:28:17.762068Z", + "start_time": "2020-08-28T11:28:17.756762Z" + } + }, + "source": [ + "We can see how each model scored using the `summary_report()` method of the `LearnerRanker`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:33:24.504903Z", + "start_time": "2020-08-28T14:33:24.499039Z" + } + }, + "outputs": [], + "source": [ + "# look at the top 5 models\n", + "print(ranker.summary_report(5))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-05T11:42:06.425585Z", + "start_time": "2020-08-05T11:42:06.423740Z" + } + }, + "source": [ + "# Using the FACET inspector for model inspection" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SHAP decomposition of features is a method we developed to identify pairs of features that share, or re-use information to predict the target. We distinguish two cases:\n", + "\n", + "- **Synergy**: the degree to which two features jointly contribute to the prediction by combining information. For example, given features X and Y as coordinates on a chess board, the colour of a square can only be predicted when considering X and Y in combination\n", + "\n", + "\n", + "- **Redundancy**: the degree to which two features use the same information, independently of each other, to contribute to a prediction. For example, temperature and pressure in a pressure cooker are redundant features for predicting cooking time since pressure will rise relative to the temperature, and vice versa. Therefore knowing just one of either temperature or pressure will likely enable the same predictive accuracy.\n", + "\n", + "Both cases can apply at the same time, i.e. a pair of features can use some information synergistically while using other information redundantly.\n", + "\n", + "To analyse redundancy for all possible feature parings, the approach is:\n", + "\n", + "1. Calculate the feature redundancy matrix using SHAP value decomposition - this gives us pairwise redundancy between features, in the range of 0.0 (fully unique contributions) and 1.0 (fully redundant contributions)\n", + "\n", + "2. Transform the feature redundancy matrix into a feature distance matrix, where distance is expressed as (1.0 - redundancy)\n", + "\n", + "3. Perform hierarchical, single-linkage clustering on the distance matrix, thus identifying groups of low-distance, redundant features which activate \u201cin tandem\u201d to predict the outcome\n", + "\n", + "The same approach can be used to analyse synergy.\n", + "\n", + "The inspector can calculate all of this with a single method call, but also offers methods to access the intermediate results of each step. A lightweight visualization framework is available to render the results in different styles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:39:19.910709Z", + "start_time": "2020-08-28T14:33:24.517489Z" + } + }, + "outputs": [], + "source": [ + "inspector = LearnerInspector()\n", + "inspector.fit(crossfit=ranker.best_model_crossfit)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-05T13:12:54.363503Z", + "start_time": "2020-08-05T13:12:54.360977Z" + } + }, + "source": [ + "## Synergy and redundancy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:08:11.655421Z", + "start_time": "2020-08-28T16:08:11.057362Z" + } + }, + "outputs": [], + "source": [ + "# synergy heatmaps\n", + "synergy_matrix = inspector.feature_synergy_matrix()\n", + "MatrixDrawer(style=\"matplot%\").draw(synergy_matrix, title=\"Feature synergies\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see in the synergy matrix that the feature \"Compressor outlet air pressure (bar)\" is highly synergystic with other features. This means that the outlet air pressure **in combination** with the turbine torque, rate of revolutions and generator rate of revolutions carries a lot of information for the model. It should not be surprising that this feature also as the highest mean absolute SHAP score. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that this uncovers very high redundancy which would not have been visible in a simple correlation matrix." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:08:39.064822Z", + "start_time": "2020-08-28T16:08:38.477297Z" + } + }, + "outputs": [], + "source": [ + "# redundancy heatmap\n", + "redundancy_matrix = inspector.feature_redundancy_matrix()\n", + "MatrixDrawer(style=\"matplot%\").draw(redundancy_matrix, title=\"Feature redundancies\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:17:34.674348Z", + "start_time": "2020-08-28T16:17:34.279844Z" + } + }, + "outputs": [], + "source": [ + "# redundancy dendrogram\n", + "redundancy = inspector.feature_redundancy_linkage()\n", + "DendrogramDrawer().draw(title=\"Redundancy linkage\", data=redundancy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For convenience when working in a non-notebook environment, all of the `Drawer`s provided by the [pytools](https://github.com/BCG-Gamma/pytools) package also support a `style='text'` flag. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:25:17.524926Z", + "start_time": "2020-08-28T16:25:17.520341Z" + } + }, + "outputs": [], + "source": [ + "DendrogramDrawer(style=\"text\").draw(title=\"Redundancy linkage\", data=redundancy)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T14:39:21.951535Z", + "start_time": "2020-08-28T14:39:21.949456Z" + } + }, + "outputs": [], + "source": [ + "redundant_features = [\"Fuel flow\", \"Turbine exhaust gas pressure\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To obtain the hierarchical clustering, we calculate a linkage tree and plug it into a dendrogram drawer. This makes it easy to visually single out features that are both important and mutually redundant." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### What can we learn from the above? \n", + "\n", + "\n", + "**Synergy**\n", + "We can see in the synergy matrix that the feature \"Compressor outlet air pressure (bar)\" is highly synergystic with other features. This means that the outlet air pressure **in combination** with the turbine torque, rate of revolutions and generator rate of revolutions carries a lot of information for the model. It should not be surprising that this feature also as the highest mean absolute SHAP score. \n", + "\n", + "When simulating the data, we should look at these features first in order to figure out which feature maximized the decay state coefficient. \n", + "\n", + "**Redundancy**\n", + "The redundancy matrix and dendrogram reveals a \"cluster\" of two variables which are highly redundant - Turbine injection control and Fuel flow. That is, they provide the same information to the target and are likely dependent on each other. Looking at the process, the fuel flow is a consequence from the turbine injection control, so we can remove this redundant feature. \n", + "\n", + "It is important to remove redundant features before running the simulation. As we simulate single features along their historical partition while keeping all other observations the same, we risk creating adversing signals when the model makes a prediction about the target if we simulate one feature, but don't change the feature it shares information with alongside. \n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In turn, we remove the redundant features from the sample and create a revised sample on which we re-train the pipeline." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:20:15.706573Z", + "start_time": "2020-08-28T16:20:15.702905Z" + } + }, + "outputs": [], + "source": [ + "sample_revised = sample_selected.drop(redundant_features)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:21:09.099135Z", + "start_time": "2020-08-28T16:20:16.527678Z" + } + }, + "outputs": [], + "source": [ + "# Run the training pipeline again\n", + "ranker_revised = LearnerRanker( \n", + " grids=grid, cv=cv, n_jobs=-3\n", + ").fit(sample=sample_revised)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:21:09.113777Z", + "start_time": "2020-08-28T16:21:09.103236Z" + } + }, + "outputs": [], + "source": [ + "ranker_revised.best_model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# FACET univariate simulator: the impact of compressor outlet air temp" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-07T15:56:26.709687Z", + "start_time": "2020-08-07T15:56:26.682253Z" + } + }, + "source": [ + "Another advantage of FACET is the ability to quickly instigate and run univariate simulation. From the synergy matrix, we can see that the Compressor outlet temperature has the highest synergy with most other features. Therefore, we want to see how the target behaves if we simulate this feature such that each state had a constant outlet compressor temperature.\n", + "\n", + "The absolute SHAP values also confirm that the three features most synergistic with `GT Compressor outlet air temp (C)` are also the most important features according to the model:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:30:48.931395Z", + "start_time": "2020-08-28T16:30:48.866357Z" + } + }, + "outputs": [], + "source": [ + "abs_shap_values = inspector.shap_values().abs().sum(axis=0).reset_index().rename({0: \"Sum of abs SHAP values\"}, axis=1)\n", + "abs_shap_values.sort_values(by=\"Sum of abs SHAP values\", ascending=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the basis for the simulation, we divide the feature into relevant partitions: \n", + "\n", + "- We use the `facet.simulation.partition.ContinuousRangePartitioner` to split the range of observed values of the outlet air temperature into intervals of equal size. Each partition is represented by the central value of that partition. \n", + "- For each partition, the simulator creates an artificial copy of the original sample assuming the variable to be simulated has the same value across all observations - which is the value representing the partition. Using the best LearnerCrossfit acquired from the ranker, the simulator now re-predicts all targets using the models trained for all folds, and determines the average uplift of the target variable resulting from this.\n", + "- The `facet.simulation.viz.SimulationDrawer` visualized the result; both in a matplotlib and a plain-text style" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:21:41.500250Z", + "start_time": "2020-08-28T16:21:41.498208Z" + } + }, + "outputs": [], + "source": [ + "# set-up and run a simulation\n", + "SIM_FEATURE = 'GT Compressor outlet air temp (C)'\n", + "simulator = UnivariateUpliftSimulator(crossfit=ranker.best_model_crossfit, n_jobs=3)\n", + "partitioner = ContinuousRangePartitioner()\n", + "univariate_simulation = simulator.simulate_feature(name=SIM_FEATURE, partitioner=partitioner)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T16:21:09.250184Z", + "start_time": "2020-08-28T16:21:09.246001Z" + } + }, + "outputs": [], + "source": [ + "# visualize the results\n", + "SimulationDrawer().draw(data=univariate_simulation, title=SIM_FEATURE)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# can also get a print out of simulation results\n", + "SimulationDrawer(\"text\").draw(data=univariate_simulation, title=SIM_FEATURE)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see from this that the turbine decay state coefficient is maximized when the outlet air temperature of the gas turbine is as small as possible. Note that this is only looking at the partitions of the historically observed range, as extrapolating these predictions into unobserved regions would risk creating infeasible scenarios. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Appendix" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data source\n", + "\n", + "**Dataset**\n", + "\n", + "The dataset used in this example is available on [Kaggle](https://www.kaggle.com/elikplim/maintenance-of-naval-propulsion-plants-data-set) and contains data from experiments carried out by means of a numerical simulator of a naval vessel (Frigate) characterized by a **Gas Turbine propulsion plant**. In this release of the simulator it is also possible to take into account the performance decay over time of the GT components such as GT compressor and turbines.\n", + "\n", + "Each possible degradation state of the plant can be characterized by three parameters: \n", + "\n", + "- Ship speed (linear function of the lever position)\n", + "- Compressor degradation coefficient kMc\n", + "- Turbine degradation coefficient\n", + "\n", + "The degradation coefficients typically vary between [1; 0.95] for compressor and [1; 0.975] for the gas turbine. \n", + "\n", + "**Features**\n", + "\n", + "One observation in this dataset represents the current decay states of the compresor and the gas turbine along with a number of sensor readings of the shipping vessels at that point in time. \n", + "\n", + "Our target, the Gas Turbine decay state is being modelled as a performance decay state metric which is measured as 1 to 0, 1 meaning delivering 100% of the nominal performance. Therefore, we want to determine the machine settings which **maximize the gas turbine decay state coefficient**. \n", + "\n", + "\n", + "**Learning Problem**\n", + "\n", + "For this learning problem, we have three key objectives: \n", + "\n", + "1. Predict the decay state of the gas turbine as accurately as possible\n", + "2. Understand which parameters drive the decay state of the turbine\n", + "3. Analyze how these drivers interact with each other and the target\n", + "\n", + "\n", + "While we can solve questions 1 and parts of question 2 with commonly used machine learning packages, `facet` will enable us to make better inferences about the way some of the features share or complement information and help us to figure out the optimal settings of the vessel to minimize the equipment degradation at a variety of ship speeds.\n", + "\n", + "Reference for the dataset used in this example is: A. Coraddu, L. Oneto, A. Ghio, S. Savio, D. Anguita, M. Figari, Machine Learning Approaches for Improving Condition?Based Maintenance of Naval Propulsion Plants, Journal of Engineering for the Maritime Environment, 2014, DOI: 10.1177/1475090214540874, (In Press)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exploratory Data Analysis (EDA)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv(\"sphinx/source/tutorial/gas_turbine_data.txt\", delim_whitespace=True)\n", + "\n", + "df.columns = ['Lever Position', \n", + " 'Ship Speed', \n", + " 'Turbine Shaft Torque (kN m)', \n", + " 'Turbine Rate of Revolutions (rpm)', \n", + " 'Generator Rate of Revolutions (rpm)', \n", + " 'Starboard Propeller Torque (kN)', \n", + " 'Port Propeller Torque (kN)', \n", + " 'HP Turbine exit temp (C)', \n", + " 'GT Compressor inlet air temp (C)', \n", + " 'GT Compressor outlet air temp (C)', \n", + " 'Turbine exit pressure (bar)', \n", + " 'Compressor inlet air pressure (bar)', \n", + " 'Compressor outlet air pressure (bar)', \n", + " 'Turbine exhaust gas pressure (bar)', \n", + " 'Turbine injection control', \n", + " 'Fuel flow', \n", + " 'GT Compressor decay state coeff', \n", + " 'GT Turbine decay state coeff']\n", + "\n", + "TARGET = \"GT Turbine decay state coeff\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# need to drop the other target\n", + "df.drop(\"GT Compressor decay state coeff\", inplace=True, axis=1)\n", + "sample = Sample(observations=df, target=TARGET)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Describe the data\n", + "df.describe().T" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also quickly check for missing values, although we can see that there appears to be none." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# count missing by feature\n", + "df.isna().sum(axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use pytool's `ECDFDrawer()` to draw the cumulative distribution of the target. This shows us that the target is uniformly distributed in increments of 0.001 increments." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# look at the target distribution\n", + "ECDFDrawer().draw(sample.target)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# look at feature distributions and correlations\n", + "sns.pairplot(sample.features)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Quick EDA summary:**\n", + "\n", + "- We have no missing values in our data\n", + "- We are dealing with a linearly distributed target\n", + "- The features exhibit a mixture of linear and non-linear relationships amongst each other. This gives us reason to test a number of non-parametric models and compare their performance. \n", + "- Some features appear to be constant and should therefore be filtered out" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.8" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/notebooks/Regression_Water_Drilling_Simulation_Example.ipynb b/notebooks/Regression_Water_Drilling_Simulation_Example.ipynb new file mode 100644 index 000000000..0cd83a563 --- /dev/null +++ b/notebooks/Regression_Water_Drilling_Simulation_Example.ipynb @@ -0,0 +1,1301 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:33:28.594834Z", + "start_time": "2020-08-31T08:33:28.410363Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "working dir is '/Users/hemker konstantin/Documents/repos/Facet/facet'\n", + "added `/Users/hemker konstantin/Documents/repos/Facet/pytools/src` to python paths\n", + "added `/Users/hemker konstantin/Documents/repos/Facet/facet/src` to python paths\n", + "added `/Users/hemker konstantin/Documents/repos/Facet/sklearndf/src` to python paths\n" + ] + } + ], + "source": [ + "# this cell's metadata contains\n", + "# \"nbsphinx\": \"hidden\" so it is hidden by nbsphinx\n", + "\n", + "def _set_paths() -> None:\n", + " # set the correct path when launched from within PyCharm\n", + "\n", + " module_paths = [\"pytools\", \"facet\", \"sklearndf\"]\n", + "\n", + " import sys\n", + " import os\n", + " \n", + " if 'cwd' not in globals():\n", + " # noinspection PyGlobalUndefined\n", + " global cwd\n", + " cwd = os.path.join(os.getcwd(), os.pardir, os.pardir, os.pardir)\n", + " os.chdir(cwd) \n", + " print(f\"working dir is '{os.getcwd()}'\")\n", + " for module_path in module_paths:\n", + " if module_path not in sys.path:\n", + " sys.path.insert(0, os.path.abspath(f\"{cwd}/{os.pardir}/{module_path}/src\"))\n", + " print(f\"added `{sys.path[0]}` to python paths\")\n", + " \n", + "def _ignore_warnings():\n", + " # ignore irrelevant warnings that would affect the output of this tutorial notebook\n", + " \n", + " # ignore a useless LGBM warning\n", + " import warnings\n", + " warnings.filterwarnings(\"ignore\", category=UserWarning, message=r\".*Xcode_8\\.3\\.3\")\n", + "\n", + "_set_paths()\n", + "_ignore_warnings()\n", + "\n", + "del _set_paths, _ignore_warnings\n", + "\n", + "\n", + "def _configure_matplotlib():\n", + " # set global options for matplotlib\n", + " \n", + " import matplotlib\n", + " \n", + " matplotlib.rcParams['figure.figsize'] = (16.0, 8.0)\n", + " matplotlib.rcParams['figure.dpi'] = 72\n", + "\n", + "_configure_matplotlib()\n", + "\n", + "del _configure_matplotlib" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T17:21:45.452088Z", + "start_time": "2020-08-28T17:21:45.450036Z" + } + }, + "source": [ + "# Imports" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-28T17:21:38.623408Z", + "start_time": "2020-08-28T17:21:38.620085Z" + } + }, + "source": [ + "Conventional imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:10.269188Z", + "start_time": "2020-08-31T08:34:02.013Z" + } + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from pathlib import Path" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Gamma Facet imports" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:33:30.464262Z", + "start_time": "2020-08-31T08:33:30.101989Z" + } + }, + "outputs": [], + "source": [ + "from facet import Sample\n", + "from facet.inspection import LearnerInspector\n", + "from facet.selection import LearnerRanker, LearnerGrid\n", + "from facet.validation import BootstrapCV\n", + "from facet.simulation.partition import ContinuousRangePartitioner\n", + "from facet.simulation import UnivariateUpliftSimulator\n", + "from facet.simulation.viz import SimulationDrawer" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-18T14:15:20.686543Z", + "start_time": "2020-08-18T14:15:20.683573Z" + } + }, + "source": [ + "Sklearndf imports\n", + "\n", + "Instead of using the \"regular\" scikit-learn package, we are using the `sklearndf` (see on [GitHub](https://github.com/orgs/BCG-Gamma/sklearndf/)) wrapper which keeps metadata such as column names when passing the data through the scikit-learn learners. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:33:30.620441Z", + "start_time": "2020-08-31T08:33:30.465741Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "The sklearn.linear_model.stochastic_gradient module is deprecated in version 0.22 and will be removed in version 0.24. The corresponding classes / functions should instead be imported from sklearn.linear_model. Anything that cannot be imported from sklearn.linear_model is now part of the private API.\n" + ] + } + ], + "source": [ + "# sklearndf\n", + "from sklearndf.pipeline import PipelineDF, RegressorPipelineDF\n", + "from sklearndf.regression import RandomForestRegressorDF\n", + "from sklearndf.regression.extra import LGBMRegressorDF\n", + "from sklearndf.transformation.extra import BorutaDF\n", + "from sklearndf.transformation import SimpleImputerDF\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:33:30.629194Z", + "start_time": "2020-08-31T08:33:30.622223Z" + } + }, + "outputs": [], + "source": [ + "from pytools.viz.dendrogram import DendrogramDrawer, DendrogramReportStyle\n", + "from pytools.viz.distribution import ECDFDrawer\n", + "from pytools.viz.matrix import MatrixDrawer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# this\n", + "from sklearn.pipeline import Pipeline\n", + "# becomes this\n", + "from sklearndf.pipeline import PipelineDF" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:46:33.795645Z", + "start_time": "2020-08-31T08:46:33.792616Z" + } + }, + "outputs": [], + "source": [ + "from facet import Sample\n", + "import pandas as pd\n", + "from sklearndf.pipeline import PipelineDF\n", + "from sklearndf.transformation.extra import BorutaDF\n", + "from sklearndf.regression import RandomForestRegressorDF\n", + "from sklearndf.transformation import SimpleImputerDF" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:33:30.656685Z", + "start_time": "2020-08-31T08:33:30.639398Z" + } + }, + "outputs": [], + "source": [ + "data_root = Path(\"sphinx/source/tutorial/\")\n", + "df = pd.read_csv(data_root.joinpath(\"water_drill_data.csv\"), sep=\";\", encoding=\"utf-8\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:33:30.665214Z", + "start_time": "2020-08-31T08:33:30.659809Z" + } + }, + "outputs": [], + "source": [ + "# Sample\n", + "sample = Sample(observations=df, target=\"Failure likelihood (%)\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:53:50.515286Z", + "start_time": "2020-08-31T08:53:26.621355Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Selected features: ['Weight on bit (kg)', 'Drill rate (m/s)', 'Vertical depth of operation (m)', 'Mud density (kg/m3)', 'Nonlinear1', 'Bit depth (m)']\n" + ] + } + ], + "source": [ + "# Wrapper class to implement Boruta feature selection\n", + "boruta = BorutaDF(\n", + " estimator = RandomForestRegressorDF(max_depth=5, random_state=42, n_jobs=3), \n", + " n_estimators=\"auto\", \n", + " random_state=42, \n", + " verbose=0, \n", + " max_iter=100\n", + ")\n", + "\n", + "preprocessing_pipeline = PipelineDF(\n", + " steps = [\n", + " (\"impute\", SimpleImputerDF()),\n", + " (\"feature selection\", boruta)\n", + " ]\n", + "\n", + ")\n", + "\n", + "preprocessing_pipeline.fit(X=sample.features, y=sample.target)\n", + "\n", + "print(f\"Selected features: {list(preprocessing_pipeline.features_out)}\")\n", + "sample_selected = sample.keep(preprocessing_pipeline.features_out)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the key features that we would expect to effect the safety of the operation would are still being included after the feature selection. A working hypothesis of how these influence the target are: \n", + "- **Weight on bit**: we expect higher weight to increase the likelihood of a failure due to heavier equipment wear\n", + "- **Drill rate**: similarly to the above, a higher drill rate leads to more wear & tear of the equipment and thus we expect a positive effect\n", + "- **Vertical depth of operation**: the deeper we dig, the more dense we expect the soil to be that we need to dig through, increasing the likelihood of either a collapse or equipment wear\n", + "- **Bit depth**: Should contain similar information to the vertical depth of the operation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "start_time": "2020-08-05T10:53:26.316Z" + } + }, + "source": [ + "# Cross validation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use a simple Bootstrap for the time series analysis here. Note that if we were given a time series dataset here (i.e. if we had timestamps of the GT readings) we could use a stationary bootstrap here using `StationaryBootstrapCV`)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-05T11:28:18.712303Z", + "start_time": "2020-08-05T11:28:18.709820Z" + }, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Regressor Pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T09:26:34.988045Z", + "start_time": "2020-08-31T09:26:34.985394Z" + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "from facet.selection import LearnerRanker, LearnerGrid\n", + "from facet.validation import BootstrapCV" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:33:54.961942Z", + "start_time": "2020-08-31T08:33:54.958552Z" + } + }, + "outputs": [], + "source": [ + "cv = BootstrapCV(n_splits=10, random_state=42)\n", + "\n", + "rf_pipeline = RegressorPipelineDF(\n", + " regressor=RandomForestRegressorDF(n_estimators=500, random_state=42),\n", + ")\n", + "\n", + "lgbm_pipeline = RegressorPipelineDF(\n", + " regressor=LGBMRegressorDF(random_state=42),\n", + ")\n", + "\n", + "\n", + "grid = [\n", + " LearnerGrid(\n", + " pipeline=rf_pipeline, \n", + " learner_parameters={ \n", + " \"min_samples_leaf\": [8, 11, 15]\n", + " } \n", + " ),\n", + " LearnerGrid(\n", + " pipeline=lgbm_pipeline, \n", + " learner_parameters={ \n", + " \"min_data_in_leaf\": [8, 11, 15]\n", + " }\n", + " )\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:04.796507Z", + "start_time": "2020-08-31T08:33:54.964092Z" + } + }, + "outputs": [], + "source": [ + "ranker = LearnerRanker( \n", + " grids=grid, cv=cv, n_jobs=-3\n", + ").fit(sample=sample_selected)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:04.806643Z", + "start_time": "2020-08-31T08:34:04.799183Z" + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "RegressorPipelineDF(regressor=LGBMRegressorDF(min_data_in_leaf=8,\n", + " random_state=42))" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ranker.best_model" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:04.813316Z", + "start_time": "2020-08-31T08:34:04.809195Z" + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Rank 1: LGBMRegressorDF, ranking_score= 0.923, scores_mean= 0.948, scores_std= 0.0126, parameters={regressor__min_data_in_leaf=8}\n", + "\n", + "Rank 2: LGBMRegressorDF, ranking_score= 0.915, scores_mean= 0.942, scores_std= 0.0137, parameters={regressor__min_data_in_leaf=11}\n", + "\n", + "Rank 3: LGBMRegressorDF, ranking_score= 0.903, scores_mean= 0.934, scores_std= 0.0156, parameters={regressor__min_data_in_leaf=15}\n", + "\n", + "Rank 4: RandomForestRegressorDF, ranking_score= 0.868, scores_mean= 0.908, scores_std= 0.0196, parameters={regressor__min_samples_leaf=8}\n", + "\n", + "Rank 5: RandomForestRegressorDF, ranking_score= 0.856, scores_mean= 0.894, scores_std= 0.0191, parameters={regressor__min_samples_leaf=11}\n", + "\n", + "Rank 6: RandomForestRegressorDF, ranking_score= 0.832, scores_mean= 0.877, scores_std= 0.0224, parameters={regressor__min_samples_leaf=15}\n", + "\n" + ] + } + ], + "source": [ + "print(ranker.summary_report())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-05T11:42:06.425585Z", + "start_time": "2020-08-05T11:42:06.423740Z" + }, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Model inspection" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:09.495621Z", + "start_time": "2020-08-31T08:34:04.816216Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "inspector = LearnerInspector(n_jobs=-3)\n", + "inspector.fit(crossfit=ranker.best_model_crossfit)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:09.500322Z", + "start_time": "2020-08-31T08:34:09.497546Z" + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "redundancy_matrix = inspector.feature_redundancy_matrix()\n", + "synergy_matrix = inspector.feature_synergy_matrix()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-11T15:12:46.059970Z", + "start_time": "2020-08-11T15:12:46.055716Z" + }, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### Feature redundancy\n", + "\n", + "When plotting out the feature redundancy, we can see that there are some features which contain the same information to the model. In this case, these features are the vertical depth of the operation and the bit depth. \n", + "Intuitively, we can see why these two features are redundant, as the bit depth will be in its most critical stages when it is drilling, i.e. at the vertical depth of operation. \n", + "\n", + "As we don't want either of the features to confuse the model inference during the simulation step, we should remove the bit depth for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from facet.inspection import LearnerInspector" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T09:29:19.652252Z", + "start_time": "2020-08-31T09:29:11.212923Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "inspector = LearnerInspector(n_jobs=-3)\n", + "inspector.fit(crossfit=ranker.best_model_crossfit)\n", + "\n", + "synergy_matrix = inspector.feature_synergy_matrix()\n", + "MatrixDrawer(style=\"matplot%\").draw(synergy_matrix, title=\"Synergy\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "redundancy_matrix = inspector.feature_redundancy_matrix()\n", + "MatrixDrawer(style=\"matplot%\").draw(redundancy_matrix, title=\"Redundancy\")" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "redundant_features = [\"Bit depth [m]\"]\n", + "sample_selected = sample_selected.drop(redundant_features)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "#### Feature synergy\n", + "When looking at the synergy matrix, we can easily figure out which of the features have an interaction effect on the target. We see that the weight on the bit and the drill rate in combination appear to have a high synergy. \n", + "\n", + "In hindsight, this appears obvious - drilling with both high bit weight and a high pace can have a disproportionally large impact on the wear of the equipment." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "MatrixDrawer(style=\"matplot%\").draw(synergy_matrix, title=\"Synergy\")" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "synergy_matrix" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "# Simulation" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "From the synergy matrix, we can see that the Compressor outlet temperature has the highest synergy with most other features. Therefore, we would want to see how the target behaves if we simulate this feature such that each state had a constant outlet compressor temperature. \n", + "\n", + "First of all, let's see if this is also confirmed by the SHAP feature importances. " + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "feat_importance = synergy_matrix.sum(axis=0).reset_index().rename({0: \"Total Synergies\"}, axis=1)\n", + "feat_importance[\"Total Synergies\"] -= 1" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "feat_importance.sort_values(by=\"Total Synergies\", ascending=False)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "We can see that the strong synergies with all other features of the Compressor outlet air temperature is also visible in the aboslute SHAP values. " + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "simulator = UnivariateUpliftSimulator(crossfit = ranker.best_model_crossfit, n_jobs=3)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "cont_partitioner = ContinuousRangePartitioner()" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "SIM_FEATURE = 'Weight on bit (kg)'\n", + "simulation = simulator.simulate_feature(name=SIM_FEATURE, partitioner = cont_partitioner)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(15, 10))\n", + "\n", + "SimulationDrawer().draw(\n", + " data=simulation, title=SIM_FEATURE\n", + ")" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T09:30:10.362980Z", + "start_time": "2020-08-31T09:30:10.009361Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(15, 10))\n", + "\n", + "SimulationDrawer().draw(\n", + " data=simulation, title=SIM_FEATURE\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:09.878333Z", + "start_time": "2020-08-31T08:34:09.875037Z" + } + }, + "outputs": [], + "source": [ + "redundant_features = [\"Bit depth [m]\"]\n", + "sample_selected = sample_selected.drop(redundant_features)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-11T15:17:27.725770Z", + "start_time": "2020-08-11T15:17:27.723200Z" + }, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### Feature synergy\n", + "When looking at the synergy matrix, we can easily figure out which of the features have an interaction effect on the target. We see that the weight on the bit and the drill rate in combination appear to have a high synergy. \n", + "\n", + "In hindsight, this appears obvious - drilling with both high bit weight and a high pace can have a disproportionally large impact on the wear of the equipment." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:10.223653Z", + "start_time": "2020-08-31T08:34:09.880444Z" + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "MatrixDrawer(style=\"matplot%\").draw(synergy_matrix, title=\"Synergy\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:10.235888Z", + "start_time": "2020-08-31T08:34:10.225319Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
featureWeight on bit (kg)Drill rate (m/s)Vertical depth of operation (m)Mud density (kg/m3)Nonlinear1Bit depth (m)
feature
Weight on bit (kg)1.0000000.2285900.0474360.0421170.0234870.049195
Drill rate (m/s)0.2285901.0000000.0698020.0486520.0329360.044492
Vertical depth of operation (m)0.0474360.0698021.0000000.0713690.0672880.050473
Mud density (kg/m3)0.0421170.0486520.0713691.0000000.0790530.081128
Nonlinear10.0234870.0329360.0672880.0790531.0000000.070590
Bit depth (m)0.0491950.0444920.0504730.0811280.0705901.000000
\n", + "
" + ], + "text/plain": [ + "feature Weight on bit (kg) Drill rate (m/s) \\\n", + "feature \n", + "Weight on bit (kg) 1.000000 0.228590 \n", + "Drill rate (m/s) 0.228590 1.000000 \n", + "Vertical depth of operation (m) 0.047436 0.069802 \n", + "Mud density (kg/m3) 0.042117 0.048652 \n", + "Nonlinear1 0.023487 0.032936 \n", + "Bit depth (m) 0.049195 0.044492 \n", + "\n", + "feature Vertical depth of operation (m) \\\n", + "feature \n", + "Weight on bit (kg) 0.047436 \n", + "Drill rate (m/s) 0.069802 \n", + "Vertical depth of operation (m) 1.000000 \n", + "Mud density (kg/m3) 0.071369 \n", + "Nonlinear1 0.067288 \n", + "Bit depth (m) 0.050473 \n", + "\n", + "feature Mud density (kg/m3) Nonlinear1 \\\n", + "feature \n", + "Weight on bit (kg) 0.042117 0.023487 \n", + "Drill rate (m/s) 0.048652 0.032936 \n", + "Vertical depth of operation (m) 0.071369 0.067288 \n", + "Mud density (kg/m3) 1.000000 0.079053 \n", + "Nonlinear1 0.079053 1.000000 \n", + "Bit depth (m) 0.081128 0.070590 \n", + "\n", + "feature Bit depth (m) \n", + "feature \n", + "Weight on bit (kg) 0.049195 \n", + "Drill rate (m/s) 0.044492 \n", + "Vertical depth of operation (m) 0.050473 \n", + "Mud density (kg/m3) 0.081128 \n", + "Nonlinear1 0.070590 \n", + "Bit depth (m) 1.000000 " + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "synergy_matrix" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Simulation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-07T15:56:26.709687Z", + "start_time": "2020-08-07T15:56:26.682253Z" + } + }, + "source": [ + "From the synergy matrix, we can see that the Compressor outlet temperature has the highest synergy with most other features. Therefore, we would want to see how the target behaves if we simulate this feature such that each state had a constant outlet compressor temperature. \n", + "\n", + "First of all, let's see if this is also confirmed by the SHAP feature importances. " + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:10.244437Z", + "start_time": "2020-08-31T08:34:10.237536Z" + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "feat_importance = synergy_matrix.sum(axis=0).reset_index().rename({0: \"Total Synergies\"}, axis=1)\n", + "feat_importance[\"Total Synergies\"] -= 1" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:10.253592Z", + "start_time": "2020-08-31T08:34:10.245903Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
featureTotal Synergies
1Drill rate (m/s)0.424472
0Weight on bit (kg)0.390824
3Mud density (kg/m3)0.322319
2Vertical depth of operation (m)0.306369
5Bit depth (m)0.295878
4Nonlinear10.273354
\n", + "
" + ], + "text/plain": [ + " feature Total Synergies\n", + "1 Drill rate (m/s) 0.424472\n", + "0 Weight on bit (kg) 0.390824\n", + "3 Mud density (kg/m3) 0.322319\n", + "2 Vertical depth of operation (m) 0.306369\n", + "5 Bit depth (m) 0.295878\n", + "4 Nonlinear1 0.273354" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "feat_importance.sort_values(by=\"Total Synergies\", ascending=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-07T16:01:58.630423Z", + "start_time": "2020-08-07T16:01:58.625941Z" + }, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "We can see that the strong synergies with all other features of the Compressor outlet air temperature is also visible in the aboslute SHAP values. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T08:34:10.259302Z", + "start_time": "2020-08-31T08:34:10.256138Z" + }, + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "simulator = UnivariateUpliftSimulator(crossfit = ranker.best_model_crossfit, n_jobs=3)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T09:34:04.743896Z", + "start_time": "2020-08-31T09:34:04.741417Z" + } + }, + "outputs": [], + "source": [ + "cont_partitioner = ContinuousRangePartitioner()" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T09:34:15.759056Z", + "start_time": "2020-08-31T09:34:15.051788Z" + }, + "pycharm": { + "name": "#%%\n" + }, + "scrolled": false + }, + "outputs": [], + "source": [ + "SIM_FEATURE = 'Weight on bit (kg)'\n", + "simulation = simulator.simulate_feature(name=SIM_FEATURE, partitioner = cont_partitioner)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "ExecuteTime": { + "end_time": "2020-08-31T09:34:18.298969Z", + "start_time": "2020-08-31T09:34:18.060638Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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ffrzFREREcnerIV//xtatoRixWDpUiV8gZBjk76CBQty4MABJQY5lLWWAwcOULBgQa9DEREREZELkJAA99wD//wntG3runXWquV1VDlTji3vrFixIjt27GDfvn1ehyIBUrBgwXTnHIqIiIhI8Nq2ze3fW74cXngBBg2CPDl2Ocp7OTbpy5cvH1WqVPE6DBERERERSWXePOjWDY4fh+nToUMHryPK+ZRPi4iIiIhIwFkL774LrVpB2bKunFMJX9ZQ0iciIiIiIgEVHw89e8ITT0DHjq5hS7VqXkeVeyjpExERERGRgNm8GRo3hokT4fXXYcoUKFrU66hylxy7p09ERERERLz1/ffQowcYA999B23aeB1R7qSVPhERERER8Str3arezTdDpUoQHa2Ez0ueJn3GmNHGmL3GmLWpjr1ojPnLGLPK93WzlzGKiIiIiEjmxca6cQwDBkD37vDTT3DllV5Hlbt5vdI3BmibxvH3rLWRvq9ZWRyTiIiIiIhcgA0boEED+OYb16lz/HgoXNjrqMTTPX3W2gXGmMpexiAiIiIiIhdv+nS4804oUADmzIGWLb2OSE7yeqUvPf80xqzxlX+W9DoYERERERFJW3IyDBrkRjFccw0sX66EL9gEY9L3H+AqIBLYBbyT1knGmD7GmGhjTPS+ffuyMj4REREREQFiYqB9e3jlFejdGxYudI1bJLgEXdJnrd1jrT1hrU0GRgIN0jlvhLU2ylobVbZs2awNUkREREQkl1u7FurXh9mz4aOPYPRoKFTI66gkLUGX9Bljyqd6eRuwNr1zRUREREQk602eDI0aQVwc/PgjPPSQm8UnwcnTRi7GmC+AFkAZY8wO4AWghTEmErDAVqCvZwGKiIiIiMhpBg1y5ZyNG8OUKVChgtcRybl43b2zRxqHR2V5ICIiIiIick7DhrmE79574T//gfz5vY5IMsPTpE9ERERERLKHmTPh0Uddl84RIyBvXq8jkswKuj19IiIiIiISXFavhu7dITISxo1TwpfdKOkTEREREZF07doF7dpB8eLw7bdQuLDXEcn5UnmniIiIiIikKT7ezeH7+29YtEhNW7IrJX0iIiIiInKW5GS4805YuRKmT3elnZI9KekTEREREZGzPPssfP01DB3qyjsl+9KePhEREREROc0nn8Bbb8HDD0O/fl5HIxdLSZ+IiIiIiKT4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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(15, 10))\n", + "\n", + "SimulationDrawer().draw(\n", + " data=simulation, title=SIM_FEATURE\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.8" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/sphinx/Makefile b/sphinx/Makefile deleted file mode 100644 index e57687d00..000000000 --- a/sphinx/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXBUILD = sphinx-build -SOURCEDIR = source -BUILDDIR = build -TEMPLATEDIR = "${SOURCEDIR}/_templates" -#DOCSDIR = ../docs -SCRIPTSDIR = "${SOURCEDIR}/scripts" -TUTORIALDIR = ../notebooks -#TUTORIALDIR = ${SOURCEDIR}/tutorial -#QS_TUTORIALDIR = "../../alpha-quickstart/tutorials" -TUTORIALBUILD = "${SCRIPTSDIR}/transform_notebook.py" - -SPHINXOPTS = -SPHINXAPIDOCOPTS = -e -t ${TEMPLATEDIR} --no-toc -o $(SOURCEDIR)/api/ -f - -# export SPHINX_APIDOC_OPTIONS = members,undoc-members,inherited-members,no-show-inheritance - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -clean: - -rm -r "$(BUILDDIR)" -# -rm -r "$(SOURCEDIR)"/api -# -rm "$(SOURCEDIR)"/gamma.*.rst -# -rm "$(SOURCEDIR)"/*.automodsumm - -apidoc: - sphinx-apidoc ${SPHINXAPIDOCOPTS} ../src - -build: - # run the Sphinx build for html - @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - - # create a nojekyll file for gh-pages: - touch "$(BUILDDIR)"/html/.nojekyll - - # clean up potentially pre-existing files in /docs and move build: - #if [ -d "${DOCSDIR}" ]; then \ - # rm -rf "${DOCSDIR}"/*.html "${DOCSDIR}"/*.js "${DOCSDIR}"/*.inv "${DOCSDIR}"/_* \ - # "${DOCSDIR}"/api "${DOCSDIR}"/tutorial; \ - #fi - # move the last build into /docs - #if [ -d "../docs" ]; then mv "$(BUILDDIR)"/html/* ../docs/; fi - - -html: build # add apidoc as a dependence to generate separate files per package - - -tutorial: - # build the tutorial notebooks - @$(TUTORIALBUILD) "${TUTORIALDIR}" - mv "${TUTORIALDIR}/example-model-inspection.ipynb" "${TUTORIALDIR}/1-example-model-inspection.ipynb" -# mv "${QS_TUTORIALDIR}/sklearndf.ipynb" "${QS_TUTORIALDIR}/2-sklearndf.ipynb" -# mv "${QS_TUTORIALDIR}/model.ipynb" "${QS_TUTORIALDIR}/3-model.ipynb" -# mv "${QS_TUTORIALDIR}/simulation.ipynb" "${QS_TUTORIALDIR}/4-simulation.ipynb" - - -# maybe not needed? -html-gh-pages: - # target to generate github pages build on branch "gh-pages" - cd .. && \ - git checkout gh-pages && \ - rm -rf * && \ - git checkout master sphinx data scripts && \ - git reset HEAD && cd sphinx && make html && \ - cd .. && \ - mv -fv "./sphinx/$(BUILDDIR)"/html/* ./ && \ - mkdir -p _static/notebooks && \ - python scripts/transform_notebook.py ../notebooks/ _static/notebooks/ && \ - rm -rf sphinx data scripts && git add -A - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/sphinx/auxiliary/Boston_getting_started_example.ipynb b/sphinx/auxiliary/Boston_getting_started_example.ipynb index 143975f94..cc8bd836e 100644 --- a/sphinx/auxiliary/Boston_getting_started_example.ipynb +++ b/sphinx/auxiliary/Boston_getting_started_example.ipynb @@ -90,6 +90,7 @@ "cell_type": "code", "execution_count": 1, "metadata": { + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [ @@ -144,6 +145,7 @@ "cell_type": "code", "execution_count": 8, "metadata": { + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [], diff --git a/sphinx/make.bat b/sphinx/make.bat deleted file mode 100644 index 0f95d1c2a..000000000 --- a/sphinx/make.bat +++ /dev/null @@ -1,59 +0,0 @@ -@ECHO OFF -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build -set NOTEBOOK_EXAMPLES=..\notebooks -REM say to apidoc which members to consider -set SPHINX_APIDOC_OPTIONS=members,undoc-members,inherited-members - - -if "%1" == "" goto help -if "%1" == "html" goto html - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:html -REM generate apidoc using docstrings -sphinx-apidoc -e --no-toc -o %SOURCEDIR%/api/ -f ../src - -REM run the sphinx build for html -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -REM run sphinx for notebook -REM %SPHINXBUILD% -b %1 -c %SOURCEDIR% %NOTEBOOK_EXAMPLES% %BUILDDIR% %SPHINXOPTS% - -REM clean up potentially pre-existing files in /docs -del /q /s ..\docs\* >nul -for /d %%i in (..\docs\*) do rd /s /q "%%i" -REM move the last build into /docs -set DIR_HTML=build\html -set DIR_DOCS=..\docs -for %%i in (%DIR_HTML%\*) do move "%%i" %DIR_DOCS%\ >nul -for /d %%i in (%DIR_HTML%\*) do move "%%i" %DIR_DOCS%\ >nul -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd \ No newline at end of file diff --git a/sphinx/make.py b/sphinx/make.py index f4b2d7c1d..1e4798c20 100755 --- a/sphinx/make.py +++ b/sphinx/make.py @@ -4,6 +4,7 @@ from typing import Callable, NamedTuple, Tuple import shutil import subprocess +from source.scripts.transform_notebook import docs_notebooks_to_interactive pwd = os.path.realpath(os.path.dirname(__file__)) @@ -15,11 +16,13 @@ # todo: check which ones are eventually obsolete FACET_SOURCEDIR = os.path.join(pwd, os.pardir, "src") SOURCEDIR = os.path.join(pwd, "source") +AUXILIARYDIR = os.path.join(pwd, "auxiliary") SOURCEAPIDIR = os.path.join(SOURCEDIR, "api") BUILDDIR = os.path.join(pwd, "build") TEMPLATEDIR = os.path.join(SOURCEDIR, "_templates") SCRIPTSDIR = os.path.join(SOURCEDIR, "scripts") -TUTORIALDIR = os.path.join(SOURCEDIR, os.pardir, "notebooks") +TUTORIALDIR = os.path.join(SOURCEDIR, "tutorial") +NOTEBOOKDIR = os.path.join(FACET_SOURCEDIR, os.pardir, "notebooks") TUTORIALBUILD = os.path.join(SCRIPTSDIR, "transform_notebook.py") @@ -73,6 +76,8 @@ def fun_html(): subprocess.run( args=f"{CMD_SPHINXBUILD} {' '.join(sphinx_html_opts)}", shell=True, check=True ) + docs_notebooks_to_interactive(TUTORIALDIR, NOTEBOOKDIR) + # docs_notebooks_to_interactive(AUXILIARYDIR, NOTEBOOKDIR) # Define MakeCommands diff --git a/sphinx/source/examples.rst b/sphinx/source/examples.rst index 53575a18d..ee492789d 100644 --- a/sphinx/source/examples.rst +++ b/sphinx/source/examples.rst @@ -13,6 +13,8 @@ Classification using FACET tutorial/Classification_with_Facet + + Predictive Maintenance Regression ------------------------------------------------ .. toctree:: @@ -21,6 +23,7 @@ Predictive Maintenance Regression tutorial/Predictive_Maintenance_Regression_with_Facet + Understanding synergy and redundancy through simulation ------------------------------------------------------------ .. toctree:: @@ -29,6 +32,7 @@ Understanding synergy and redundancy through simulation tutorial/Classification_simulation_example_Facet + Regression machine failures on a water well (simulated) ----------------------------------------------------------- diff --git a/sphinx/source/tutorial/Classification_simulation_example_Facet.ipynb b/sphinx/source/tutorial/Classification_simulation_example_Facet.ipynb index e35f4f4ad..9ee34b901 100644 --- a/sphinx/source/tutorial/Classification_simulation_example_Facet.ipynb +++ b/sphinx/source/tutorial/Classification_simulation_example_Facet.ipynb @@ -60,6 +60,7 @@ "cell_type": "code", "execution_count": null, "metadata": { + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [], @@ -130,6 +131,7 @@ "cell_type": "code", "execution_count": null, "metadata": { + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [], diff --git a/sphinx/source/tutorial/Classification_with_Facet.ipynb b/sphinx/source/tutorial/Classification_with_Facet.ipynb index 6580f46a2..14346820a 100644 --- a/sphinx/source/tutorial/Classification_with_Facet.ipynb +++ b/sphinx/source/tutorial/Classification_with_Facet.ipynb @@ -57,6 +57,7 @@ "cell_type": "code", "execution_count": null, "metadata": { + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [], @@ -145,6 +146,7 @@ "cell_type": "code", "execution_count": null, "metadata": { + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [], diff --git a/sphinx/source/tutorial/Predictive_Maintenance_Regression_with_Facet.ipynb b/sphinx/source/tutorial/Predictive_Maintenance_Regression_with_Facet.ipynb index bd785f480..78a7f2304 100644 --- a/sphinx/source/tutorial/Predictive_Maintenance_Regression_with_Facet.ipynb +++ b/sphinx/source/tutorial/Predictive_Maintenance_Regression_with_Facet.ipynb @@ -60,6 +60,7 @@ "end_time": "2020-08-28T14:29:36.416582Z", "start_time": "2020-08-28T14:29:36.410164Z" }, + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [], @@ -109,6 +110,7 @@ "end_time": "2020-08-28T14:29:36.537625Z", "start_time": "2020-08-28T14:29:36.419137Z" }, + "delete_for_interactive": true, "nbsphinx": "hidden" }, "outputs": [],