1. Data Import and Integrity Check

# Direct path to downloaded CSV file
data_path <- "C:/Users/user/Downloads/archive (7)/alzheimers_disease_data.csv"

alzheimers <- read.csv(data_path)

# Verify dimensions and initial structure
dim(alzheimers)
## [1] 2149   35
str(alzheimers[, 1:8])
## 'data.frame':    2149 obs. of  8 variables:
##  $ PatientID         : int  4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 ...
##  $ Age               : int  73 89 73 74 89 86 68 75 72 87 ...
##  $ Gender            : int  0 0 0 1 0 1 0 0 1 0 ...
##  $ Ethnicity         : int  0 0 3 0 0 1 3 0 1 0 ...
##  $ EducationLevel    : int  2 0 1 1 0 1 2 1 0 0 ...
##  $ BMI               : num  22.9 26.8 17.8 33.8 20.7 ...
##  $ Smoking           : int  0 0 0 1 0 0 1 0 0 1 ...
##  $ AlcoholConsumption: num  13.3 4.54 19.56 12.21 18.45 ...
# Check for missing values across the dataset
missing_total <- sum(is.na(alzheimers))
cat("Total Missing Values in Dataset:", missing_total, "\n")
## Total Missing Values in Dataset: 0

2. Data Cleaning and Factor Recoding

# Create analysis copy
alz_clean <- alzheimers

# Recode binary variables to factors with clear labels
alz_clean$Diagnosis <- factor(alz_clean$Diagnosis, levels = c(0, 1), labels = c("No", "Yes"))
alz_clean$Gender    <- factor(alz_clean$Gender, levels = c(0, 1), labels = c("Male", "Female"))

# Check class frequencies
table(Diagnosis = alz_clean$Diagnosis)
## Diagnosis
##   No  Yes 
## 1389  760
prop.table(table(Diagnosis = alz_clean$Diagnosis)) * 100
## Diagnosis
##       No      Yes 
## 64.63471 35.36529

3. Exploratory Data Analysis & Group Comparisons

# Summary table of clinical indicators grouped by Diagnosis
clinical_summary <- alz_clean %>%
  group_by(Diagnosis) %>%
  summarise(
    Count     = n(),
    Mean_Age  = mean(Age, na.rm = TRUE),
    SD_Age    = sd(Age, na.rm = TRUE),
    Mean_MMSE = mean(MMSE, na.rm = TRUE),
    SD_MMSE   = sd(MMSE, na.rm = TRUE),
    Mean_BMI  = mean(BMI, na.rm = TRUE),
    SD_BMI    = sd(BMI, na.rm = TRUE)
  )

clinical_summary
## # A tibble: 2 × 8
##   Diagnosis Count Mean_Age SD_Age Mean_MMSE SD_MMSE Mean_BMI SD_BMI
##   <fct>     <int>    <dbl>  <dbl>     <dbl>   <dbl>    <dbl>  <dbl>
## 1 No         1389     74.9   8.90      16.3    8.93     27.5   7.17
## 2 Yes         760     74.8   9.15      12.0    7.23     27.9   7.30

4. Visualizations

# 1. Boxplot of MMSE (Cognitive Function) by Diagnosis
ggplot(alz_clean, aes(x = Diagnosis, y = MMSE, fill = Diagnosis)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "red") +
  theme_minimal() +
  labs(
    title = "MMSE Cognitive Score Distribution by Diagnosis",
    x = "Alzheimer's Diagnosis",
    y = "MMSE Score"
  ) +
  theme(legend.position = "none")

# 2. Age Density Distribution across Diagnosis Groups
ggplot(alz_clean, aes(x = Age, fill = Diagnosis)) +
  geom_density(alpha = 0.4) +
  theme_minimal() +
  labs(
    title = "Age Density Distribution Across Diagnosis Groups",
    x = "Age (Years)",
    y = "Density"
  )

5. Binary Logistic Regression Analysis

# Multivariable logistic regression model
logit_model <- glm(
  Diagnosis ~ Age + Gender + BMI + MMSE,
  data = alz_clean,
  family = binomial(link = "logit")
)

summary(logit_model)
## 
## Call:
## glm(formula = Diagnosis ~ Age + Gender + BMI + MMSE, family = binomial(link = "logit"), 
##     data = alz_clean)
## 
## Coefficients:
##               Estimate Std. Error z value Pr(>|z|)    
## (Intercept)   0.165233   0.439463   0.376    0.707    
## Age          -0.001374   0.005178  -0.265    0.791    
## GenderFemale -0.067322   0.093003  -0.724    0.469    
## BMI           0.007743   0.006442   1.202    0.229    
## MMSE         -0.059972   0.005574 -10.759   <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: 2792.3  on 2148  degrees of freedom
## Residual deviance: 2666.9  on 2144  degrees of freedom
## AIC: 2676.9
## 
## Number of Fisher Scoring iterations: 4
# Compute Odds Ratios (OR) and 95% Wald Confidence Intervals
odds_ratios <- exp(coef(logit_model))
conf_intervals <- exp(confint.default(logit_model))

model_table <- cbind(
  Odds_Ratio = odds_ratios,
  conf_intervals,
  p_value = summary(logit_model)$coefficients[, 4]
)

round(model_table, 4)
##              Odds_Ratio  2.5 % 97.5 % p_value
## (Intercept)      1.1797 0.4985 2.7915  0.7069
## Age              0.9986 0.9885 1.0088  0.7908
## GenderFemale     0.9349 0.7791 1.1218  0.4691
## BMI              1.0078 0.9951 1.0206  0.2294
## MMSE             0.9418 0.9316 0.9521  0.0000

6. Model Evaluation and ROC Curve

# Generate predicted probabilities
alz_clean$pred_prob <- predict(logit_model, type = "response")

# Classification at default 0.5 threshold
alz_clean$pred_class <- factor(
  ifelse(alz_clean$pred_prob >= 0.5, "Yes", "No"),
  levels = c("No", "Yes")
)

# Confusion Matrix & Classification Accuracy
conf_mat <- table(Predicted = alz_clean$pred_class, Actual = alz_clean$Diagnosis)
print(conf_mat)
##          Actual
## Predicted   No  Yes
##       No  1231  630
##       Yes  158  130
accuracy <- sum(diag(conf_mat)) / sum(conf_mat)
cat("Classification Accuracy:", round(accuracy * 100, 2), "%\n")
## Classification Accuracy: 63.33 %
# ROC Curve and Area Under the Curve (AUC)
roc_curve <- roc(alz_clean$Diagnosis, alz_clean$pred_prob, levels = c("No", "Yes"))
cat("Area Under Curve (AUC):", round(auc(roc_curve), 4), "\n")
## Area Under Curve (AUC): 0.6441
plot(roc_curve, col = "#1B4F72", lwd = 2.5, main = "ROC Curve: Alzheimer's Diagnosis Model")
abline(a = 0, b = 1, lty = 2, col = "gray60")

7. Discussion and Summary