Title: ECI 587: Introduction to Learning Analytics Output: HTML (default is fine)

Step O: Preparing The Environment

Install required packages

install.packages(“tidyverse”) install.packages(“caret”) install.packages(“randomForest”) install.packages(“scales”) install.packages(“ggplot2”) install.packages(“dplyr”)

Load required package

library(“tidyverse”) library(“caret”) library(“randomForest”) library(“scales”) library(“ggplot2”) library(“stringr”) library(dplyr)

set.seed(42)

Step 1: Collecting Data

1.1 Prepare Environment

library(readr) library(tidyverse)

1.2 Read Data

df <- read_csv(“students.csv”)

1.3 Inspect Structure

glimpse(df)

1.4 Check working directory files

getwd() list.files()

Step 2: Exploring & Preparing Data

2.1 Basic exploration

Summary statistics

summary(df)

Check missing values

colSums(is.na(df))

Check duplicates (based on all columns)

sum(duplicated(df))

2.2 Type conversions

df <- df %>% mutate( Gender = as.factor(Gender), Branch = as.factor(Branch), Internship_Done = as.factor(Internship Done) )

2.3 Drop strictly ID or clearly post-outcome columns

df_cleaned <- df %>% select( -Student ID, -Name, -Placement Status, -CTC (LPA), -Alumni Path, -Internship Domain, )

Skills and Clubs processing

df_cleaned <- df_cleaned %>% mutate( Clubs = ifelse(is.na(Clubs), ““, Clubs), Skills = ifelse(is.na(Skills),”“, Skills) )

df_cleaned <- df_cleaned %>% mutate( Has_Clubs = ifelse(Clubs == ““, 0, 1) )

Skill indicators

