In [ ]:
import pandas as pd
data = pd.read_excel("Telco_customer_churn.xlsx")
print(data.head())
In [ ]:
# Look for any missing values
data.isna().sum()
In [ ]:
del data['Churn Reason']
In [ ]:
print(data.columns)
In [ ]:
# Show data types
data.dtypes
In [ ]:
del data['State']
del data['Country']
del data['City']
In [ ]:
print(data.columns)
In [ ]:
del data['Zip Code']
del data['Lat Long']
del data['Latitude']
del data['Longitude']
In [ ]:
print(data.columns)
In [ ]:
data['Total Charges'] = data['Total Charges'].astype(str).str.strip() # Rmove any spaces from total charges
data['Total Charges'] = pd.to_numeric(data['Total Charges'], errors='coerce') # Change Total Charges to numeric 

print(f"The data type for total charges has been changed to: {data['Total Charges'].dtype}")
In [ ]:
print(data.dtypes)
In [ ]:
# Convert no feature to 0 for the following columns
convert_feature_columns = ['Multiple Lines', 'Online Security', 'Online Backup', 'Device Protection', 'Tech Support', 'Streaming TV', 'Streaming Movies']

# Change no feature to 0 and yes to 1 using .replace [1]
data[convert_feature_columns] = data[convert_feature_columns].replace({'Yes': 1, 'No': 0,
                                                                       'No IPS': 0,
                                                                       'No phone': 0}).astype(int)

print("The following feature columns have been updated:")
print(data[convert_feature_columns].sample(10)) # Display 10 random rows
In [ ]:
# Convert no feature to 0 for the following columns
convert_feature_columns = ['Multiple Lines', 'Online Security', 'Online Backup', 'Device Protection', 'Tech Support', 'Streaming TV', 'Streaming Movies']

# Change no feature to 0 and yes to 1 using .replace [1]
data[convert_feature_columns] = data[convert_feature_columns].replace({'Yes': 1, 'No': 0,
                                                                       'No internet service': 0,
                                                                       'No phone service': 0}).astype(int)

print("The following feature columns have been updated:")
print(data[convert_feature_columns].sample(10)) # Display 10 random rows
In [ ]:
# Convert no feature to 0 for the following columns
convert_feature_columns = ['Multiple Lines', 'Online Security', 'Online Backup', 'Device Protection', 'Tech Support', 'Streaming TV', 'Streaming Movies']

# Change no feature to 0 and yes to 1 using .replace [1]
data[convert_feature_columns] = data[convert_feature_columns].replace({'Yes': 1, 'No': 0,
                                                                       'No internet service': 0,
                                                                       'No phone service': 0})
# Convert columns to numeric values
data[convert_feature_columns] = data[convert_feature_columns].astype(int)

print("The following feature columns have been updated:")
print(data[convert_feature_columns].sample(10)) # Display 10 random rows
In [ ]:
# Show all values for all text columns
for col in data.select_dtypes(include=['object']):
    print(f"{col}: {data[col].unique()}")
In [ ]:
# Display all columns with yes and no values
yes_no_columns = ['Senior Citizen', 'Partner', 'Dependents', 'Phone Service', 'Paperless Billing', 'Churn Label']

# Change yes to 1 and no to 0
data[yes_no_columns] = data[yes_no_columns].replace({'Yes': 1, 'No': 0})

print("The following columns have been updated:")
print(data[yes_no_columns].sample(10)) # Display 10 random rows
In [ ]:
# Display all columns with yes and no values
yes_no_columns = ['Senior Citizen', 'Partner', 'Dependents', 'Phone Service', 'Paperless Billing', 'Churn Label']

# Change yes to 1 and no to 0
data[yes_no_columns] = data[yes_no_columns].replace({'Yes': 1, 'No': 0})

#Convert to numeric type
data[yes_no_columns] = data[yes_no_columns].astype(int)

print("The following columns have been updated:")
print(data[yes_no_columns].sample(10)) # Display 10 random rows
In [ ]:
# Display unique values for text columns
text_values = {col: data[col].unique() for col in data.select_dtypes(include='object')}
print(text_values)
In [ ]:
# [2] Encode columns
encoded_columns = ['Internet Service', 'Contract', 'Payment Method', 'Multiple Lines'] 

data_encoded = pd.get_dummies(data, columns=encoded_columns, drop_first=True)

# Show the first 10 rows of the encoded data 
print("You have encoded the following columns:")
print(data_encoded.head(10)) 
In [ ]:
# Change True/Flase to 1/0
data_encoded = data_encoded.replace({True: 1, False: 0})

# Show the updated data (first 10 rows)
print("The following boolean values have been updated to 0 and 1:")
print(data_encoded.head(10))
In [ ]:
# Import scikit learn to split data 
from sklearn.model_selection import train_test_split

# Split data into features (input) and target (output)
features, target_label = data_encoded.drop(columns='Churn Value'), data_encoded['Churn Value']

