InĀ [1]:
# Importing libraries
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report, accuracy_score, ConfusionMatrixDisplay, confusion_matrix, roc_curve, auc
import matplotlib.pyplot as plt
InĀ [2]:
# Read csv file into data variable
data = pd.read_csv('Telco-Customer-Churn.csv')

# Splitting the data into training and testing, using Churn as the label
train_df, test_df = train_test_split(
    data, 
    test_size=0.3, 
    stratify=data['Churn'])

# Displays the top rows of each new data set
display(train_df.head())
display(test_df.head())
customerID gender SeniorCitizen Partner Dependents tenure PhoneService MultipleLines InternetService OnlineSecurity ... DeviceProtection TechSupport StreamingTV StreamingMovies Contract PaperlessBilling PaymentMethod MonthlyCharges TotalCharges Churn
313 2799-ARNLO Female 1 Yes No 5 Yes No Fiber optic No ... No No No No Month-to-month Yes Electronic check 69.35 341.6 No
911 7508-SMHXL Female 1 No No 15 Yes Yes Fiber optic No ... No No Yes No Month-to-month No Credit card (automatic) 89.00 1288.3 No
5332 4565-EVZMJ Female 0 No No 47 Yes No DSL Yes ... No Yes No No One year Yes Mailed check 58.90 2813.05 No
4062 1915-IOFGU Female 0 No No 1 Yes No Fiber optic No ... No No No No Month-to-month No Electronic check 70.50 70.5 Yes
2629 5028-GZLDO Male 0 No No 2 Yes No Fiber optic No ... No No No No Month-to-month No Credit card (automatic) 70.70 140.7 Yes

5 rows Ɨ 21 columns

customerID gender SeniorCitizen Partner Dependents tenure PhoneService MultipleLines InternetService OnlineSecurity ... DeviceProtection TechSupport StreamingTV StreamingMovies Contract PaperlessBilling PaymentMethod MonthlyCharges TotalCharges Churn
1281 9531-NSBMR Female 0 No No 36 Yes No No No internet service ... No internet service No internet service No internet service No internet service One year Yes Bank transfer (automatic) 19.25 679.8 No
3159 5150-ITWWB Male 1 No No 3 Yes Yes Fiber optic No ... No No Yes Yes Month-to-month Yes Electronic check 94.85 335.75 No
7024 7398-LXGYX Male 0 Yes No 44 Yes Yes Fiber optic Yes ... Yes No No No Month-to-month Yes Credit card (automatic) 84.80 3626.35 No
3110 6569-KTMDU Female 0 No No 1 Yes No No No internet service ... No internet service No internet service No internet service No internet service Month-to-month No Mailed check 19.10 19.1 No
1067 7030-NJVDP Male 0 Yes No 24 Yes No Fiber optic Yes ... No Yes No Yes Month-to-month Yes Electronic check 89.25 2210.2 No

5 rows Ɨ 21 columns

InĀ [3]:
# Handle missing values
train_df.fillna(value=0, inplace=True)
test_df.fillna(value=0, inplace=True)

# Check missing values have been handled
display("Training set columns:")
display(train_df.isnull().sum())
display("Testing set columns:")
display(test_df.isnull().sum())
'Training set columns:'
customerID          0
gender              0
SeniorCitizen       0
Partner             0
Dependents          0
tenure              0
PhoneService        0
MultipleLines       0
InternetService     0
OnlineSecurity      0
OnlineBackup        0
DeviceProtection    0
TechSupport         0
StreamingTV         0
StreamingMovies     0
Contract            0
PaperlessBilling    0
PaymentMethod       0
MonthlyCharges      0
TotalCharges        0
Churn               0
dtype: int64
'Testing set columns:'
customerID          0
gender              0
SeniorCitizen       0
Partner             0
Dependents          0
tenure              0
PhoneService        0
MultipleLines       0
InternetService     0
OnlineSecurity      0
OnlineBackup        0
DeviceProtection    0
TechSupport         0
StreamingTV         0
StreamingMovies     0
Contract            0
PaperlessBilling    0
PaymentMethod       0
MonthlyCharges      0
TotalCharges        0
Churn               0
dtype: int64
InĀ [4]:
#https://www.geeksforgeeks.org/machine-learning/label-encoding-across-multiple-columns-in-scikit-learn/

# Columns to encode (change to numerical values)
columns_to_encode = ['Churn', 'gender', 'Partner', 'Dependents', 'PhoneService', 'PaperlessBilling', 'MultipleLines', 'InternetService', 'OnlineSecurity',
            'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies', 'Contract', 'PaymentMethod']

