Abstract
The ABC Multinational Bank client retention research team, or Harry Plotter and the Chamber of Refits, conducted an analysis of a large data set containing information on our clientele. The data set includes many different continuous and categorical variables, and whether or not a client “churned,” or left the bank. Why are some clients leaving ABC Multinational Bank while others are staying? The goal of this study is to identify key factors that influence customer churn and optimize predictive models that will aid in aswering that question. Our team constructed a linear regression, random forest, and a c5.0 boosted model. The c5.0 boosted model demonstrated the strongest predictive performance, achieving an accuracy of an accuracy of 84.7% and an AUC of 0.863 on the test set.
Harry Plotter and the Chamber of Refits assessed model performance using a variety of evaluation metrics such as AUC, model accuracy, MSE, and RMSE, along with comparisons of training and test results to evaluate generalization and stability. In addition to predictive performance, we also considered model interpretability when selecting our chamion model given its importance in banking applications. While logistic regression offered greater transparency, the boosted c5.0 model provided the best overall balance between performance and reliability. The resulting model provides a robust tool for identifying customers at risk of churn, which will ultimately aid in clientele retention, mitigate churn rates, and boost profits for the company.
| Variable | Description |
|---|---|
| customer_id | Account Number |
| credit_score | credit score |
| country | Name of the Country |
| gender | Female or Male |
| age | age |
| tenure | How many years as client |
| balance | Account Balance |
| products_number | Number of products of the Bank |
| credit_card | 0 – no, 1–yes |
| active_member | 0 – no, 1–yes |
| estimated_salary | Salary |
You may present the Project individually or join a team with your fellow students with appropriate size (Up to four Students total), if you need my help allocating you to a group let me know (rafael_gomeztagle@g.harvard.edu)
Load and Review the dataset named “Bank Customer Churn Prediction.csv”
Create a model development document that describes the model using this template, input the name of the authors, Harvard IDs, the name of the Group, all of your code and calculations, etc..:
Notes No typographical errors, grammar mistakes, or misspelled words, use English language All tables need to be numbered and describe their content in the body of the document All figures/graphs need to be numbered and describe their content All results must be accurate and clearly explained for a casual reviewer to fully understand their purpose and impact Submit both the RMD markdown file and PDF with the sections with appropriate explanations. A more formal document in Word can be used in place of the pdf file but must include all appropriate explanations.
This project developed a predictive model to identify customers at high risk of churning (i.e. changing banks) from ABC Multinational Bank, enabling proactive retention strategies such as personalized offers and improved customer engagement. Three classification models were trained and evaluated on a dataset of 10,000 customers: Logistic Regression, Boosted C5.0, and Random Forest. The Boosted C5.0 algorithm was selected as the champion model due to its superior performance, achieving an AUC of 0.863, F1 score of 0.689, and accuracy of 84.7% on the test set. Logistic Regression was retained as the benchmark for its interpretability: its odds ratios provide regulatory transparency. Key limitations include reduced explainability compared with Logistic Regression, sensitivity to class imbalance, and the model capturing patterns rather than causal relationships. Ongoing monthly monitoring using AUC and Population Stability Index is recommended to ensure continued effectiveness in deployment.
We at the ABC Multinational Bank are analyzing and interpreting a data set with information on 10,000 of our clients in hopes to better classify whether or not a customer is at high-risk of leaving the bank – and therefore losing us money. Through rigorous testing we have developed an optimized model to help apply targeted customer retention strategies before a loss of clientele. The data set we tested on contains information on demographics, account behavior, and product usage, including credit score, country (location of clientele), gender, age, tenure as a client, account balance, number of products of the regional Bank (products number), credit card ownership, active membership status, and estimated salary. Our model balances predictive accuracy, stability on the test sample (we used a 70%/30% training to testing sample split), and interpretability to output a “churn” value – a churn value of 1 indicates the client left ABC Multinational Bank during the observed period, while a value of 0 indicates successful clientele retention.
Our research team considered and compared multiple methods in order to find the most suitable model for predicting churn values. These included logistic regression, simple decision trees, and boosted decision trees.
The clientele information data set is very high quality and suitable for model training. There are no missing values nor any duplicated rows. The predictors include a mix of continuous and categorical variables. Credit score, age, tenure, products number, balance, and estimated salary are continuous, while country, gender, credit card ownership, and active member status are categorical. This means we had to construct dummy variables for the categorical variables in order to adequately build our model. However, prior to implementing our dummy variables, we performed diagnostic testing on the data set. Our findings were as follows:
The response variable churn is rather imbalanced, with 20.4% of clients leaving the bank, while 79.6% stayed (refer to Figure 1 below). This means when analyzing our model, accuracy alone may not be sufficient. In addition to accuracy, we evaluated model sensitivity and specificity, as well as the ROC curve and AUC. Several of the predictor variables show particularly meaningful differences when plotted against churn status. The distribution of age, as seen in Figure 2, is skewed right, with most clients being 25 to 40 years old. Figures 3 and 4 provide evidence that older clients, along with clients who have a higher account balance, are on average more likely to leave the ABC Multinational Bank. On top of age and account balance, gender has a noticeable impact on churn rates, with female clients having a higher probability of leaving the bank. France and Spain have virtually the same churn proportions (at 16% and 17% respectively), while Germany sees higher rates of clients leaving, with a 32% proportion. Figure 7 shows that the status of a member (either active or not) has a significant impact on churn rates. Active members are nearly half as likely to leave the bank (14% vs 27% for non-active members). Figure 8 informs us that estimated salary has a very minimal impact on churn probability. The final figure showing churn proportion by number of products reveals an interesting finding. All clients with a bank with four products churned, and a large majority (83%) of clients at a bank with three products churned as well. Banks with only two products seemed to perform the best, with a churn rate of only 7.6%. It is important to note, however, that only a small portion of the total data set represents banks with 3 or 4 products.
## credit_score age tenure balance
## Min. :350.0 Min. :18.00 Min. : 0.000 Min. : 0
## 1st Qu.:584.0 1st Qu.:32.00 1st Qu.: 3.000 1st Qu.: 0
## Median :652.0 Median :37.00 Median : 5.000 Median : 97199
## Mean :650.5 Mean :38.92 Mean : 5.013 Mean : 76486
## 3rd Qu.:718.0 3rd Qu.:44.00 3rd Qu.: 7.000 3rd Qu.:127644
## Max. :850.0 Max. :92.00 Max. :10.000 Max. :250898
## products_number estimated_salary churn credit_card_Yes
## Min. :1.00 Min. : 11.58 No :7963 Min. :0.0000
## 1st Qu.:1.00 1st Qu.: 51002.11 Yes:2037 1st Qu.:0.0000
## Median :1.00 Median :100193.91 Median :1.0000
## Mean :1.53 Mean :100090.24 Mean :0.7055
## 3rd Qu.:2.00 3rd Qu.:149388.25 3rd Qu.:1.0000
## Max. :4.00 Max. :199992.48 Max. :1.0000
## active_member_Yes country_Spain country_Germany gender_Male
## Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000
## Median :1.0000 Median :0.0000 Median :0.0000 Median :1.0000
## Mean :0.5151 Mean :0.2477 Mean :0.2509 Mean :0.5457
## 3rd Qu.:1.0000 3rd Qu.:0.0000 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :1.0000 Max. :1.0000 Max. :1.0000 Max. :1.0000
## [1] "Total Churn Values and Rates:"
##
## No Yes
## 7963 2037
##
## No Yes
## 0.7963 0.2037
## [1] "Churn Rates by Country:"
##
## No Yes
## France 0.8384523 0.1615477
## Spain 0.8332660 0.1667340
## Germany 0.6755680 0.3244320
## [1] "Churn Rates by Active Member Status:"
##
## No Yes
## No 0.7314910 0.2685090
## Yes 0.8573093 0.1426907
## [1] "Churn Rates and Total Values by Product Number:"
##
## No Yes
## 1 0.72285602 0.27714398
## 2 0.92418301 0.07581699
## 3 0.17293233 0.82706767
## 4 0.00000000 1.00000000
##
## No Yes
## 1 3675 1409
## 2 4242 348
## 3 46 220
## 4 0 60
## 'data.frame': 10000 obs. of 12 variables:
## $ credit_score : int 619 608 502 699 850 645 822 376 501 684 ...
## $ age : int 42 41 42 39 43 44 50 29 44 27 ...
## $ tenure : int 2 1 8 1 2 8 7 4 4 2 ...
## $ balance : num 0 83808 159661 0 125511 ...
## $ products_number : int 1 1 3 2 1 2 2 4 2 1 ...
## $ estimated_salary : num 101349 112543 113932 93827 79084 ...
## $ churn : Factor w/ 2 levels "No","Yes": 2 1 2 1 1 2 1 2 1 1 ...
## $ credit_card_Yes : int 1 0 1 0 1 1 1 1 0 1 ...
## $ active_member_Yes: int 1 1 0 0 1 0 1 0 1 1 ...
## $ country_Spain : int 0 1 0 0 1 1 0 0 0 0 ...
## $ country_Germany : int 0 0 0 0 0 0 0 1 0 0 ...
## $ gender_Male : int 0 0 0 0 0 1 1 0 1 1 ...
## Train split: 70.01 %
## Test split: 29.99 %
## Train churn rate: 20.37 %
## Test churn rate: 20.37 %
We chose a logistic regression model as our model due to the nature of our data. More specifically, we selected our model using stepwise AIC variable selection over the full logistic regression model due to better performance on certain metrics.
logit_full <- glm(churn ~ ., data=train, family="binomial")
summary(logit_full)
##
## Call:
## glm(formula = churn ~ ., family = "binomial", data = train)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -3.281e+00 2.943e-01 -11.147 < 2e-16 ***
## credit_score -9.176e-04 3.361e-04 -2.730 0.00633 **
## age 7.435e-02 3.110e-03 23.909 < 2e-16 ***
## tenure -1.312e-02 1.118e-02 -1.173 0.24069
## balance 3.446e-06 6.102e-07 5.647 1.63e-08 ***
## products_number -6.968e-02 5.648e-02 -1.234 0.21726
## estimated_salary -1.638e-07 5.613e-07 -0.292 0.77045
## credit_card_Yes -7.038e-02 7.081e-02 -0.994 0.32025
## active_member_Yes -1.090e+00 6.911e-02 -15.766 < 2e-16 ***
## country_Spain 1.527e-02 8.440e-02 0.181 0.85646
## country_Germany 7.040e-01 8.094e-02 8.697 < 2e-16 ***
## gender_Male -5.734e-01 6.534e-02 -8.775 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 7077.6 on 7000 degrees of freedom
## Residual deviance: 5969.4 on 6989 degrees of freedom
## AIC: 5993.4
##
## Number of Fisher Scoring iterations: 5
logit_step <- stepAIC(logit_full, direction="both", trace=FALSE)
summary(logit_step)
##
## Call:
## glm(formula = churn ~ credit_score + age + balance + active_member_Yes +
## country_Germany + gender_Male, family = "binomial", data = train)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -3.540e+00 2.586e-01 -13.692 < 2e-16 ***
## credit_score -9.058e-04 3.359e-04 -2.697 0.007 **
## age 7.451e-02 3.107e-03 23.984 < 2e-16 ***
## balance 3.669e-06 5.871e-07 6.249 4.12e-10 ***
## active_member_Yes -1.088e+00 6.904e-02 -15.758 < 2e-16 ***
## country_Germany 6.846e-01 7.530e-02 9.092 < 2e-16 ***
## gender_Male -5.733e-01 6.527e-02 -8.784 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 7077.6 on 7000 degrees of freedom
## Residual deviance: 5973.5 on 6994 degrees of freedom
## AIC: 5987.5
##
## Number of Fisher Scoring iterations: 5
The final stepwise logistic regression model retained credit_score, age, balance, active_member_Yes, country_Germany, and gender as predictors of churn. Age, balance, active membership, being located in Germany, and gender were significant at the 5% level. Older customers and customers with higher account balances exhibited higher odds of churn, while active members and male customers exhibited lower odds of churn. Customers located in Germany were significantly more likely to churn than customers in the reference country. The final model reduced deviance substantially relative to the null model, indicating that the retained predictors provide meaningful explanatory power. The model substantially improved fit relative to the intercept-only model, reducing deviance from 7077.6 to 5973.5.
# Compute odds ratios
exp(coef(logit_step))
## (Intercept) credit_score age balance
## 0.02900177 0.99909466 1.07735645 1.00000367
## active_member_Yes country_Germany gender_Male
## 0.33689204 1.98300666 0.56365751
# 95% CI for predictors
exp(confint(logit_step))
## Waiting for profiling to be done...
## 2.5 % 97.5 %
## (Intercept) 0.01742474 0.04802264
## credit_score 0.99843671 0.99975225
## age 1.07085671 1.08398010
## balance 1.00000252 1.00000482
## active_member_Yes 0.29401278 0.38541689
## country_Germany 1.71097025 2.29855579
## gender_Male 0.49583848 0.64043400
Odds-ratio analysis confirmed that age, balance, active membership status, customer location in Germany, and gender were key drivers of churn in the final logistic regression model (James et al. 2014). Each additional year of age increased churn odds by about 7.7%, while active members had about 66% lower odds of churn than inactive members. Customers in Germany had approximately 1.98 times the odds of churn relative to the reference country, and male customers had lower odds of churn than female customers. Higher balances were also associated with increased churn risk, although the effect is best interpreted over larger balance changes because balance is measured in small units. Credit score had a statistically significant but modest protective effect, whereas tenure and number of products were only marginally significant.
Compute VIF to check for multicollinearity:
vif(logit_step)
## credit_score age balance active_member_Yes
## 1.000811 1.085746 1.186767 1.079263
## country_Germany gender_Male
## 1.184501 1.003899
All VIF values are close to 1, with the highest value equal to 1.187 for balance. These results indicate no evidence of problematic multicollinearity, suggesting that the coefficient estimates are stable and interpretable (James et al. 2014).
First we will perform any metric calculations that are not dependent on a prediction threshold cutoff. We check the Brier score (MSE), RMSE, SSE as follows:
## Brier Score (MSE) RMSE SSE
## Probability Calibration Metrics 0.1350271 0.3674604 945.325
The logistic regression model had a Brier score of 0.135, which suggests that on average, the model’s predicted probabilities deviate from the true outcomes by a modest amount (n.d.). The corresponding RMSE of 0.367 also reflects moderate prediction error on the probability scale. The SSE was 945.325. However, this metric is scale-dependent and less informative than the two other metrics (James et al. 2014).
Compute the pseudo-\(R^2\):
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML
## -2986.7518470 -3538.7879986 1104.0723031 0.1559958 0.1458958
## r2CU
## 0.2293518
The final logistic regression model achieved a McFadden pseudo-\(R^2\) of 0.156, indicating a meaningful improvement in fit relative to the intercept-only model. Although pseudo-\(R^2\) values in logistic regression are not interpreted the same way as ordinary pseudo-\(R^2\) in linear regression, this result suggests that the selected predictors provide a moderate and useful level of explanatory power for customer churn (Long 1997).
Next, we perform a Hosmer-Lemeshow goodness-of-fit test:
Hypotheses: \[ H_0: \text{model fits the data well}\\ \] \[ H_a: \text{model does not fit the data well} \]
Decision rule: At the 5% significance level, if p < 0.05, then reject \(H_0\). Otherwise, fail to reject \(H_0\).
##
## Hosmer and Lemeshow goodness of fit (GOF) test
##
## data: actual_numeric, probs_logit
## X-squared = 9.9436, df = 8, p-value = 0.269
Conclusion: At the 5% significance level, since the p-value is greater than 0.05, we fail to reject \(H_0\). There is sufficient evidence to suggest the model fits the data well (Hosmer and Lemeshow 2000).
We first check the ROC curve and AUC (Fawcett 2006) before deciding which cutoff to choose:
## Setting direction: controls < cases
## Area under the curve: 0.7688
The model achieved an AUC of 0.7624, meaning that in approximately 76.24% of randomly selected churner versus non-churner pairs, the model assigns a higher predicted probability to the churner. This indicates moderate discriminatory ability. While the model provides useful separation between customers who churn and those who do not, its ranking performance is only fair to acceptable rather than strong.
Finally, we actually try predicting churns two options by introducing a decision rule cutoff(Kennedy 2024). To determine what cutoff seems best - and if deviating from the trivial choice 0.5 is useful at all - one may build a function for simulation purposes.
| Cutoff | TN | FP | FN | TP | Accuracy | Sensitivity | Specificity | Precision | Recall | F1 | Balanced_Accuracy |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0.50 | 5373 | 202 | 1115 | 311 | 0.8119 | 0.2181 | 0.9638 | 0.6062 | 0.2181 | 0.3208 | 0.5909 |
| 0.45 | 5276 | 299 | 1036 | 390 | 0.8093 | 0.2735 | 0.9464 | 0.5660 | 0.2735 | 0.3688 | 0.6099 |
| 0.40 | 5152 | 423 | 939 | 487 | 0.8055 | 0.3415 | 0.9241 | 0.5352 | 0.3415 | 0.4170 | 0.6328 |
| 0.35 | 4987 | 588 | 826 | 600 | 0.7980 | 0.4208 | 0.8945 | 0.5051 | 0.4208 | 0.4591 | 0.6576 |
| 0.30 | 4750 | 825 | 696 | 730 | 0.7827 | 0.5119 | 0.8520 | 0.4695 | 0.5119 | 0.4898 | 0.6820 |
Among the tested probability cutoffs, 0.35 provided the best overall balance between identifying churners and controlling false positives. While the 0.30 cutoff achieved the highest sensitivity, F1 score, and balanced accuracy, it also generated substantially more false positives and a lower precision rate. The 0.35 cutoff offered a stronger compromise, improving sensitivity meaningfully over 0.40 and 0.50 while maintaining better specificity and precision than 0.30. For this reason, 0.35 was selected as the final operational cutoff for the logistic regression model. Going forward, we will therefore only analyze that model:
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 4987 826
## Yes 588 600
##
## Accuracy : 0.798
## 95% CI : (0.7884, 0.8074)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 0.3674
##
## Kappa : 0.3362
##
## Mcnemar's Test P-Value : 2.926e-10
##
## Precision : 0.5051
## Recall : 0.4208
## F1 : 0.4591
## Prevalence : 0.2037
## Detection Rate : 0.0857
## Detection Prevalence : 0.1697
## Balanced Accuracy : 0.6576
##
## 'Positive' Class : Yes
##
| Metric | Logistic Regression (0.35 cutoff) |
|---|---|
| TN | 4987 |
| FP | 588 |
| FN | 826 |
| TP | 600 |
| Accuracy | 0.7980 |
| Kappa | 0.3362 |
| Sensitivity | 0.4208 |
| Specificity | 0.8945 |
| Precision | 0.5051 |
| Recall | 0.4208 |
| F1 | 0.4591 |
| NPV | 0.8579 |
| Prevalence | 0.2037 |
| Detection Rate | 0.0857 |
| Detection Prevalence | 0.1697 |
| Balanced Accuracy | 0.6576 |
| AUC | 0.7688 |
| SSE | 945.3250 |
| RMSE | 0.3675 |
On the train set, our stepwise selected logistic regression model achieved an accuracy of 79.4%, which is very close to the no information rate of 78.97%. This reflects the class imbalance. While precision (50.5%) and recall (42.1%) indicate moderate ability in identifying churners, the relatively low F1 score (45.9%) and balanced accuracy (65.8%) suggest the model performs better at identifying non-churners than it does for churners. Overall, our model demonstrates moderate in-sample performance.
## Setting direction: controls < cases
## Area under the curve: 0.7624
The model achieved an AUC of 0.7624, meaning that in approximately 76.24% of randomly selected churner versus non-churner pairs, the model assigns a higher predicted probability to the churner (Fawcett 2006). This indicates moderate discriminatory ability. While the model provides useful separation between customers who churn and those who do not, its ranking performance is only fair to acceptable rather than strong.
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 2119 345
## Yes 269 266
##
## Accuracy : 0.7953
## 95% CI : (0.7804, 0.8096)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 0.564755
##
## Kappa : 0.3384
##
## Mcnemar's Test P-Value : 0.002472
##
## Precision : 0.4972
## Recall : 0.4354
## F1 : 0.4642
## Prevalence : 0.2037
## Detection Rate : 0.0887
## Detection Prevalence : 0.1784
## Balanced Accuracy : 0.6614
##
## 'Positive' Class : Yes
##
| Metric | Logistic Regression (0.35 cutoff) |
|---|---|
| TN | 2119 |
| FP | 269 |
| FN | 345 |
| TP | 266 |
| Accuracy | 0.7953 |
| Kappa | 0.3384 |
| Sensitivity | 0.4354 |
| Specificity | 0.8874 |
| Precision | 0.4972 |
| Recall | 0.4354 |
| F1 | 0.4642 |
| NPV | 0.8600 |
| Prevalence | 0.2037 |
| Detection Rate | 0.0887 |
| Detection Prevalence | 0.1784 |
| Balanced Accuracy | 0.6614 |
| AUC | 0.7624 |
| SSE | 413.8020 |
| RMSE | 0.3715 |
The logistic regression model showed similar performance on the train and test sets, which indicates the model generalizes well and that there is no evidence of overfitting. Brier score and RMSE increased only slightly from the train to test set, and classification metrics (accuracy, precision, recall, F1) were roughly the same. The model demonstrates moderate predictive performance on both sets, though it has limited ability to detect churners likely due to the class imbalance.
We use bank_factor, our factored dataset from earlier
for these models.
## 'data.frame': 10000 obs. of 11 variables:
## $ credit_score : int 619 608 502 699 850 645 822 376 501 684 ...
## $ country : Factor w/ 3 levels "France","Spain",..: 1 2 1 1 2 2 1 3 1 1 ...
## $ gender : Factor w/ 2 levels "Female","Male": 1 1 1 1 1 2 2 1 2 2 ...
## $ age : int 42 41 42 39 43 44 50 29 44 27 ...
## $ tenure : int 2 1 8 1 2 8 7 4 4 2 ...
## $ balance : num 0 83808 159661 0 125511 ...
## $ products_number : int 1 1 3 2 1 2 2 4 2 1 ...
## $ credit_card : Factor w/ 2 levels "No","Yes": 2 1 2 1 2 2 2 2 1 2 ...
## $ active_member : Factor w/ 2 levels "No","Yes": 2 2 1 1 2 1 2 1 2 2 ...
## $ estimated_salary: num 101349 112543 113932 93827 79084 ...
## $ churn : Factor w/ 2 levels "No","Yes": 2 1 2 1 1 2 1 2 1 1 ...
## Train split: 70.01 %
## Test split: 29.99 %
## Train churn rate: 20.4 %
## Test churn rate: 20.4 %
The first challenger model we build is a Boosted C5.0 model (Perner 2018).
##
## Call:
## C5.0.formula(formula = churn ~ ., data = train_factor, trials = 25, type
## = "prob")
##
## Classification Tree
## Number of samples: 7001
## Number of predictors: 10
##
## Number of boosting iterations: 25
## Average tree size: 22.2
##
## Non-standard options: attempt to group attributes
We test different probability cutoffs and analyze metrics for each (Kennedy 2024):
| Cutoff | TN | FP | FN | TP | Accuracy | Sensitivity | Specificity | Precision | Recall | F1 | Balanced_Accuracy |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0.50 | 5458 | 117 | 662 | 764 | 0.8887 | 0.5358 | 0.9790 | 0.8672 | 0.5358 | 0.6623 | 0.76 |
| 0.45 | 5390 | 185 | 596 | 830 | 0.8884 | 0.5820 | 0.9668 | 0.8177 | 0.5820 | 0.6800 | 0.77 |
| 0.40 | 5311 | 264 | 539 | 887 | 0.8853 | 0.6220 | 0.9526 | 0.7706 | 0.6220 | 0.6884 | 0.79 |
| 0.35 | 5197 | 378 | 478 | 948 | 0.8777 | 0.6648 | 0.9322 | 0.7149 | 0.6648 | 0.6890 | 0.80 |
| 0.30 | 5068 | 507 | 406 | 1020 | 0.8696 | 0.7153 | 0.9091 | 0.6680 | 0.7153 | 0.6908 | 0.81 |
While a cutoff of 0.30 achieves the highest recall it results in a large number of false positives and lower precision, which is less desirable. The 0.35 cutoff (consistent with the logistic regression model) maintains strong recall while significantly improving precision and reducing false positives. Strong recall is important when considering identifying customer churn for this bank. This cutoff also results in high overall performance metrics such as F1 score and balanced accuracy.
Evaluate model on train data:
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
## Boosted C5.0 Train
## Brier score (MSE) 0.08749
## RMSE 0.29579
## SSE 612.51083
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 5197 478
## Yes 378 948
##
## Accuracy : 0.8777
## 95% CI : (0.8698, 0.8853)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.613
##
## Mcnemar's Test P-Value : 0.000715
##
## Precision : 0.7149
## Recall : 0.6648
## F1 : 0.6890
## Prevalence : 0.2037
## Detection Rate : 0.1354
## Detection Prevalence : 0.1894
## Balanced Accuracy : 0.7985
##
## 'Positive' Class : Yes
##
The C5.0 boosted model showed strong in-sample performance with an accuracy of 87.77%, which is substantially higher than the no-information rate of 79.63%. Precision (71.49%), recall (66.48%), and F1-score (68.9%) showed good ability to identify churners, and the balanced accuracy of 79.85% suggests solid performance across both classes. In terms of probability metrics, the boosted C5.0 model also achieves a lower Brier score and RMSE, which indicates more accurate probability predictions than the logistic regression model (n.d.). The boosted C5.0 model substantially outperforms logistic regression on the training set, though we must assess test set performance in case there is overfitting.
Evaluate model on test data:
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 2157 228
## Yes 231 383
##
## Accuracy : 0.8469
## 95% CI : (0.8336, 0.8597)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 6.052e-13
##
## Kappa : 0.5291
##
## Mcnemar's Test P-Value : 0.9256
##
## Precision : 0.6238
## Recall : 0.6268
## F1 : 0.6253
## Prevalence : 0.2037
## Detection Rate : 0.1277
## Detection Prevalence : 0.2047
## Balanced Accuracy : 0.7651
##
## 'Positive' Class : Yes
##
The boosted C5.0 model demonstrated strong performance, though some overfitting is evident. The Brier score increased from the train to test set, meaning there was a decline in the probability prediction accuracy. Similarly, the accuracy decreased from 87.8% to 84.7% in the test set. The precision, recall, and F1 scores were also slightly lower when evaluated on the test set. Despite this performance drop, however, the model still achieves relatively strong test performance compared to logistic regression, so we can assume this model has good predictive ability and minimal overfitting.
## Area under the curve: 0.8629
The model had a small drop in AUC from 0.90 in the train set to 0.86 in the test set which indicates minimal overfitting and good generalization (Fawcett 2006).
A random forest extends the decision tree by averaging predictions across 500 trees, each trained on a bootstrap sample with a random subset of predictors at each split. This reduces variance and produces a more stable, higher-performing classifier. OOB error provides an unbiased estimate of generalization error without needing a separate validation set (Perner 2018).
##
## Call:
## randomForest(formula = churn ~ credit_score + country + gender + age + balance + products_number + credit_card + active_member, data = train_factor, ntree = 500, mtry = 3, classwt = c(No = 1, Yes = 4), importance = TRUE)
## Type of random forest: classification
## Number of trees: 500
## No. of variables tried at each split: 3
##
## OOB estimate of error rate: 16.1%
## Confusion matrix:
## No Yes class.error
## No 5066 509 0.09130045
## Yes 618 808 0.43338008
The Random Forest model achieved an out-of-bag (OOB) error rate of 16.1%, which indicates good overall predictive performance. However, the confusion matrix shows an imbalance in classification performance, with a lower error rate for non-churners (9.1%) and a high error rate for churners (43.3%).
We applied class weights (No = 1, Yes = 4)
to penalize misclassification of churners more heavily. While this
shifts the model’s focus toward the minority class, the relatively high
error rate for churners suggests that imbalance remains an issue.
The variable importance plot shows that age and products_number are the most important based on Mean Decrease Accuracy, meaning they have a strong impact on model performance. Based on Mean Decrease Gini, age, balance, and credit_score are the most important, which suggests they are frequently used in tree splits.
Evaluate train set performance:
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 5444 0
## Yes 131 1426
##
## Accuracy : 0.9813
## 95% CI : (0.9778, 0.9843)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9442
##
## Mcnemar's Test P-Value : < 2.2e-16
##
## Precision : 0.9159
## Recall : 1.0000
## F1 : 0.9561
## Prevalence : 0.2037
## Detection Rate : 0.2037
## Detection Prevalence : 0.2224
## Balanced Accuracy : 0.9883
##
## 'Positive' Class : Yes
##
Evaluate test set performance:
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 2143 220
## Yes 245 391
##
## Accuracy : 0.8449
## 95% CI : (0.8315, 0.8577)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 4.804e-12
##
## Kappa : 0.5293
##
## Mcnemar's Test P-Value : 0.2657
##
## Precision : 0.6148
## Recall : 0.6399
## F1 : 0.6271
## Prevalence : 0.2037
## Detection Rate : 0.1304
## Detection Prevalence : 0.2121
## Balanced Accuracy : 0.7687
##
## 'Positive' Class : Yes
##
The random forest model showed strong performance with a test AUC of 0.858, the highest of the three models so far. We applied class weights of No = 1 and Yes = 4 to correct for the 80/20 class imbalance, which improved the sensitivity while minimizing AUC loss. Performance decreased from the train to test set (e.g., accuracy went down from 98.1% to 84.4%), which suggests moderate overfitting and poor generalization. The increase in Brier score and RMSE also indicates slightly less accurate probability predictions out-of-sample. Overall, the model had solid predictive performance on the test set, though its ability to detect churners (recall \(\approx\) 0.61) remains moderate.
ROC Curve Comparison on Test Data
The boosted C5.0 model had the most optimal ROC curve and the highest AUC. It had the best discrimination across all thresholds (Fawcett 2006).
Model Comparison Table
| Model | Accuracy | Sensitivity | Specificity | Precision | Recall | F1.Score | AUC | MSE | RMSE |
|---|---|---|---|---|---|---|---|---|---|
| Logistic Regression | 0.7953 | 0.4354 | 0.8874 | 0.4972 | 0.4354 | 0.4642 | 0.7624 | 0.1380 | 0.3715 |
| Boosted C5.0 | 0.8469 | 0.6268 | 0.9033 | 0.6238 | 0.6268 | 0.6253 | 0.8629 | 0.1033 | 0.3215 |
| Random Forest | 0.8449 | 0.6399 | 0.8974 | 0.6148 | 0.6399 | 0.6271 | 0.8578 | 0.1166 | 0.3415 |
Given the class imbalance in the dataset (~20% churn), we applied different strategies across the models to improve detection of the minority class. Logistic regression addresses class imbalance through threshold tuning, whereas random forest incorporates class weighting during training, leading to improved detection of churners. The Boosted C5.0 model is inherently less sensitive to class imbalance, but we also used threshold adjustments to improve this model (Kennedy 2024).
Based on Table 7, two models are designated for ongoing use:
Champion Model: Boosted C5.0 - Selected for its superior test set performance and stability when generalizing on unseen data. It achieved the highest AUC, accuracy, and lowest prediction error (Brier score, RMSE), meaning its probability estimates were the most well-calibrated. In addition, it had the highest F1 score, which indicates good balance between precision and recall.
Benchmark: Logistic Regression — While logistic regression offers greater interpretability through its odds ratios, it performed substantially worse than the boosted C5.0 and Random Forest models on key metrics such as AUC and F1 score. Given the objective of accurately identifying churners, the improvement in predictive performance provided by the boosted model outweighs the loss in interpretability in this context.
Random Forest — The Random Forest model performed strongly and achieved metrics similar to those of the Boosted C5.0 model on the test set. However, it was highly unstable when evaluated on unseen data and does not generalize well given the train set accuracy of 98.1% and test set accuracy of 84.5%.
| Assumption | Status |
|---|---|
| Binary outcome | Met — churn is 0/1 |
| Independence of observations | Met — cross-sectional data, one row per customer |
| No severe multicollinearity | Met — all VIF < 2 (Table 3) |
| Linear log-odds relationship | Partially met — age may have non-linear effect |
| Adequate sample size | Met — 7,001 training observations |
| No complete separation | Met — No evidence of complete separation after proper variable encoding |
4 of the 6 assumptions were fully met for the Logistic Regression model, though age non-linearity in particular is a concern (Bobbitt 2020).
The Box-Tidwell test checks whether the log-odds relationship is truly linear in continuous predictors. A significant interaction term (variable x log(variable)) signals non-linearity.
##
## Call:
## glm(formula = churn_num ~ age + age_log + balance + bal_log +
## credit_score + cs_log, family = binomial, data = train_bt)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.149e+01 2.268e+00 -5.069 4e-07 ***
## age 1.395e+00 1.029e-01 13.553 <2e-16 ***
## age_log -2.753e-01 2.123e-02 -12.964 <2e-16 ***
## balance 4.351e-05 1.694e-05 2.568 0.0102 *
## bal_log -3.218e-06 1.423e-06 -2.262 0.0237 *
## credit_score -5.724e-02 2.434e-02 -2.352 0.0187 *
## cs_log 7.560e-03 3.263e-03 2.317 0.0205 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 7077.6 on 7000 degrees of freedom
## Residual deviance: 6201.5 on 6994 degrees of freedom
## AIC: 6215.5
##
## Number of Fisher Scoring iterations: 5
The Box-Tidwell test results indicate that the interaction terms for age, balance, and credit score are statistically significant, which suggests these predictors do not have a linear relationship with the log-odds of churn. This violates the linearity assumption of logistic regression. Transformations or polynomial terms are worth exploring in future models (Leung 2021).
For logistic regression, residuals are not required to be normally distributed — this is an OLS assumption that does not apply here. For random forest there are no distributional assumptions at all (Perner 2018).
Random Forest OOB Error Rate
OOB error stabilizes ~50 trees. 500 trees are more than sufficient, so there is no benefit beyond this amount. While the overall OOB error rate is relatively low (~15%), the class-specific error rates show that the model performs much better for non-churners than for churners. In particular, the error rate for churners remains high at ~43%, which suggests the model struggles more to identify the minority class.
The Boosted C5.0 and Random Forest are flexible and have no strict assumptions on linearity or functional form, but they require careful tuning and evaluation to avoid overfitting and handle class imbalance. These were addressed during our challenger model development through class weighting and threshold tuning (James et al. 2014; Kennedy 2024).
| Metric | Logistic | Boosted.C5.0 | Random.Forest |
|---|---|---|---|
| McFadden Pseudo R^2 | 0.1560 | NA | NA |
| MSE (test) | 0.1380 | 0.1033 | 0.1166 |
| RMSE (test) | 0.3715 | 0.3215 | 0.3415 |
| AUC (test) | 0.7624 | 0.8629 | 0.8578 |
Pseudo-\(R^2\) (only for logistic regression) estimates the goodness-of-fit by comparing the log-likelihood of a full model against an intercept-only model and typically ranges from 0 to 1. Higher values suggest better fit, with values greater than 0.20 considered as excellent (Long 1997). Lower MSE (Brier score) and RMSE indicate better probability calibration (n.d.).
Logistic Regression: (Leung 2021)
Random Forest: (Perner 2018)
Boosted C5.0: (Perner 2018)
Dataset:
A deployed churn model operates in a live environment where customer behavior, economic conditions, and bank product offerings continuously evolve. Without active monitoring, a model that performs well today can silently degrade and produce misleading scores (Sobolik and Boudard 2024).
| Metric | Frequency | Alert_Threshold | Action |
|---|---|---|---|
| AUC (ROC) | Monthly | Drop > 0.03 from baseline (below 0.81) | Re-validate, consider retraining |
| Population Stability Index (PSI) | Monthly | PSI > 0.20 | Investigate data drift, retrain |
| Accuracy | Monthly | Drop > 3% from baseline (below 0.80) | Flag for review |
| Actual vs Expected Churn Rate | Monthly | Divergence > 5 percentage points | Recalibrate probability outputs |
| Hosmer-Lemeshow p-value | Quarterly | p < 0.05 | Recalibrate model |
Thresholds were set relative to our actual test results: AUC baseline 0.8629, accuracy baseline 0.8469.
The model assumes the following conditions remain stable during deployment:
Stable predictor distributions — age, balance, and other inputs do not shift materially. Monitored via PSI, where PSI > 0.20 signals significant population shift requiring retraining.
Consistent data pipeline — input data continues to be formatted identically to training data. Any upstream schema changes must trigger an immediate model review.
Stable churn definition — the business definition of churn remains unchanged. Redefining churn invalidates the model entirely.
No structural breaks — major economic shocks, regulatory changes, or bank mergers may fundamentally alter customer behavior in ways the model cannot anticipate.
The model should be retired and fully rebuilt when any of the following occur:
We chose the Boosted C5.0 model based on its test performance and stability compared to its training performance. It achieved the highest AUC (0.8629), accuracy (0.8469), and the lowest prediction error (MSE and RMSE), which indicates strong discrimination and well-calibrated probabilities. While Random Forest showed comparable performance and slightly higher recall on the test set, it exhibited greater overfitting and weaker probability calibration, making it less robust overall. Logistic regression, although more interpretable, performed substantially worse across all metrics, so its predictive capability was not comparable to the other two models. Given the objective of accurately identifying customers at risk of churn, we select the Boosted model as the champion model since it provides the best balance of predictive performance and generalizability.
Confusion Matrices
## [1] "Logistic Regression Train"
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 4987 826
## Yes 588 600
##
## Accuracy : 0.798
## 95% CI : (0.7884, 0.8074)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 0.3674
##
## Kappa : 0.3362
##
## Mcnemar's Test P-Value : 2.926e-10
##
## Precision : 0.5051
## Recall : 0.4208
## F1 : 0.4591
## Prevalence : 0.2037
## Detection Rate : 0.0857
## Detection Prevalence : 0.1697
## Balanced Accuracy : 0.6576
##
## 'Positive' Class : Yes
##
## [1] "Logistic Regression Test"
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 2119 345
## Yes 269 266
##
## Accuracy : 0.7953
## 95% CI : (0.7804, 0.8096)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 0.564755
##
## Kappa : 0.3384
##
## Mcnemar's Test P-Value : 0.002472
##
## Precision : 0.4972
## Recall : 0.4354
## F1 : 0.4642
## Prevalence : 0.2037
## Detection Rate : 0.0887
## Detection Prevalence : 0.1784
## Balanced Accuracy : 0.6614
##
## 'Positive' Class : Yes
##
## [1] "Boosted C5.0 Train"
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 5197 478
## Yes 378 948
##
## Accuracy : 0.8777
## 95% CI : (0.8698, 0.8853)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.613
##
## Mcnemar's Test P-Value : 0.000715
##
## Precision : 0.7149
## Recall : 0.6648
## F1 : 0.6890
## Prevalence : 0.2037
## Detection Rate : 0.1354
## Detection Prevalence : 0.1894
## Balanced Accuracy : 0.7985
##
## 'Positive' Class : Yes
##
## [1] "Boosted C5.0 Test"
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 2157 228
## Yes 231 383
##
## Accuracy : 0.8469
## 95% CI : (0.8336, 0.8597)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 6.052e-13
##
## Kappa : 0.5291
##
## Mcnemar's Test P-Value : 0.9256
##
## Precision : 0.6238
## Recall : 0.6268
## F1 : 0.6253
## Prevalence : 0.2037
## Detection Rate : 0.1277
## Detection Prevalence : 0.2047
## Balanced Accuracy : 0.7651
##
## 'Positive' Class : Yes
##
## [1] "Random Forest Train"
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 5444 0
## Yes 131 1426
##
## Accuracy : 0.9813
## 95% CI : (0.9778, 0.9843)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9442
##
## Mcnemar's Test P-Value : < 2.2e-16
##
## Precision : 0.9159
## Recall : 1.0000
## F1 : 0.9561
## Prevalence : 0.2037
## Detection Rate : 0.2037
## Detection Prevalence : 0.2224
## Balanced Accuracy : 0.9883
##
## 'Positive' Class : Yes
##
## [1] "Random Forest Test"
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 2143 220
## Yes 245 391
##
## Accuracy : 0.8449
## 95% CI : (0.8315, 0.8577)
## No Information Rate : 0.7963
## P-Value [Acc > NIR] : 4.804e-12
##
## Kappa : 0.5293
##
## Mcnemar's Test P-Value : 0.2657
##
## Precision : 0.6148
## Recall : 0.6399
## F1 : 0.6271
## Prevalence : 0.2037
## Detection Rate : 0.1304
## Detection Prevalence : 0.2121
## Balanced Accuracy : 0.7687
##
## 'Positive' Class : Yes
##
The confusion matrices compare each model’s predicted vs. actual churn classifications across train and test sets, highlighting Random Forest’s overfitting (near-perfect training accuracy that drops significantly on test data) and Logistic Regression’s more consistent generalization.
ROC Curves
The six ROC curves display each model’s ability to distinguish between
churned and non-churned customers across train and test sets, showing
that Random Forest and Boosted C5.0 substantially outperform Logistic
Regression, with the near-perfect Train Random Forest curve confirming
overfitting to the training data.
Additional Data Analysis Plots
Tenure by Churn Status (box plot): Customers who churned (Yes) tend to
have higher and more variable tenure than those who didn’t, suggesting
that longer-tenured customers are not necessarily more loyal and may
still leave the bank.
Churn Proportion by Credit Card Status (stacked bar): The churn rate is nearly identical between customers with and without a credit card (~20% each), indicating that credit card ownership has little to no predictive power for churn
Aggregated Model Metrics
Aggregated Model Metrics table: This table compares all three models (Logistic Regression, Boosted C5.0, Random Forest) across train and test sets on metrics like accuracy, AUC, and F1-score, revealing that Random Forest revealed high training performance which showed signs of overfitting, while Boosted C5.0 offered the strongest balance between train and test generalization.