#clear the memory
rm(list = ls())
setwd("/Users/nickponzi/lab/data")
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.5.0 ✔ purrr 1.0.2
## ✔ tibble 3.2.1 ✔ dplyr 1.1.4
## ✔ tidyr 1.3.1 ✔ stringr 1.5.0
## ✔ readr 2.1.3 ✔ forcats 0.5.2
## Warning: package 'ggplot2' was built under R version 4.2.3
## Warning: package 'tidyr' was built under R version 4.2.3
## Warning: package 'dplyr' was built under R version 4.2.3
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
# Load the CSV file into a data frame
data <- read.csv("diabetes.csv", header = TRUE)
# Display the structure of the dataset
str(data)
## 'data.frame': 768 obs. of 9 variables:
## $ Pregnancies : int 6 1 8 1 0 5 3 10 2 8 ...
## $ Glucose : int 148 85 183 89 137 116 78 115 197 125 ...
## $ BloodPressure : int 72 66 64 66 40 74 50 0 70 96 ...
## $ SkinThickness : int 35 29 0 23 35 0 32 0 45 0 ...
## $ Insulin : int 0 0 0 94 168 0 88 0 543 0 ...
## $ BMI : num 33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 0 ...
## $ DiabetesPedigreeFunction: num 0.627 0.351 0.672 0.167 2.288 ...
## $ Age : int 50 31 32 21 33 30 26 29 53 54 ...
## $ Outcome : int 1 0 1 0 1 0 1 0 1 1 ...
# Display the first few rows of the dataset
head(data)
## Pregnancies Glucose BloodPressure SkinThickness Insulin BMI
## 1 6 148 72 35 0 33.6
## 2 1 85 66 29 0 26.6
## 3 8 183 64 0 0 23.3
## 4 1 89 66 23 94 28.1
## 5 0 137 40 35 168 43.1
## 6 5 116 74 0 0 25.6
## DiabetesPedigreeFunction Age Outcome
## 1 0.627 50 1
## 2 0.351 31 0
## 3 0.672 32 1
## 4 0.167 21 0
## 5 2.288 33 1
## 6 0.201 30 0
# Check for missing values
missing_values <- colSums(is.na(data))
print(missing_values)
## Pregnancies Glucose BloodPressure
## 0 0 0
## SkinThickness Insulin BMI
## 0 0 0
## DiabetesPedigreeFunction Age Outcome
## 0 0 0
# Calculate Z-scores for each numerical feature
z_scores <- scale(data[, -9]) # Exclude the outcome variable
# Identify outliers based on Z-scores
outliers <- apply(abs(z_scores) > 3, 1, any) # Check if any Z-score exceeds 3 for each row
outlier_indices <- which(outliers)
# Print the indices of outliers
print(outlier_indices)
## [1] 5 8 9 10 14 16 46 50 59 61 76 79 82 89 112 124 146 154 160
## [20] 173 178 183 187 194 221 223 229 248 262 267 270 287 299 301 331 333 337 343
## [39] 348 350 358 371 372 396 410 416 427 431 436 446 454 456 460 469 485 487 495
## [58] 503 523 534 536 580 585 590 594 602 605 620 622 644 646 656 667 674 685 696
## [77] 698 704 707 754
# Remove outliers
data_clean <- data[-outlier_indices, ]
# Verify the removal of outliers
print("Number of observations after removing outliers:")
## [1] "Number of observations after removing outliers:"
print(dim(data_clean))
## [1] 688 9
# Set seed for reproducibility
set.seed(123)
# Split data into training and testing sets
library(caTools)
split <- sample.split(data_clean$Outcome, SplitRatio = 0.7)
training_data <- subset(data_clean, split == TRUE)
testing_data <- subset(data_clean, split == FALSE)
# Check dimensions of training and testing sets
dim(training_data)
## [1] 482 9
dim(testing_data)
## [1] 206 9
#Create a logistic Regression Model
# Load required library
library(glmnet)
## Loading required package: Matrix
##
## Attaching package: 'Matrix'
##
## The following objects are masked from 'package:tidyr':
##
## expand, pack, unpack
##
## Loaded glmnet 4.1-6
# Create a logistic regression model
logistic_model <- glm(Outcome ~ ., data = training_data, family = "binomial")
# Print the summary of the model
summary(logistic_model)
##
## Call:
## glm(formula = Outcome ~ ., family = "binomial", data = training_data)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.0172 -0.6840 -0.3505 0.6132 2.5647
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.078e+01 1.131e+00 -9.535 < 2e-16 ***
## Pregnancies 1.234e-01 4.402e-02 2.804 0.005044 **
## Glucose 3.738e-02 5.029e-03 7.434 1.06e-13 ***
## BloodPressure -7.116e-03 1.076e-02 -0.662 0.508286
## SkinThickness -8.219e-03 9.285e-03 -0.885 0.376046
## Insulin 7.604e-04 1.515e-03 0.502 0.615629
## BMI 1.230e-01 2.265e-02 5.429 5.68e-08 ***
## DiabetesPedigreeFunction 1.635e+00 4.205e-01 3.888 0.000101 ***
## Age 2.239e-02 1.265e-02 1.771 0.076605 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 611.26 on 481 degrees of freedom
## Residual deviance: 416.74 on 473 degrees of freedom
## AIC: 434.74
##
## Number of Fisher Scoring iterations: 5
#Evaluate Model Performance
# Predict probabilities of diabetes on testing data
logistic_probabilities <- predict(logistic_model, newdata = testing_data, type = "response")
# Convert probabilities to binary predictions (0 or 1) based on a threshold of 0.5
logistic_predictions <- ifelse(logistic_probabilities > 0.5, 1, 0)
# Calculate confusion matrix
conf_matrix <- table(Actual = testing_data$Outcome, Predicted = logistic_predictions)
# Calculate accuracy
accuracy <- sum(diag(conf_matrix)) / sum(conf_matrix)
# Calculate precision
precision <- conf_matrix[2, 2] / sum(conf_matrix[, 2])
# Calculate recall (sensitivity)
recall <- conf_matrix[2, 2] / sum(conf_matrix[2, ])
# Calculate F1-score
f1_score <- 2 * precision * recall / (precision + recall)
# Print evaluation metrics
print(paste("Accuracy:", accuracy))
## [1] "Accuracy: 0.762135922330097"
print(paste("Precision:", precision))
## [1] "Precision: 0.641791044776119"
print(paste("Recall (Sensitivity):", recall))
## [1] "Recall (Sensitivity): 0.63235294117647"
print(paste("F1-Score:", f1_score))
## [1] "F1-Score: 0.637037037037037"