# for loop to work through each column and display the object to integer conversions
for column in columns_to_encode:
    label_encoder = LabelEncoder()
    train_df[column] = label_encoder.fit_transform(train_df[column])
    test_df[column] = label_encoder.transform(test_df[column])
    print(column, list(zip(label_encoder.classes_, label_encoder.transform(label_encoder.classes_))))


# display updated training and testing data sets
display(train_df.head())
display(test_df.head())
Churn [('No', 0), ('Yes', 1)]
gender [('Female', 0), ('Male', 1)]
Partner [('No', 0), ('Yes', 1)]
Dependents [('No', 0), ('Yes', 1)]
PhoneService [('No', 0), ('Yes', 1)]
PaperlessBilling [('No', 0), ('Yes', 1)]
MultipleLines [('No', 0), ('No phone service', 1), ('Yes', 2)]
InternetService [('DSL', 0), ('Fiber optic', 1), ('No', 2)]
OnlineSecurity [('No', 0), ('No internet service', 1), ('Yes', 2)]
OnlineBackup [('No', 0), ('No internet service', 1), ('Yes', 2)]
DeviceProtection [('No', 0), ('No internet service', 1), ('Yes', 2)]
TechSupport [('No', 0), ('No internet service', 1), ('Yes', 2)]
StreamingTV [('No', 0), ('No internet service', 1), ('Yes', 2)]
StreamingMovies [('No', 0), ('No internet service', 1), ('Yes', 2)]
Contract [('Month-to-month', 0), ('One year', 1), ('Two year', 2)]
PaymentMethod [('Bank transfer (automatic)', 0), ('Credit card (automatic)', 1), ('Electronic check', 2), ('Mailed check', 3)]
customerID gender SeniorCitizen Partner Dependents tenure PhoneService MultipleLines InternetService OnlineSecurity ... DeviceProtection TechSupport StreamingTV StreamingMovies Contract PaperlessBilling PaymentMethod MonthlyCharges TotalCharges Churn
313 2799-ARNLO 0 1 1 0 5 1 0 1 0 ... 0 0 0 0 0 1 2 69.35 341.6 0
911 7508-SMHXL 0 1 0 0 15 1 2 1 0 ... 0 0 2 0 0 0 1 89.00 1288.3 0
5332 4565-EVZMJ 0 0 0 0 47 1 0 0 2 ... 0 2 0 0 1 1 3 58.90 2813.05 0
4062 1915-IOFGU 0 0 0 0 1 1 0 1 0 ... 0 0 0 0 0 0 2 70.50 70.5 1
2629 5028-GZLDO 1 0 0 0 2 1 0 1 0 ... 0 0 0 0 0 0 1 70.70 140.7 1

5 rows Ɨ 21 columns

customerID gender SeniorCitizen Partner Dependents tenure PhoneService MultipleLines InternetService OnlineSecurity ... DeviceProtection TechSupport StreamingTV StreamingMovies Contract PaperlessBilling PaymentMethod MonthlyCharges TotalCharges Churn
1281 9531-NSBMR 0 0 0 0 36 1 0 2 1 ... 1 1 1 1 1 1 0 19.25 679.8 0
3159 5150-ITWWB 1 1 0 0 3 1 2 1 0 ... 0 0 2 2 0 1 2 94.85 335.75 0
7024 7398-LXGYX 1 0 1 0 44 1 2 1 2 ... 2 0 0 0 0 1 1 84.80 3626.35 0
3110 6569-KTMDU 0 0 0 0 1 1 0 2 1 ... 1 1 1 1 0 0 3 19.10 19.1 0
1067 7030-NJVDP 1 0 1 0 24 1 0 1 2 ... 0 2 0 2 0 1 2 89.25 2210.2 0

5 rows Ɨ 21 columns

InĀ [5]:
# Set features and target (x and y axis) for training data
x_train = train_df.drop(['Churn', 'customerID', 'TotalCharges', 'MonthlyCharges'], axis=1)  
y_train = train_df['Churn']

# Set features and target (x and y axis) for testing data
x_test = test_df.drop(['Churn', 'customerID',  'TotalCharges', 'MonthlyCharges'], axis=1)
y_test = test_df['Churn']
InĀ [6]:
# Logistic Regression Hyperparameters
lr_model = LogisticRegression(max_iter=1000)


lr_parameters = {
    'C': [0.01, 0.1, 1, 10],
    'penalty': ['l2'], 
    'solver': ['liblinear', 'lbfgs', 'saga'],
    'class_weight': [None, 'balanced']
}

