1. Project Overview and Objectives

This regression project aims to predict customers’ TotalCharges based on multiple telecom service features using Random Forest and Gradient Boosting (GBM) models. The goal is to evaluate predictive accuracy and identify the most influential variables.

2. Workflow Summary

Step Process Description
1 Load libraries Load necessary R packages for modeling and visualization
2 Load and clean data Read dataset, filter missing/invalid rows, and process categorical features
3 Feature engineering Remove irrelevant features and create a numeric support feature (NS)
4 Data splitting Split dataset into training and testing sets (70:30)
5 Model training Train Random Forest and GBM regression models
6 Model evaluation Compute RMSE, R², and MAE for both models
7 Feature importance Plot top 15 most important variables from Random Forest
8 Visualization Plot predicted vs actual TotalCharges for each model
9 Export results Save outputs: plots, CSV files, RDS model

3. Load Libraries

library(dplyr)
library(caret)
library(randomForest)
library(ggplot2)
library(corrplot)

4. Load and Clean Data

set.seed(123)
out_dir <- "Regression_Results"
if (!dir.exists(out_dir)) dir.create(out_dir)

f <- "customer_churn_telecom_services.csv"
df <- read.csv(f)

5. Preprocess Function

prep <- function(df) {
  df <- df[df$TotalCharges != "" & !is.na(df$TotalCharges), ]
  df$TotalCharges <- as.numeric(as.character(df$TotalCharges))
  
  cat_vars <- c("gender", "Partner", "Dependents", "PhoneService", 
                "MultipleLines", "InternetService", "OnlineSecurity",
                "OnlineBackup", "DeviceProtection", "TechSupport",
                "StreamingTV", "StreamingMovies", "Contract",
                "PaperlessBilling", "PaymentMethod", "Churn")
  
  for (v in cat_vars) {
    df[[v]] <- factor(df[[v]])
    levels(df[[v]]) <- gsub("No internet service|No phone service", "No", levels(df[[v]]))
  }
  
  df <- df %>% select(-MonthlyCharges, -Churn)
  
  df$NS <- rowSums(df %>% select(OnlineSecurity, OnlineBackup, DeviceProtection,
                                 TechSupport, StreamingTV, StreamingMovies) == "Yes")
  
  df <- df %>%
    mutate(TotalCharges = ifelse(tenure == 0 & TotalCharges > 0, TotalCharges, TotalCharges))
  
  return(df)
}

df_c <- prep(df)

6. Train-Test Split

idx <- createDataPartition(df_c$TotalCharges, p = 0.7, list = FALSE)
trn <- df_c[idx, ]
tst <- df_c[-idx, ]

7. Train Random Forest & DBM Model

mdl_list <- list()
res <- list()

eval_m <- function(m, tst) {
  pred <- predict(m, newdata = tst)
  rmse <- RMSE(pred, tst$TotalCharges)
  r2 <- R2(pred, tst$TotalCharges)
  mae <- MAE(pred, tst$TotalCharges)
  return(list(pred = pred, metrics = data.frame(RMSE = rmse, R2 = r2, MAE = mae)))
}

set.seed(123)
mdl_list[["RF"]] <- randomForest(TotalCharges ~ ., data = trn, ntree = 200)
res[["RF"]] <- eval_m(mdl_list[["RF"]], tst)

set.seed(123)
ctrl <- trainControl(method = "cv", number = 5)
mdl_list[["GBM"]] <- train(TotalCharges ~ ., data = trn, method = "gbm", trControl = ctrl, verbose = FALSE)
res[["GBM"]] <- eval_m(mdl_list[["GBM"]], tst)

8. Feature Importance Plot

imp <- varImp(mdl_list[["RF"]], scale = TRUE)
imp_df <- data.frame(Var = rownames(imp), Imp = imp$Overall) %>% arrange(desc(Imp))

p_imp <- imp_df %>%
  head(15) %>%
  ggplot(aes(x = reorder(Var, Imp), y = Imp)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(title = "Top 15 Important Features", x = "Variables", y = "Importance") +
  theme_minimal()

ggsave(file.path(out_dir, "feature_importance.png"), p_imp, width = 8, height = 6)

9. Predicted vs Actual Plot

plot_cmp <- function(tst, res) {
  df_all <- data.frame()
  for (m in names(res)) {
    df_temp <- data.frame(Model = m,
                          Actual = tst$TotalCharges,
                          Predicted = res[[m]]$pred)
    df_all <- rbind(df_all, df_temp)
  }
  ggplot(df_all, aes(x = Actual, y = Predicted)) +
    geom_point(alpha = 0.3, color = "steelblue") +
    geom_abline(slope = 1, intercept = 0, color = "red", linetype = "dashed") +
    facet_wrap(~ Model, ncol = 2) +
    labs(title = "Actual vs Predicted Values",
         x = "Actual Total Charges", y = "Predicted Total Charges") +
    theme_bw()
}

p_cmp <- plot_cmp(tst, res)
ggsave(file.path(out_dir, "predictions_vs_actual.png"), p_cmp, width = 10, height = 8)

10. Save Evaluation Results

m_df <- data.frame()
for (m in names(res)) {
  m_df <- rbind(m_df, data.frame(Model = m, res[[m]]$metrics))
}

write.csv(m_df, file.path(out_dir, "model_performance.csv"), row.names = FALSE)
saveRDS(mdl_list, file.path(out_dir, "regression_models.rds"))
write.csv(df_c, file.path(out_dir, "cleaned_dataset.csv"), row.names = FALSE)

print("Model Comparison:")
## [1] "Model Comparison:"
print(m_df)
##   Model     RMSE        R2       MAE
## 1    RF 157.4967 0.9957800 105.41846
## 2   GBM 138.5160 0.9962581  98.31762
cat("\nResults saved in:", out_dir)
## 
## Results saved in: Regression_Results