df_cleaned <- df_cleaned %>% mutate( Knows_Python = ifelse(str_detect(Skills, regex(“Python”, ignore_case = TRUE)), 1, 0), Knows_C = ifelse(str_detect(Skills, regex(“C\+\+”, ignore_case = TRUE)), 1, 0), Knows_ML = ifelse(str_detect(Skills, regex(“Machine Learning”, ignore_case = TRUE)), 1, 0), Knows_Java = ifelse(str_detect(Skills, regex(“Java”, ignore_case = TRUE)), 1, 0), Knows_SQL = ifelse(str_detect(Skills, regex(“SQL”, ignore_case = TRUE)), 1, 0), Knows_WD = ifelse(str_detect(Skills, regex(“Web Development”, ignore_case = TRUE)), 1, 0), Knows_DS = ifelse(str_detect(Skills, regex(“Data Science”, ignore_case = TRUE)), 1, 0)

colnames(df_cleaned)

df_cleaned <- df_cleaned %>%
  mutate(
    Internship_Done_Binary = ifelse(`Internship Done` == "Yes", 1, 0),
    Skill_Count = ifelse(Skills == "", 0, str_count(Skills, ",") + 1)
  )

df_cleaned <- df_cleaned %>%
  mutate(
    Avg_Sem_GPA = rowMeans(select(., starts_with("Sem")), na.rm = TRUE),
    Sem_GPA_SD  = apply(select(., starts_with("Sem")), 1, sd, na.rm = TRUE)
  )

# Step 3: Train/Test Split in R 

df_model <- df_cleaned %>%
  filter(!is.na(Internship_Done_Binary))

# 3.1 Define outcome variable
y <- df_cleaned$Internship_Done_Binary
table(y)

y <- factor(y, levels = c(0, 1))

# 3.2 Define predictor variables
predictors <- df_cleaned %>%
  select(
    Gender, Branch, Age,
    `Average GPA`, Backlogs, `Attendance (%)`,
    Has_Clubs, Skill_Count,
    Knows_Python, Knows_CPP, Knows_ML,
    Avg_Sem_GPA, Sem_GPA_SD,
    starts_with("Sem")
  )

# 3.3 Create Train/Test Split
train_index <- createDataPartition(y, p = 0.75, list = FALSE)

X_train <- predictors[train_index, ]
X_test  <- predictors[-train_index, ]

y_train <- y[train_index]
y_test  <- y[-train_index]

# 3.4 Confirm split
cat("Training rows:", nrow(X_train), "\n")
cat("Testing rows:", nrow(X_test), "\n")

## Step 4: Logistic Regression 

# Make sure outcome is numeric 0/1 (or factor with 0/1)
y_train_glm <- as.numeric(as.character(y_train))  # in case it's factor

log_data <- data.frame(
  Internship_Done_Binary = y_train_glm,
  X_train
)

log_model <- glm(
  Internship_Done_Binary ~ .,
  data = log_data,
  family = binomial
)

# Predict probabilities on test set
log_test_data <- data.frame(X_test)
log_probs <- predict(log_model, newdata = log_test_data, type = "response")

# Convert probabilities to class labels (0/1)
log_pred_class <- ifelse(log_probs > 0.5, 1, 0)

# Make sure both are factors with same levels
log_pred_factor <- factor(log_pred_class, levels = c(0, 1))
y_test_factor   <- factor(y_test,         levels = c(0, 1))

confusionMatrix(log_pred_factor, y_test_factor, positive = "1")

summary(log_model)

## Step 5: Random Forest 

# Check for NAs in predictors
colSums(is.na(X_train))

# 5.1 Make outcome a factor first
y_train_rf <- factor(y_train, levels = c(0, 1))

# 5.2 Keep only complete cases in training predictors
train_complete <- complete.cases(X_train)
X_train_rf <- X_train[train_complete, ]
y_train_rf_clean <- y_train_rf[train_complete]

# 5.3 Fit Random Forest model
rf_model <- randomForest(
  x = X_train_rf,
  y = y_train_rf_clean,
  ntree = 500,
  importance = TRUE
)

rf_model   

# 5.4 Clean test set to remove NAs in predictors
test_complete <- complete.cases(X_test)
X_test_rf <- X_test[test_complete, ]
y_test_rf <- y_test[test_complete]

# 5.5 Predict on test set
rf_pred <- predict(rf_model, newdata = X_test_rf)

# 5.6 Evaluate performance
confusionMatrix(
  rf_pred,
  factor(y_test_rf, levels = c(0, 1)),
  positive = "1"
)

test_complete <- complete.cases(X_test)
X_test_rf <- X_test[test_complete, ]
y_test_rf <- y_test[test_complete]

rf_pred <- predict(rf_model, newdata = X_test_rf)

confusionMatrix(rf_pred, factor(y_test_rf, levels = c(0, 1)), positive = "1")

ggplot(df_cleaned, aes(x = Gender, fill = factor(`Internship Done`))) +
  geom_bar(position = "dodge") +
  scale_fill_manual(
    values = c("No" = "blue", "Yes" = "red"), 
    labels = c("No Internship", "Completed Internship")
  ) +
  labs(
    title = "Internship Completion Count by Gender",
    x = "Gender",
    y = "Count of Students",
    fill = "Internship Status"
  ) +
  theme_minimal()

ggplot(df_cleaned, aes(x = Branch, fill = factor(`Internship Done`))) +
  geom_bar(position = "dodge") +
  scale_fill_manual(
    values = c("No" = "tomato", "Yes" = "steelblue"),
    labels = c("No Internship", "Completed Internship")
  ) +
  labs(
    title = "Internship Completion by Engineering Academic Major",
    x = "Major (Branch)",
    y = "Count of Students",
    fill = "Internship Status"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(df_cleaned, aes(x = factor(Backlogs), fill = factor(`Internship Done`))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "Internship Completion Rate by Number of Backlogs",
    x = "Backlogs",
    y = "Proportion of Students",
    fill = "Internship Status"
  ) +
  theme_minimal()

df_att <- df_cleaned |> tidyr::drop_na(`Attendance (%)`, `Internship Done`)

ggplot(df_att, aes(
  x = factor(`Internship Done`, levels = c("No", "Yes")),
  y = `Attendance (%)`
)) +
  geom_boxplot(fill = "lightgreen") +
  labs(
    title = "Attendance Rates by Internship Completion",
    x = "Internship Completed",
    y = "Attendance (%)"
  ) +
  theme_minimal()

df_clubs <- df_cleaned |> 
  dplyr::filter(!is.na(Has_Clubs), !is.na(`Internship Done`))

ggplot(df_clubs, aes(x = factor(Has_Clubs), fill = factor(`Internship Done`))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(
    values = c("No" = "#FF6F61", "Yes" = "#6B5B95"),
    labels = c("No Internship", "Completed Internship")
  ) +
  labs(
    title = "Internship Completion Rate by Club Involvement",
    x = "Club Involvement (0 = No, 1 = Yes)",
    y = "Proportion of Students",
    fill = "Internship Status"
  ) +
  theme_minimal()

ggplot(df_cleaned, aes(x = Branch)) +
  geom_bar(fill = "red") +
  labs(
    title = "Number of Students by Major",
    x = "Major (Branch)",
    y = "Count"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

df_cleaned$Knows_Python <- ifelse(grepl("Python", df_cleaned$Skills, ignore.case = TRUE), 1, 0)
df_cleaned$Knows_C      <- ifelse(grepl("C\\+\\+", df_cleaned$Skills, ignore.case = TRUE), 1, 0)
df_cleaned$Knows_ML     <- ifelse(grepl("Machine Learning", df_cleaned$Skills, ignore.case = TRUE), 1, 0)
df_cleaned$Knows_Java   <- ifelse(grepl("Java", df_cleaned$Skills, ignore.case = TRUE), 1, 0)
df_cleaned$Knows_SQL    <- ifelse(grepl("SQL", df_cleaned$Skills, ignore.case = TRUE), 1, 0)
df_cleaned$Knows_WD     <- ifelse(grepl("Web Development", df_cleaned$Skills, ignore.case = TRUE), 1, 0)
df_cleaned$Knows_DS     <- ifelse(grepl("Data Science", df_cleaned$Skills, ignore.case = TRUE), 1, 0)

names(df_cleaned)

skills <- c("Knows_Python", "Knows_C", "Knows_ML",
            "Knows_Java", "Knows_SQL", "Knows_WD", "Knows_DS")

skill_labels <- c(
  Knows_Python = "Python",
  Knows_C      = "C++",
  Knows_ML     = "Machine Learning",
  Knows_Java   = "Java",
  Knows_SQL    = "SQL",
  Knows_WD     = "Web Development",
  Knows_DS     = "Data Science"
)

all_skill_results <- list()

for (s in skills) {
  sub <- df_cleaned[df_cleaned[[s]] == 1, ]
  if (nrow(sub) == 0) next
  
  tab <- prop.table(table(sub[["Internship Done"]]))
  
  all_skill_results[[s]] <- data.frame(
    Skill = skill_labels[[s]],
    InternshipStatus = names(tab),
    Proportion = as.numeric(tab)
  )
}

skill_summary <- do.call(rbind, all_skill_results)

ggplot(skill_summary,
       aes(x = Skill,
           y = Proportion,
           fill = factor(InternshipStatus))) +
  geom_col() +
  scale_y_continuous(labels = percent_format()) +
  coord_flip() +
  labs(
    title = "Internship Completion Rate by Skill",
    x     = "Skill",
    y     = "Proportion of Students (who have that skill)",
    fill  = "Internship Status"
  ) +
  theme_minimal()

ls()

library(ggplot2)
library(scales)

ggplot(skill_summary,
       aes(x = Skill,
           y = Proportion,
           fill = factor(InternshipStatus))) +
  geom_col() +
  scale_y_continuous(labels = percent_format()) +
  coord_flip() +
  labs(
    title = "Internship Completion Rate by Skill",
    x     = "Skill",
    y     = "Proportion of Students (who have that skill)",
    fill  = "Internship Status"
  ) +
  theme_minimal()