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",
+ " gender | \n",
+ " SeniorCitizen | \n",
+ " Partner | \n",
+ " Dependents | \n",
+ " tenure | \n",
+ " PhoneService | \n",
+ " OnlineSecurity | \n",
+ " OnlineBackup | \n",
+ " DeviceProtection | \n",
+ " TechSupport | \n",
+ " StreamingTV | \n",
+ " StreamingMovies | \n",
+ " Contract | \n",
+ " MonthlyCharges | \n",
+ " TotalCharges | \n",
+ " Churn | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 488 | \n",
+ " Female | \n",
+ " 0 | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " 0 | \n",
+ " No | \n",
+ " Yes | \n",
+ " No | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " No | \n",
+ " Two year | \n",
+ " 52.55 | \n",
+ " NaN | \n",
+ " No | \n",
+ "
\n",
+ " \n",
+ " | 753 | \n",
+ " Male | \n",
+ " 0 | \n",
+ " No | \n",
+ " Yes | \n",
+ " 0 | \n",
+ " Yes | \n",
+ " No internet service | \n",
+ " No internet service | \n",
+ " No internet service | \n",
+ " No internet service | \n",
+ " No internet service | \n",
+ " No internet service | \n",
+ " Two year | \n",
+ " 20.25 | \n",
+ " NaN | \n",
+ " No | \n",
+ "
\n",
+ " \n",
+ " | 936 | \n",
+ " Female | \n",
+ " 0 | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " 0 | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " No | \n",
+ " Yes | \n",
+ " Yes | \n",
+ " Two year | \n",
+ " 80.85 | \n",
+ " NaN | \n",
+ " No | \n",
+ "
\n",
+ " \n",
+ "
\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",
+ " gender | \n",
+ " SeniorCitizen | \n",
+ " Partner | \n",
+ " Dependents | \n",
+ " tenure | \n",
+ " PhoneService | \n",
+ " OnlineSecurity | \n",
+ " OnlineBackup | \n",
+ " DeviceProtection | \n",
+ " TechSupport | \n",
+ " StreamingTV | \n",
+ " StreamingMovies | \n",
+ " Contract | \n",
+ " MonthlyCharges | \n",
+ " TotalCharges | \n",
+ " Churn | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\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",
+ " SeniorCitizen | \n",
+ " tenure | \n",
+ " MonthlyCharges | \n",
+ " TotalCharges | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0 | \n",
+ " 1 | \n",
+ " 29.85 | \n",
+ " 29.85 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 0 | \n",
+ " 34 | \n",
+ " 56.95 | \n",
+ " 1889.50 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 0 | \n",
+ " 2 | \n",
+ " 53.85 | \n",
+ " 108.15 | \n",
+ "
\n",
+ " \n",
+ "
\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",
+ " SeniorCitizen | \n",
+ " tenure | \n",
+ " MonthlyCharges | \n",
+ " TotalCharges | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0 | \n",
+ " 1 | \n",
+ " 29.85 | \n",
+ " 29.85 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 0 | \n",
+ " 34 | \n",
+ " 56.95 | \n",
+ " 1889.50 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 0 | \n",
+ " 2 | \n",
+ " 53.85 | \n",
+ " 108.15 | \n",
+ "
\n",
+ " \n",
+ "
\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
+}