# Split data so that 75% is for training and 15% is for testing 
train_features, test_features, train_labels, test_labels = train_test_split(
    features, target_label, test_size=0.25, shuffle=True, random_state=42
)

# Show the data sizes for training and testing
print(f"Training data shape: {train_features.shape}, {train_labels.shape}")
print(f"Testing data shape: {test_features.shape}, {test_labels.shape}")
In [ ]:
# delete churn label and score
train_features = train_features.drop(columns=['Churn Label', 'Churn Score'], errors='ignore')
test_features = test_features.drop(columns=['Churn Label', 'Churn Score'], errors='ignore')
#Display the columns now
print("Train features:", train_features.columns)
print("Test features:", test_features.columns)
In [ ]:
# Import logistic regression
from sklearn.linear_model import LogisticRegression as LogReg
In [ ]:
# Remove CustomerID
train_features = train_features.drop(columns=['CustomerID'], errors='ignore')
test_features = test_features.drop(columns=['CustomerID'], errors='ignore')
In [ ]:
# Chnage gender to 1 and 0 
train_features['Gender'] = train_features['Gender'].map({'Male':1, 'Female': 0})
test_features['Gender'] = test_features['Gender'].map({'Male':1, 'Female': 0})
In [ ]:
print("missing values:")
print(train_features.isna().sum())
In [ ]:
# Remove missing values from total charges 
train_features.dropna(subset=['Total Charges'], inplace=True)
test_features.dropna(subset=['Total Charges'], inplace=True)
In [ ]:
train_labels = train_labels.loc[train_features.index]
In [ ]:
print(f"train_features shape: {train_features.shape}")
print(f"train_labels shape: {train_labels.shape}")
In [ ]:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
train_scaled = scaler.fit_transform(train_features)
test_scaled = scaler.transform(test_features)

# Set up logistic regression for churn prediction 
churn_model = LogReg(max_iter=1500, random_state=42, class_weight="balanced")
churn_model.fit(train_scaled, train_labels)

print("Training is complete, the model is now ready")
In [ ]:
# Get predictions using the scaled test features 
predictions = churn_model.predict(test_scaled)

# DIsplay 15 predictions
print("Churn predictions:", predictions[:15])
In [ ]:
#Remove labels from test_labels
test_labels = test_labels.iloc[:test_features.shape[0]]

#Show the updated shapes
print(f"Test features shape: {test_features.shape}")
print(f"Test labels shape: {test_labels.shape}")
In [ ]:
# Import the following to evaluate the LR model's performance
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score

# Get predictions
predicted_labels = churn_model.predict(test_scaled)

# Get the probability of the customer churning 
predicted_probabilities = churn_model.predict_proba(test_scaled)[:, -1]

# Show model's performance
performance_results = {
    "Accuracy": accuracy_score(test_labels, predicted_labels),    #Total correct predictions
    "Precision": precision_score(test_labels, predicted_labels),           #Total predicted churn casesthat were actually churn
    "Recall": recall_score(test_labels, predicted_labels),           #How many actual churn cases the model identified  
    "F1 score": f1_score(test_labels, predicted_labels),              #Combo of precision and recall 
    "AUC-ROC": roc_auc_score(test_labels, predicted_probabilities),         #How well the model tells churners and non churners apart 
}

# Show performance results
print("Performance results:")
for metric, value in performance_results.items():
    print(f"{metric}: {value:.2f}")
In [ ]:
from sklearn.svm import SVC

# Set up SVM to predict the churn probability 
svm_churn_model = SVC(kernel="rbf", probability=True, random_state=42, class_weight="balanced")

# Train SVM using the training data
svm_churn_model.fit(train_scaled, train_labels)

print("SVM is ready to use!")
In [ ]:
# Import the following to evaluate the SVM model's performance
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score 

# Get predictions
svm_predictions = svm_churn_model.predict(test_scaled)

# Get the probability of the customer churning
svm_probabilities = svm_churn_model.predict_proba(test_scaled)[:, 1]

# Show model's performance
svm_performance = {
    "Accuracy": accuracy_score(test_labels, svm_predictions),    #Total correct predictions
    "Precision": precision_score(test_labels, svm_predictions),           #Total predicted churn casesthat were actually churn
    "Recall": recall_score(test_labels, svm_predictions),           #How many actual churn cases the model identified  
    "F1 score": f1_score(test_labels, svm_predictions),              #Combo of precision and recall 
    "AUC-ROC": roc_auc_score(test_labels, svm_probabilities),         #How well the model tells churners and non churners apart 
}

# Show performance results
print("Performance results:")
for metric, value in svm_performance.items():
    print(f"{metric}: {value:.2f}")
In [ ]:
# [3] Tune SVM
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC

# Hyperparameters that need testing
svm_hyperparameters = {
    'C': [0.01, 0.1, 1, 10, 100],
    'gamma': [0.001, 0.01, 0.1, 1],
    'kernel': ['rbf']
}