lr_grid = GridSearchCV(lr_model, param_grid=lr_parameters, scoring='accuracy')

lr_grid.fit(x_train, y_train)
print("Best Logistic Regression Parameters:", lr_grid.best_params_)
Best Logistic Regression Parameters: {'C': 0.1, 'class_weight': None, 'penalty': 'l2', 'solver': 'liblinear'}
InĀ [7]:
# SVM Hyperparameters
# https://www.geeksforgeeks.org/machine-learning/svm-hyperparameter-tuning-using-gridsearchcv-ml/
"""
#commented out due to the length of time taken to execute

svm_model = SVC(probability=True)

svm_parameters = [
    {'kernel': ['linear'], 'C': [0.01, 0.1, 1, 10]},
    {'kernel': ['rbf', 'poly'], 'C': [0.01, 0.1, 1, 10], 
     'gamma': [1, 0.1, 0.01, 0.001]}
]

svm_grid = GridSearchCV(svm_model, param_grid=svm_parameters, scoring='accuracy', n_jobs=-1) 

svm_grid.fit(x_train, y_train)
print("Best SVM Params:", svm_grid.best_params_)

"""

svm_model = SVC(probability=True, kernel='linear', C=10)
svm_model.fit(x_train, y_train)
Out[7]:
SVC(C=10, kernel='linear', probability=True)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
SVC(C=10, kernel='linear', probability=True)
InĀ [8]:
# LR predict test data using best parameters identified
best_lr = lr_grid.best_estimator_
y_lr_pred = best_lr.predict(x_test)

print("Logistic Regression Model Accuracy Score:", accuracy_score(y_test, y_lr_pred))
print(classification_report(y_test, y_lr_pred))

# SVM predict test data using best parameters identified
y_svm_pred = svm_model.predict(x_test)

print("SVM Model Accuracy Score:", accuracy_score(y_test, y_svm_pred))
print(classification_report(y_test, y_svm_pred))
Logistic Regression Model Accuracy Score: 0.8012304779933743
              precision    recall  f1-score   support

           0       0.83      0.92      0.87      1552
           1       0.68      0.47      0.56       561

    accuracy                           0.80      2113
   macro avg       0.76      0.69      0.71      2113
weighted avg       0.79      0.80      0.79      2113

SVM Model Accuracy Score: 0.79649787032655
              precision    recall  f1-score   support

           0       0.82      0.92      0.87      1552
           1       0.67      0.46      0.54       561

    accuracy                           0.80      2113
   macro avg       0.75      0.69      0.71      2113
weighted avg       0.78      0.80      0.78      2113

InĀ [9]:
# https://www.geeksforgeeks.org/machine-learning/confusion-matrix-machine-learning/
# confusion matrix for LR model

cm = confusion_matrix(y_test, y_lr_pred, labels=[0, 1])
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=['0 - No', '1 - Yes'])
disp.plot(cmap=plt.cm.Blues)
plt.title('Confusion Matrix for LR where Customer Churn is Predicted', fontsize=15, pad=20)
plt.xlabel('Predicted values')
plt.ylabel('Actual values')
plt.show()

# confusion matrix SVM model
cm = confusion_matrix(y_test, y_svm_pred, labels=[0, 1])
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=['0 - No', '1 - Yes'])
disp.plot(cmap=plt.cm.Blues)
plt.title('Confusion Matrix for SVM where Customer Churn is Predicted', fontsize=15, pad=20)
plt.xlabel('Predicted values')
plt.ylabel('Actual values')
plt.show()
No description has been provided for this image
No description has been provided for this image
InĀ [10]:
# plot auc roc curve
# https://www.geeksforgeeks.org/machine-learning/auc-roc-curve/

y_lr_pred = best_lr.predict_proba(x_test)[:, 1]
y_svm_pred = svm_model.predict_proba(x_test)[:, 1]

test_df = pd.DataFrame(
    {'True': y_test, 'LR': y_lr_pred, 'SVM': y_svm_pred})

plt.figure(figsize=(7, 5))

for model in ['LR', 'SVM']:
    fpr, tpr, _ = roc_curve(test_df['True'], test_df[model])
    roc_auc = auc(fpr, tpr)
    plt.plot(fpr, tpr, label=f'{model} (AUC = {roc_auc:.2f})')

plt.plot([0, 1], [0, 1], 'r--', label='Random Guess')

plt.xlabel('False Positive')
plt.ylabel('True Positive')
plt.title('ROC Curve Graph for LR and SVM Model')
plt.legend()
plt.show()
No description has been provided for this image