Customer churn presents a critical challenge in the modern banking industry, where increasing competition and evolving customer expectations place substantial pressure on financial institutions to retain their client base. Churn, defined as the cessation of a customer’s relationship with a bank, directly affects long-term profitability and growth. Research indicates that acquiring a new customer can cost up to five times more than retaining an existing one, making churn prediction and prevention a key strategic priority.
This project addresses the churn problem using a dataset containing 10,000 records and 14+ customer attributes, including sociodemographic details (such as age, gender, and geography), financial indicators (like credit score, balance, and salary), and behavioral metrics (such as product usage, tenure, and membership status). The dataset,offers a comprehensive view of customer behavior and is well-suited for predictive modeling and risk classification.
The analysis begins with data cleaning and preprocessing, including handling missing values, feature encoding, and scaling. Exploratory Data Analysis (EDA) is conducted to uncover patterns, trends, and correlations that influence churn behavior. A logistic regression model is then applied to predict the churn probability of each customer, and customers are categorized into High, Medium, and Low risk groups based on these probabilities.
To develop a data-driven churn prediction system that classifies banking customers into High, Medium, and Low risk categories using a logistic regression model. This classification will support targeted customer retention strategies by estimating churn probabilities and prioritizing outreach efforts.
Load Libraries
library(dplyr) library(caret) library(pROC) library(ggplot2)
Library(dplyr)
Data manipulation and wrangling
dplyr is part of the tidyverse and provides fast, readable functions to filter, select, mutate, summarize, and group data.
In this project, it’s used to clean and transform the dataset, such as filtering rows, creating new columns, or summarizing churn rates by customer features.
Library(caret)
Classification and Regression Training
caret stands for Classification And Regression Training, and it’s a unified framework for building and evaluating machine learning models.
In churn prediction, it helps to split data, perform cross-validation, and train the logistic regression model.
Library(pROC)
Classification and Regression Training
ROC curve plotting and AUC evaluation
pROC is used to evaluate binary classification performance (like churn: yes/no) by plotting ROC (Receiver Operating Characteristic) curves and calculating AUC (Area Under Curve).
It helps measure how well the model distinguishes between churned and retained customers.
Library(ggplot2)
Data visualization
ggplot2 is the most widely used plotting system in R and is essential for creating clean, customizable visualizations.
It is used to plot churn probability trends, feature distributions, and model performance charts.
data <- read.csv("C:/R/Bank Customer Churn Prediction.csv", sep=",")
data$churn <- as.factor(data$churn)
data <- read.csv() : Loads the Bank Customer Churn dataset from local machine into R as a data frame using a comma as the separator.
data$\(churn <- as.factor(data\)churn) : Converts the churn column into a factor so it can be treated as a categorical variable for classification of logistic regression modeling .
4.2 Summary Statistics and Missing Value Check
summary(data) colSums(is.na(data))
summary(data): Displays summary statistics for each column to understand data distribution and detect anomalies.
colSums(is.na(data)): Counts missing values in each column to identify data quality issues.
5.1 Split Data into Train and Test Sets (70-30)
set.seed(123) train_index <- createDataPartition(data$churn, p = 0.7, list = FALSE) train_data <- data[train_index, ] test_data <- data[-train_index, ]
set.seed(123): Sets a seed to ensure reproducibility of random operations.
train_index <- createDataPartition(data$churn, p = 0.7, list = FALSE): Creates a random 70% sample of row indices from the churn column while maintaining class proportions.
train_data <- data[train_index, ]: Extracts the training set (70% of data) using the sampled indices.
test_data <- data[-train_index, ]: Extracts the remaining 30% of data as the test set.
5.2 Build Logistic Regression Model
model <- glm(churn ~ credit_score + balance + tenure + age + gender,
data = train_data,
family = binomial)
summary(model)
model <- glm(): Builds a logistic regression model to predict churn using selected features (credit_score, balance, tenure, age, and gender) from the training data.
glm(): Fits a generalized linear model; here, it’s a logistic regression because family = binomial.
churn ~ credit_score + balance + tenure + age + gender: The model uses these five predictors to estimate the probability that a customer will churn.
data = train_data: The model is trained on the train_data subset.
family = binomial: Specifies that this is a binary classification model (logistic regression), suitable for predicting probabilities of churn (0 or 1).
summary(model): Displays detailed model output, including coefficients, significance levels (p-values), and model fit statistics, helping assess how well predictors explain churn.
test_predictions_prob <- predict(model, test_data, type = "response")
roc_curve <- roc(test_data$churn, test_predictions_prob)
auc_value <- auc(roc_curve)
cat("AUC:", round(auc_value, 4))
all_predictions_prob <- predict(model, data, type = "response")
data$Churn_Probability <- all_predictions_prob
test_predictions_prob <- predict(model, test_data, type = “response”): Predicts churn probabilities for the test dataset using the logistic regression model.
roc_curve <- roc(test_data$churn, test_predictions_prob): Generates the ROC curve by comparing actual churn values with predicted probabilities.
The ROC curve is a graph that shows the performance of a classification model at all classification thresholds.
It plots:
True Positive Rate (Sensitivity) on the Y-axis
False Positive Rate (1 – Specificity) on the X-axis
It helps understand how well model is at distinguishing between classes, like:
Churn (1) vs. Not Churn (0)
A good model will have a curve that bows toward the top-left corner, indicating high true positive and low false positive rates.
AUC stands for the area under the ROC curve.
It is a single number between 0 and 1 that summarizes the model’s ability to distinguish between classes:
AUC = 0.5 → No better than random guessing
AUC = 1.0 → Perfect classification
AUC > 0.8 → Generally considered good
Higher AUC = Better model performance in classifying churn vs. retention.
5.4 Creating Risk Categories
risk_category <- cut(all_predictions_prob, breaks = c(-1, 0.3, 0.7, 1),
labels = c("Low Risk", "Medium Risk", "High Risk"))
data$Risk_category <- risk_category
risk_category <- cut(all_predictions_prob, breaks = c(-1, 0.3, 0.7, 1), labels = c(“Low Risk”, “Medium Risk”, “High Risk”)): Categorizes churn probabilities into Low, Medium, and High risk using defined cutoff points.
data$Risk_category <- risk_category: Adds the risk categories as a new column (Risk_category) to the original dataset.
5.5 Adding Churn Status Columndata <- data %>% mutate(Churn_Status = ifelse(churn == 1, "Churned", "Retained"))
data <- data %>% mutate(Churn_Status = ifelse(churn == 1, “Churned”, “Retained”)): Adds a new column Churn_Status that labels each customer as “Churned” if churn == 1 or “Retained” if churn == 0.
5.6 Risk Category Summaryprint(table(risk_category)) prop.table(table(risk_category)) * 100
print(table(risk_category)): Displays the count of customers in each churn risk category (Low, Medium, High).
prop.table(table(risk_category)) 100: Calculates the percentage of customers in each risk category by converting counts to proportions and multiplying by 100.
5.7 Saving the Results
write.csv(data, "C:/R/customer_churn_predictions.csv", row.names = FALSE)
write.csv(data, “C:/R/customer_churn_predictions.csv”, row.names = FALSE): Saves the updated data (with predictions and risk categories) as a CSV file to the specified path without including row numbers.
png("risk_distribution.png", width = 800, height = 600)
ggplot(data, aes(x = risk_category, fill = risk_category)) +
geom_bar() +
labs(title = "Distribution of Customer Risk Categories",
x = "Risk Category",
y = "Number of Customers") +
theme_minimal() +
scale_fill_manual(values = c("Low Risk" = "green",
"Medium Risk" = "orange",
"High Risk" = "red"))
dev.off()
png("probability_distribution.png", width = 800, height = 600)
ggplot(data, aes(x = Churn_Probability)) +
geom_histogram(bins = 30, fill = "skyblue", alpha = 0.7) +
labs(title = "Distribution of Churn Probabilities",
x = "Churn Probability",
y = "Frequency") +
theme_minimal()
dev.off()
png("roc_curve.png", width = 800, height = 600)
plot(roc_curve, main = paste("ROC Curve (AUC =", round(auc_value, 3), ")"))
dev.off()
Customer churn prediction is a vital focus for banks aiming to enhance customer retention and safeguard profitability. This project utilized a logistic regression model to classify customers into High, Medium, and Low churn risk categories, based on demographic and behavioral attributes such as credit score, balance, age, tenure, and gender.
The dataset underwent essential preprocessing, including factor conversion, train-test splitting, and risk categorization based on predicted probabilities. The model was evaluated using ROC and AUC metrics, achieving an AUC score of 0.76, which indicates a moderately strong ability to distinguish between churned and retained customers.
Although logistic regression is a relatively simple model, its interpretability and stable performance make it a practical starting point for churn analysis. The AUC score suggests the model can support early identification of at-risk customers, guiding the design of proactive retention strategies.