From d2312e1fdbbae886fe7bf89d9962b8b2e8b88a68 Mon Sep 17 00:00:00 2001 From: ignaciolorenzo <80812996+ignaciolorenzo@users.noreply.github.com> Date: Sat, 2 Oct 2021 17:26:41 +0200 Subject: [PATCH] [lab-handling-data-imbalance-classification] Ignacio --- ...ta-imbalance-classification] Ignacio.ipynb | 1066 +++++++++++++++++ 1 file changed, 1066 insertions(+) create mode 100644 [lab-handling-data-imbalance-classification] Ignacio.ipynb diff --git a/[lab-handling-data-imbalance-classification] Ignacio.ipynb b/[lab-handling-data-imbalance-classification] Ignacio.ipynb new file mode 100644 index 0000000..96ae1dd --- /dev/null +++ b/[lab-handling-data-imbalance-classification] Ignacio.ipynb @@ -0,0 +1,1066 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "845db9b1", + "metadata": {}, + "source": [ + "# Lab | Handling Data Imbalance in Classification Models\n" + ] + }, + { + "cell_type": "markdown", + "id": "1c081a45", + "metadata": {}, + "source": [ + "### Import the required libraries and modules that you would need." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "158ef718", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: pymysql in /usr/local/Caskroom/miniconda/base/lib/python3.8/site-packages (1.0.2)\r\n" + ] + } + ], + "source": [ + "!pip install pymysql" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "50c36c38", + "metadata": {}, + "outputs": [], + "source": [ + "import pymysql\n", + "from sqlalchemy import create_engine\n", + "import pandas as pd\n", + "import numpy as np\n", + "import getpass\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import confusion_matrix\n", + "from sklearn.preprocessing import OneHotEncoder, Normalizer, LabelEncoder\n", + "from imblearn.over_sampling import SMOTE\n", + "from imblearn.under_sampling import TomekLinks" + ] + }, + { + "cell_type": "markdown", + "id": "21678c70", + "metadata": {}, + "source": [ + "### Read that data into Python and call the dataframe churnData." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4163fc9c", + "metadata": {}, + "outputs": [], + "source": [ + "churnData = pd.read_csv(\"files_for_lab/Customer-Churn.csv\")" + ] + }, + { + "cell_type": "markdown", + "id": "1eb39034", + "metadata": {}, + "source": [ + "## Check the datatypes of all the columns in the data. \n", + "\n", + "You would see that the column TotalCharges is object type. Convert this column into numeric type using pd.to_numeric function.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ade1fca1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "gender object\n", + "SeniorCitizen int64\n", + "Partner object\n", + "Dependents object\n", + "tenure int64\n", + "PhoneService object\n", + "OnlineSecurity object\n", + "OnlineBackup object\n", + "DeviceProtection object\n", + "TechSupport object\n", + "StreamingTV object\n", + "StreamingMovies object\n", + "Contract object\n", + "MonthlyCharges float64\n", + "TotalCharges object\n", + "Churn object\n", + "dtype: object" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "churnData.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "78c5f37f", + "metadata": {}, + "outputs": [], + "source": [ + "churnData[\"TotalCharges\"] = pd.to_numeric(churnData[\"TotalCharges\"], errors = 'coerce')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ad4e5e37", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dtype('float64')" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "churnData[\"TotalCharges\"].dtypes" + ] + }, + { + "cell_type": "markdown", + "id": "1a68aed9", + "metadata": {}, + "source": [ + "### Check for null values in the dataframe. Replace the null values." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0c99d706", + "metadata": {}, + "outputs": [], + "source": [ + "def checking_nulls(df):\n", + " # This function shows which columns have null values and returns a df with only nulls\n", + " for c in df.columns:\n", + " null_count = df[c].isnull().sum()\n", + " if null_count > 0:\n", + " print (\"The column \", c, \" has \", null_count, \" null values\")\n", + " nulls = df[df.isna().any(axis=1)]\n", + " return nulls.head(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c904923c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The column TotalCharges has 11 null values\n" + ] + }, + { + "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", + " \n", + " \n", + " \n", + " \n", + "
genderSeniorCitizenPartnerDependentstenurePhoneServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportStreamingTVStreamingMoviesContractMonthlyChargesTotalChargesChurn
488Female0YesYes0NoYesNoYesYesYesNoTwo year52.55NaNNo
753Male0NoYes0YesNo internet serviceNo internet serviceNo internet serviceNo internet serviceNo internet serviceNo internet serviceTwo year20.25NaNNo
936Female0YesYes0YesYesYesYesNoYesYesTwo year80.85NaNNo
\n", + "
" + ], + "text/plain": [ + " gender SeniorCitizen Partner Dependents tenure PhoneService \\\n", + "488 Female 0 Yes Yes 0 No \n", + "753 Male 0 No Yes 0 Yes \n", + "936 Female 0 Yes Yes 0 Yes \n", + "\n", + " OnlineSecurity OnlineBackup DeviceProtection \\\n", + "488 Yes No Yes \n", + "753 No internet service No internet service No internet service \n", + "936 Yes Yes Yes \n", + "\n", + " TechSupport StreamingTV StreamingMovies Contract \\\n", + "488 Yes Yes No Two year \n", + "753 No internet service No internet service No internet service Two year \n", + "936 No Yes Yes Two year \n", + "\n", + " MonthlyCharges TotalCharges Churn \n", + "488 52.55 NaN No \n", + "753 20.25 NaN No \n", + "936 80.85 NaN No " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "checking_nulls(churnData)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "7ab15a14", + "metadata": {}, + "outputs": [], + "source": [ + "def replace_nulls_mean(df):\n", + " # This function replaces null values with the mean of the column.\n", + " for c in df.columns:\n", + " null_count = df[c].isnull().sum()\n", + " if null_count > 0:\n", + " df[c].fillna((df[c].mean()), inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "61af7a57", + "metadata": {}, + "outputs": [], + "source": [ + "replace_nulls_mean(churnData)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d0df64cb", + "metadata": {}, + "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", + "
genderSeniorCitizenPartnerDependentstenurePhoneServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportStreamingTVStreamingMoviesContractMonthlyChargesTotalChargesChurn
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [gender, SeniorCitizen, Partner, Dependents, tenure, PhoneService, OnlineSecurity, OnlineBackup, DeviceProtection, TechSupport, StreamingTV, StreamingMovies, Contract, MonthlyCharges, TotalCharges, Churn]\n", + "Index: []" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "checking_nulls(churnData)" + ] + }, + { + "cell_type": "markdown", + "id": "c459fccb", + "metadata": {}, + "source": [ + "### Use the following features: tenure, SeniorCitizen, MonthlyCharges and TotalCharges:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "c7a78e38", + "metadata": {}, + "outputs": [], + "source": [ + "y = pd.DataFrame(churnData[\"Churn\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "b9f1fe59", + "metadata": {}, + "outputs": [], + "source": [ + "for c in churnData.columns:\n", + " if c not in ['tenure', 'SeniorCitizen', 'MonthlyCharges', 'TotalCharges']:\n", + " X = churnData.drop(c, axis = 1, inplace = True)" + ] + }, + { + "cell_type": "markdown", + "id": "7444f8ce", + "metadata": {}, + "source": [ + "#### - Scale the features either by using normalizer or a standard scaler." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "93c1489f", + "metadata": {}, + "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", + "
SeniorCitizentenureMonthlyChargesTotalCharges
00129.8529.85
103456.951889.50
20253.85108.15
\n", + "
" + ], + "text/plain": [ + " SeniorCitizen tenure MonthlyCharges TotalCharges\n", + "0 0 1 29.85 29.85\n", + "1 0 34 56.95 1889.50\n", + "2 0 2 53.85 108.15" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "churnData.head(3)" + ] + }, + { + "cell_type": "markdown", + "id": "7d1a1fc7", + "metadata": {}, + "source": [ + "#### - Scale the features either by using normalizer or a standard scaler." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "34c7ee22", + "metadata": {}, + "outputs": [], + "source": [ + "transformer = Normalizer().fit(churnData)\n", + "transformer\n", + "churnData_norm = transformer.transform(churnData)\n", + "churnData_norm = pd.DataFrame(churnData_norm, columns=churnData.columns, index=churnData.index)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "d9f2952f", + "metadata": {}, + "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", + "
SeniorCitizentenureMonthlyChargesTotalCharges
00129.8529.85
103456.951889.50
20253.85108.15
\n", + "
" + ], + "text/plain": [ + " SeniorCitizen tenure MonthlyCharges TotalCharges\n", + "0 0 1 29.85 29.85\n", + "1 0 34 56.95 1889.50\n", + "2 0 2 53.85 108.15" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "churnData.head(3)" + ] + }, + { + "cell_type": "markdown", + "id": "90f3d27f", + "metadata": {}, + "source": [ + "#### - Split the data into a training set and a test set." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "ffd59304", + "metadata": {}, + "outputs": [], + "source": [ + "X = churnData" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "b140ba30", + "metadata": {}, + "outputs": [], + "source": [ + "X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)" + ] + }, + { + "cell_type": "markdown", + "id": "ea6b490b", + "metadata": {}, + "source": [ + "#### - Fit a logistic regression model on the training data." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "4ac34124", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.9/site-packages/sklearn/utils/validation.py:63: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " return f(*args, **kwargs)\n" + ] + }, + { + "data": { + "text/plain": [ + "LogisticRegression()" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "logreg = LogisticRegression()\n", + "logreg.fit(X_train, y_train)" + ] + }, + { + "cell_type": "markdown", + "id": "0479584e", + "metadata": {}, + "source": [ + "#### - Check the accuracy on the test data." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "ed9c2932", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.7825099375354913" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "logreg.score(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "id": "753a6100", + "metadata": {}, + "source": [ + "### Managing imbalance in the dataset" + ] + }, + { + "cell_type": "markdown", + "id": "459b3f84", + "metadata": {}, + "source": [ + "#### - Check for the imbalance." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "4c851cbc", + "metadata": {}, + "outputs": [], + "source": [ + "def cat_exploration(df):\n", + " # This function displays the proportion of each value type for each categorical column and its countplot\n", + " cat = df.select_dtypes('object')\n", + " for c in cat.columns:\n", + " sns.set_style(\"darkgrid\")\n", + " print(c)\n", + " print(cat[c].value_counts(normalize=True).mul(100).round(1))\n", + " print(cat[c].value_counts())\n", + " fig, axes = plt.subplots(1, 1, figsize=(7, 4))\n", + " sns.countplot(cat[c], color = 'gray')\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "ea790eb9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Churn\n", + "No 73.5\n", + "Yes 26.5\n", + "Name: Churn, dtype: float64\n", + "No 5174\n", + "Yes 1869\n", + "Name: Churn, dtype: int64\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.9/site-packages/seaborn/_decorators.py:36: FutureWarning: Pass the following variable as a keyword arg: x. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cat_exploration(y)" + ] + }, + { + "cell_type": "markdown", + "id": "f9ff4b30", + "metadata": {}, + "source": [ + "#### - Use the resampling strategies used in class for upsampling and downsampling to create a balance between the two classes." + ] + }, + { + "cell_type": "markdown", + "id": "8c3c90a7", + "metadata": {}, + "source": [ + "Upsampling " + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "94b1a773", + "metadata": {}, + "outputs": [], + "source": [ + "data_up = pd.concat([X_train, y_train], axis=1)\n", + "\n", + "Yes = data_up[data_up['Churn'] == 'Yes'].sample(5174, replace=True) \n", + "No = data_up[data_up['Churn'] == 'No'].sample(5174, replace=True)\n", + "\n", + "upsampled_train = pd.concat([Yes, No]).sample(frac=1)\n", + "X_up_train = upsampled_train.drop(\"Churn\", axis = 1)\n", + "y_up_train = upsampled_train[\"Churn\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "28bfc008", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.6802952867688813" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "logreg.fit(X_up_train, y_up_train)\n", + "logreg.score(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "id": "6e81bcb4", + "metadata": {}, + "source": [ + "SMOTE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b3284e8", + "metadata": {}, + "outputs": [], + "source": [ + "X_train_sm = X_train.copy()\n", + "y_train_sm = y_train.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "bb347843", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Churn\n", + "No 3876\n", + "Yes 3876\n", + "dtype: int64" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "smote = SMOTE()\n", + "\n", + "X_train_sm, y_train_sm = smote.fit_resample(X_train_sm, y_train_sm)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "dd502e3d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.9/site-packages/sklearn/utils/validation.py:63: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " return f(*args, **kwargs)\n" + ] + }, + { + "data": { + "text/plain": [ + "0.7149346961953436" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "logreg.fit(X_train_sm, y_train_sm)\n", + "logreg.score(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "id": "0244b7dd", + "metadata": {}, + "source": [ + "Downsampling" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "3a297581", + "metadata": {}, + "outputs": [], + "source": [ + "data_dw = pd.concat([X_train, y_train], axis=1)\n", + "\n", + "Yes = data_dw[data_dw['Churn'] == 'Yes'].sample(1869, replace=True) \n", + "No = data_dw[data_dw['Churn'] == 'No'].sample(1869, replace=True)\n", + "\n", + "downsampled_train = pd.concat([Yes, No]).sample(frac=1)\n", + "X_dw_train = downsampled_train.drop(\"Churn\", axis = 1)\n", + "y_dw_train = downsampled_train[\"Churn\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "ca69c794", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.7018739352640545" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "logreg.fit(X_dw_train, y_dw_train)\n", + "logreg.score(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "id": "a575d10d", + "metadata": {}, + "source": [ + "Tomeklinks" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "9bb45d7b", + "metadata": {}, + "outputs": [], + "source": [ + "X_train_tl = X_train.copy()\n", + "y_train_tl = y_train.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "cef786c7", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/Cellar/jupyterlab/3.0.16_1/libexec/lib/python3.9/site-packages/imblearn/utils/_validation.py:587: FutureWarning: Pass sampling_strategy=majority as keyword args. From version 0.9 passing these as positional arguments will result in an error\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "tl = TomekLinks('majority')\n", + "\n", + "X_train_tl, y_train_tl = tl.fit_resample(X_train_tl, y_train_tl)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "3e09f8c3", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/local/lib/python3.9/site-packages/sklearn/utils/validation.py:63: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().\n", + " return f(*args, **kwargs)\n" + ] + }, + { + "data": { + "text/plain": [ + "0.7597955706984668" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "logreg.fit(X_train_tl, y_train_tl)\n", + "logreg.score(X_test, y_test)" + ] + } + ], + "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.9.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}