From 0c62139d92a09a66e43fffa620f185e97d2add59 Mon Sep 17 00:00:00 2001 From: CharlotteStiller <76783661+CharlotteStiller@users.noreply.github.com> Date: Thu, 30 Sep 2021 15:50:26 +0200 Subject: [PATCH] Add files via upload --- Solutions.ipynb | 744 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 744 insertions(+) create mode 100644 Solutions.ipynb diff --git a/Solutions.ipynb b/Solutions.ipynb new file mode 100644 index 0000000..e045f47 --- /dev/null +++ b/Solutions.ipynb @@ -0,0 +1,744 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5a37bb75", + "metadata": {}, + "source": [ + "1. ) Import the required libraries and modules that you would need." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d66768a", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.neural_network import MLPRegressor\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.preprocessing import OneHotEncoder, Normalizer, LabelEncoder\n", + "from sklearn import metrics\n", + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "markdown", + "id": "73648fab", + "metadata": {}, + "source": [ + "2.) Read that data into Python and call the dataframe churnData." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c25f693d", + "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", + " \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", + " \n", + " \n", + " \n", + "
genderSeniorCitizenPartnerDependentstenurePhoneServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportStreamingTVStreamingMoviesContractMonthlyChargesTotalChargesChurn
0Female0YesNo1NoNoYesNoNoNoNoMonth-to-month29.8529.85No
1Male0NoNo34YesYesNoYesNoNoNoOne year56.951889.5No
2Male0NoNo2YesYesYesNoNoNoNoMonth-to-month53.85108.15Yes
3Male0NoNo45NoYesNoYesYesNoNoOne year42.301840.75No
4Female0NoNo2YesNoNoNoNoNoNoMonth-to-month70.70151.65Yes
\n", + "
" + ], + "text/plain": [ + " gender SeniorCitizen Partner Dependents tenure PhoneService \\\n", + "0 Female 0 Yes No 1 No \n", + "1 Male 0 No No 34 Yes \n", + "2 Male 0 No No 2 Yes \n", + "3 Male 0 No No 45 No \n", + "4 Female 0 No No 2 Yes \n", + "\n", + " OnlineSecurity OnlineBackup DeviceProtection TechSupport StreamingTV \\\n", + "0 No Yes No No No \n", + "1 Yes No Yes No No \n", + "2 Yes Yes No No No \n", + "3 Yes No Yes Yes No \n", + "4 No No No No No \n", + "\n", + " StreamingMovies Contract MonthlyCharges TotalCharges Churn \n", + "0 No Month-to-month 29.85 29.85 No \n", + "1 No One year 56.95 1889.5 No \n", + "2 No Month-to-month 53.85 108.15 Yes \n", + "3 No One year 42.30 1840.75 No \n", + "4 No Month-to-month 70.70 151.65 Yes " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "churnData = pd.read_csv('Customer-Churn.csv')\n", + "churnData.head()" + ] + }, + { + "cell_type": "markdown", + "id": "58516276", + "metadata": {}, + "source": [ + "3.) Check the datatypes of all the columns in the data. You would see that the column TotalCharges is object type. Convert this column into numeric type using pd.to_numeric function." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a293b997", + "metadata": {}, + "outputs": [], + "source": [ + "def get_started(data): \n", + " data.columns = [column.lower().replace(' ', '_').replace('#_','') for column in data.columns]\n", + " print(\"shape dataframe: \", data.shape, data.info())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "414bf65f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 7043 entries, 0 to 7042\n", + "Data columns (total 16 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 gender 7043 non-null object \n", + " 1 seniorcitizen 7043 non-null int64 \n", + " 2 partner 7043 non-null object \n", + " 3 dependents 7043 non-null object \n", + " 4 tenure 7043 non-null int64 \n", + " 5 phoneservice 7043 non-null object \n", + " 6 onlinesecurity 7043 non-null object \n", + " 7 onlinebackup 7043 non-null object \n", + " 8 deviceprotection 7043 non-null object \n", + " 9 techsupport 7043 non-null object \n", + " 10 streamingtv 7043 non-null object \n", + " 11 streamingmovies 7043 non-null object \n", + " 12 contract 7043 non-null object \n", + " 13 monthlycharges 7043 non-null float64\n", + " 14 totalcharges 7043 non-null object \n", + " 15 churn 7043 non-null object \n", + "dtypes: float64(1), int64(2), object(13)\n", + "memory usage: 880.5+ KB\n", + "shape dataframe: (7043, 16) None\n" + ] + } + ], + "source": [ + "get_started(churnData)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f79b152f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['gender', 'seniorcitizen', 'partner', 'dependents', 'tenure',\n", + " 'phoneservice', 'onlinesecurity', 'onlinebackup', 'deviceprotection',\n", + " 'techsupport', 'streamingtv', 'streamingmovies', 'contract',\n", + " 'monthlycharges', 'totalcharges', 'churn'],\n", + " dtype='object')" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "churnData.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "ae7f29eb", + "metadata": {}, + "outputs": [], + "source": [ + "churnData[\"totalcharges\"] = pd.to_numeric(churnData[\"totalcharges\"], errors='raise')" + ] + }, + { + "cell_type": "markdown", + "id": "a6fb09bc", + "metadata": {}, + "source": [ + "4.) Check for null values in the dataframe. Replace the null values." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "4705f339", + "metadata": {}, + "outputs": [], + "source": [ + "def percantage_null(data):\n", + " nulls = pd.DataFrame(data.isna().sum()*100/len(data), columns=['percentage'])\n", + " print(nulls.sort_values('percentage', ascending = False))" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "76b89ae3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " percentage\n", + "totalcharges 0.156183\n", + "gender 0.000000\n", + "seniorcitizen 0.000000\n", + "partner 0.000000\n", + "dependents 0.000000\n", + "tenure 0.000000\n", + "phoneservice 0.000000\n", + "onlinesecurity 0.000000\n", + "onlinebackup 0.000000\n", + "deviceprotection 0.000000\n", + "techsupport 0.000000\n", + "streamingtv 0.000000\n", + "streamingmovies 0.000000\n", + "contract 0.000000\n", + "monthlycharges 0.000000\n", + "churn 0.000000\n" + ] + } + ], + "source": [ + "percantage_null(churnData)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "88c91f54", + "metadata": {}, + "outputs": [], + "source": [ + "def replace_by_mean(data, columns = []):\n", + " for i in columns:\n", + " data[i].fillna(data[i].mean(), inplace = True)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "738fb927", + "metadata": {}, + "outputs": [], + "source": [ + "replace_by_mean(churnData, columns = [\"totalcharges\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "83a062a7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " percentage\n", + "gender 0.0\n", + "seniorcitizen 0.0\n", + "partner 0.0\n", + "dependents 0.0\n", + "tenure 0.0\n", + "phoneservice 0.0\n", + "onlinesecurity 0.0\n", + "onlinebackup 0.0\n", + "deviceprotection 0.0\n", + "techsupport 0.0\n", + "streamingtv 0.0\n", + "streamingmovies 0.0\n", + "contract 0.0\n", + "monthlycharges 0.0\n", + "totalcharges 0.0\n", + "churn 0.0\n" + ] + } + ], + "source": [ + "percantage_null(churnData)" + ] + }, + { + "cell_type": "markdown", + "id": "3fbfaeb5", + "metadata": {}, + "source": [ + "5.) Use the following features: tenure, SeniorCitizen, MonthlyCharges and TotalCharges:\n", + "- Scale the features either by using normalizer or a standard scaler.\n", + "- Split the data into a training set and a test set.\n", + "- Fit a logistic regression model on the training data.\n", + "- Check the accuracy on the test data." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "00f31375", + "metadata": {}, + "outputs": [], + "source": [ + "X = churnData[['seniorcitizen', 'tenure', 'monthlycharges', 'totalcharges']]\n", + "y = churnData['churn']" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "3753e689", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(7043, 4)" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "transformer = Normalizer() \n", + "transformer.fit(X)\n", + "x_normalized = transformer.transform(X)\n", + "x_normalized.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "9d262bc1", + "metadata": {}, + "outputs": [], + "source": [ + "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "945e196c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " precision recall f1-score support\n", + "\n", + " No 0.82 0.90 0.86 1025\n", + " Yes 0.64 0.46 0.54 384\n", + "\n", + " accuracy 0.78 1409\n", + " macro avg 0.73 0.68 0.70 1409\n", + "weighted avg 0.77 0.78 0.77 1409\n", + "\n" + ] + } + ], + "source": [ + "model = LogisticRegression()\n", + "model.fit(X_train,y_train)\n", + "preds = model.predict(X_test)\n", + "print(classification_report(y_test, preds))" + ] + }, + { + "cell_type": "markdown", + "id": "8bab8c90", + "metadata": {}, + "source": [ + "## Managing imbalance in the dataset" + ] + }, + { + "cell_type": "markdown", + "id": "19b512f1", + "metadata": {}, + "source": [ + "6.) Check for the imbalance." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "fe04e1c1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "No 5174\n", + "Yes 1869\n", + "Name: churn, dtype: int64" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y.value_counts()" + ] + }, + { + "cell_type": "markdown", + "id": "bd277168", + "metadata": {}, + "source": [ + "Targetcolumn is imbalanced. " + ] + }, + { + "cell_type": "markdown", + "id": "1e32be72", + "metadata": {}, + "source": [ + "7.) Use the resampling strategies used in class for upsampling and downsampling to create a balance between the two classes.\n", + "Each time fit the model and see how the accuracy of the model is." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "f73691a5", + "metadata": {}, + "outputs": [], + "source": [ + "from imblearn.over_sampling import SMOTE\n", + "from imblearn.under_sampling import TomekLinks" + ] + }, + { + "cell_type": "markdown", + "id": "9f101815", + "metadata": {}, + "source": [ + "7.1.) Upsampling with smote" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "73ce4f5a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Yes 5174\n", + "No 5174\n", + "Name: churn, dtype: int64" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "smote = SMOTE()\n", + "X_sm, y_sm = smote.fit_resample(X, y)\n", + "y_sm.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "517b6147", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " precision recall f1-score support\n", + "\n", + " No 0.74 0.73 0.73 1052\n", + " Yes 0.72 0.73 0.73 1018\n", + "\n", + " accuracy 0.73 2070\n", + " macro avg 0.73 0.73 0.73 2070\n", + "weighted avg 0.73 0.73 0.73 2070\n", + "\n" + ] + } + ], + "source": [ + "X_train, X_test, y_train, y_test = train_test_split(X_sm, y_sm, test_size=0.2, random_state=100)\n", + "\n", + "model = LogisticRegression()\n", + "model.fit(X_train,y_train)\n", + "preds = model.predict(X_test)\n", + "print(classification_report(y_test, preds))" + ] + }, + { + "cell_type": "markdown", + "id": "ba0d4f67", + "metadata": {}, + "source": [ + "Prediction on Yes much better than imbalanced data (recall before: 0.49)" + ] + }, + { + "cell_type": "markdown", + "id": "4c0fc008", + "metadata": {}, + "source": [ + "7.2.) Downsampling with tomeklinks" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "354cd206", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "No 4620\n", + "Yes 1869\n", + "Name: churn, dtype: int64" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tomek = TomekLinks()\n", + "X_tl, y_tl = tomek.fit_resample(X, y)\n", + "y_tl.value_counts()" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "50766482", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " precision recall f1-score support\n", + "\n", + " No 0.83 0.90 0.86 891\n", + " Yes 0.73 0.59 0.65 407\n", + "\n", + " accuracy 0.80 1298\n", + " macro avg 0.78 0.74 0.76 1298\n", + "weighted avg 0.80 0.80 0.80 1298\n", + "\n" + ] + } + ], + "source": [ + "X_train, X_test, y_train, y_test = train_test_split(X_tl, y_tl, test_size=0.2, random_state=100)\n", + "\n", + "model = LogisticRegression()\n", + "model.fit(X_train,y_train)\n", + "preds = model.predict(X_test)\n", + "print(classification_report(y_test, preds))" + ] + }, + { + "cell_type": "markdown", + "id": "31c7adb8", + "metadata": {}, + "source": [ + "Prediction on Yes a little bit better than imbalanced data (recall before: 0.49)" + ] + } + ], + "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.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}