# Find the best SVM settings (run 5 times)
svm_tuner = GridSearchCV(SVC(probability=True, random_state=42), svm_hyperparameters, cv=5, scoring='accuracy', n_jobs=-1)

# Train SVM
svm_tuner.fit(train_scaled, train_labels)

#Store best settings and accuracy 
best_svm_settings = svm_tuner.best_params_
best_svm_accuracy = svm_tuner.best_score_

# Display the best SVM settings
print("The best SVM results:", best_svm_settings)
print(f"Best accuracy: {best_svm_accuracy:.2f}")
In [ ]:
tuned_svm = SVC(**best_svm_settings, probability=True, random_state=42)

#  Train the tuned model
tuned_svm.fit(train_scaled, train_labels)

print("The tuned SVM model is trained and ready to use")
In [ ]:
# Get predictions
tuned_svm_predictions = tuned_svm.predict(test_scaled)

# Get the probability of the customer churning
tuned_svm_probabilities = tuned_svm.predict_proba(test_scaled)[:, 1]

# Show model's performance
tuned_svm_performance = {
    "Accuracy": accuracy_score(test_labels, tuned_svm_predictions),    #Total correct predictions
    "Precision": precision_score(test_labels, tuned_svm_predictions),           #Total predicted churn casesthat were actually churn
    "Recall": recall_score(test_labels, tuned_svm_predictions),           #How many actual churn cases the model identified  
    "F1 score": f1_score(test_labels, tuned_svm_predictions),              #Combo of precision and recall 
    "AUC-ROC": roc_auc_score(test_labels, tuned_svm_probabilities),         #How well the model tells churners and non churners apart 
}

# Show performance results
print("Performance results for the tuned SVM model:")
for metric, value in tuned_svm_performance.items():
    print(f"{metric}: {value:.2f}")
In [ ]:
from sklearn.model_selection import GridSearchCV 
from sklearn.linear_model import LogisticRegression as LogReg

# Tune LR & define hyperparamters to test for LR
lr_hyperparameters = { 
    'C': [0.01, 0.1, 1, 10, 100], 
    'solver': ['liblinear', 'saga']
}

# Find the best LR settings (run 5 times)
lr_tuner = GridSearchCV(LogReg(random_state=42, max_iter=1500),
                        lr_hyperparameters, cv=5, scoring='accuracy', n_jobs=-1)

#Train LR
lr_tuner.fit(train_scaled, train_labels)

#Store best settings and accuracy
best_lr_settings = lr_tuner.best_params_
best_lr_accuracy = lr_tuner.best_score_

# Display the best LR settings and accuracy 
print("The best LR results:", best_lr_settings)
print(f"Best accuracy: {best_lr_accuracy:.2f}")



# Train the tuned LR model
tuned_lr = LogReg(**best_lr_settings, random_state=42, max_iter=1500)  # Use best settings
tuned_lr.fit(train_scaled, train_labels)

print("The tuned LR model is now ready to use")

# Get predictions using the tuned LR model
tuned_lr_predictions = tuned_lr.predict(test_scaled)

# Get the probability of customer churning
tuned_lr_probabilities = tuned_lr.predict_proba(test_scaled)[:, 1]

# Evaluate the performance of the tuned Logistic Regression model
tuned_lr_performance = {
    "Accuracy": accuracy_score(test_labels, tuned_lr_predictions),
    "Precision": precision_score(test_labels, tuned_lr_predictions),
    "Recall": recall_score(test_labels, tuned_lr_predictions),
    "F1 score": f1_score(test_labels, tuned_lr_predictions),
    "AUC-ROC": roc_auc_score(test_labels, tuned_lr_probabilities)
}

# Show performance results for tuned LR
print("\nPerformance results for the tuned Logistic Regression model:")
for metric, value in tuned_lr_performance.items():
    print(f"{metric}: {value:.2f}")
In [ ]:
# Compare model's perfoamnce
models_performance = {
    "Logistic regression": performance_results, 
    "Tuned SVM": tuned_svm_performance
}

# Show the comparison 
print("Comparison between Logistic regression and Tuned SVM - ")
for model, scores in models_performance.items():
    print(f"\n{model}:")
    for metric, value in scores.items():
        print(f"{metric}: {value:.2f}")
In [ ]:
# Display how many churners and non churners are in the dataset
churn_total = target_label.value_counts(normalize=True).rename("percentage")
print("The amount of churners and non churners in the dataset:", churn_total)
In [ ]:
# Compare performance of both of the tuned models
models_performance = {
    "Tuned LR": tuned_lr_performance,
    "Tuned SVM": tuned_svm_performance
}

print("Comparison between Tuned LR and Tuned SVM:")
for model, scores in models_performance.items():
    print(f"\n{model}:")
    for metric, value in scores.items():
        print(f"{metric}: {value:.2f}")