This project aims to build a classification model to predict whether a telecom customer will churn or not. By identifying high-risk customers using service behavior and contract-related features, the company can implement retention strategies to reduce churn and maintain revenue.
| Step | Process | Description |
|---|---|---|
| 1 | Load libraries | Import required R packages (randomForest,
caret, ggplot2) |
| 2 | Load and clean data | Read the dataset, remove missing values, and ensure target variable is a factor |
| 3 | Feature selection | Select relevant features such as contract type, billing amount, support usage |
| 4 | Data splitting | Split the dataset into training (80%) and testing (20%) subsets |
| 5 | Model training | Train a Random Forest classifier with 200 trees |
| 6 | Model prediction | Generate predictions on the test set |
| 7 | Evaluation metrics | Calculate accuracy, RMSE, precision, recall, F1 score |
| 8 | Confusion matrix display | Show the classification matrix with true vs predicted values |
| 9 | Feature importance | Output feature importance scores from the Random Forest model |
| 10 | Visualization | Plot a bar chart comparing predicted vs actual churn results |
| 11 | Save summary | Export key evaluation results and model info to a text file |
library(randomForest)
library(caret)
library(ggplot2)
out <- "output"
if (!dir.exists(out)) dir.create(out)
df <- read.csv("customer_churn_telecom_services.csv", stringsAsFactors = TRUE)
df <- na.omit(df)
df$Churn <- as.factor(df$Churn)
write.csv(df, file.path(out, "cleaned_data.csv"), row.names = FALSE)
sel <- df[, c("Churn", "Contract", "tenure", "MonthlyCharges", "InternetService",
"PaymentMethod", "OnlineSecurity", "OnlineBackup", "DeviceProtection",
"TechSupport", "StreamingTV", "StreamingMovies", "MultipleLines")]
set.seed(123)
i <- createDataPartition(sel$Churn, p = 0.8, list = FALSE)
tr <- sel[i, ]
ts <- sel[-i, ]
mdl <- randomForest(Churn ~ ., data = tr, ntree = 200, importance = TRUE)
pred <- predict(mdl, ts)
cm <- confusionMatrix(pred, ts$Churn)
acc <- cm$overall["Accuracy"]
rmse <- sqrt(mean((as.numeric(pred) - as.numeric(ts$Churn))^2))
prec <- posPredValue(pred, ts$Churn, positive = "Yes")
rec <- sensitivity(pred, ts$Churn, positive = "Yes")
f1 <- 2 * prec * rec / (prec + rec)
list(
Accuracy = acc,
RMSE = rmse,
Precision = prec,
Recall = rec,
F1_Score = f1
)
## $Accuracy
## Accuracy
## 0.8035587
##
## $RMSE
## [1] 0.443217
##
## $Precision
## [1] 0.6456456
##
## $Recall
## [1] 0.5764075
##
## $F1_Score
## [1] 0.6090652
cm
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Yes
## No 914 158
## Yes 118 215
##
## Accuracy : 0.8036
## 95% CI : (0.7818, 0.824)
## No Information Rate : 0.7345
## P-Value [Acc > NIR] : 9.176e-10
##
## Kappa : 0.4784
##
## Mcnemar's Test P-Value : 0.0189
##
## Sensitivity : 0.8857
## Specificity : 0.5764
## Pos Pred Value : 0.8526
## Neg Pred Value : 0.6456
## Prevalence : 0.7345
## Detection Rate : 0.6505
## Detection Prevalence : 0.7630
## Balanced Accuracy : 0.7310
##
## 'Positive' Class : No
##
mdl
##
## Call:
## randomForest(formula = Churn ~ ., data = tr, ntree = 200, importance = TRUE)
## Type of random forest: classification
## Number of trees: 200
## No. of variables tried at each split: 3
##
## OOB estimate of error rate: 20.97%
## Confusion matrix:
## No Yes class.error
## No 3650 481 0.1164367
## Yes 699 797 0.4672460
importance(mdl)
## No Yes MeanDecreaseAccuracy MeanDecreaseGini
## Contract -6.7833838 25.866991 27.806895 194.81836
## tenure 10.3030068 41.308323 31.717224 380.60250
## MonthlyCharges 11.3996016 10.439007 20.050967 312.32972
## InternetService 9.9705540 14.630484 16.766423 76.88417
## PaymentMethod -4.3063370 14.566111 8.335510 112.35160
## OnlineSecurity 0.8365918 22.257239 14.388882 86.73827
## OnlineBackup 3.2824784 10.557927 9.833020 49.93962
## DeviceProtection 7.1047051 1.014956 8.017648 43.13440
## TechSupport 3.6608031 20.345184 15.391365 79.38950
## StreamingTV 6.3061389 1.446131 7.633675 33.81143
## StreamingMovies 7.2862507 1.287617 8.247824 32.52817
## MultipleLines 1.2929768 8.242170 7.728753 45.46728
df_out <- data.frame(Actual = ts$Churn, Predicted = pred)
ggplot(df_out, aes(x = Actual, fill = Predicted)) +
geom_bar(position = "dodge") +
labs(title = "Prediction vs Actual", x = "Actual", y = "Count") +
theme_minimal()
sink(file.path(out, "summary.txt"))
cat("Model Evaluation Summary\n\n")
cat("1. Accuracy: ", round(acc, 4), "\n")
cat("2. RMSE: ", round(rmse, 4), "\n")
cat("3. Precision: ", round(prec, 4), "\n")
cat("4. Recall: ", round(rec, 4), "\n")
cat("5. F1 Score: ", round(f1, 4), "\n\n")
cat("Confusion Matrix\n\n")
print(cm)
cat("\n Model Summary \n\n")
print(mdl)
cat("\n Feature Importance\n\n")
print(importance(mdl))
sink()