Prediksi Diabetes Menggunakan Regresi Logistik

Diabetes melitus (DM) merupakan satu masalah kesehatan yang besar. Menurut International Diabetes Federation (IDF) tahun 2015, penderita diabetes melitus tertinggi terdapat di Cina dengan jumlah penderita sebanyak 109,6 juta jiwa, diikuti India dan USA dengan masing-masing jumlah penderita diabetes sebanyak 69,2 juta jiwa dan 29,3 juta jiwa. Indonesia menduduki urutan ke 7 tertinggi dengan jumlah populasi yang terkena diabetes mencapai 10 juta jiwa dan diperkirakan akan meningkat menjadi16,2 juta jiwa pada tahun 2040.

Apa Saja Bahaya Penyakit Gula?

  1. Penyempitan pembuluh darah

  2. Bisa menyebabkan kerusakan pada mata

  3. Menimbulkan hiperglikemia dan hipoglikemia

  4. Kerusakan pada saraf

  5. Kerusakan pada ginjal

  6. Masalah pada kaki

Faktor Risiko Diabetes Melitus

Secara umum, diabetes mellitus bisa dibedakan menjadi dua jenis, yaitu diabetes tipe 1 dan tipe 2.

Diabetes tipe 1 terjadi karena adanya kondisi autoimun, di mana sistem kekebalan tubuh pengidap sendiri yang menyerang dan menghancurkan sel-sel pankreas yang memproduksi insulin. Hal ini mengakibatkan kadar gula darah jadi meningkat, sehingga memicu terjadinya kerusakan pada organ-organ tubuh. Masih belum diketahui apa penyebab kondisi autoimun ini. Namun, dugaan paling kuat adalah karena adanya faktor genetik yang dimiliki pengidap dan ditambah lagi dengan faktor lingkungan.

Diabetes tipe 2 merupakan jenis diabetes yang lebih sering terjadi. Diabetes ini disebabkan karena sel-sel tubuh kurang sensitif terhadap insulin, sehingga insulin yang dihasilkan tidak bisa dipergunakan dengan baik (resistensi sel tubuh terhadap insulin). Hampir sebagian besar pengidap diabetes di dunia mengalami diabetes tipe 2.

Berikut ini faktor-faktor risiko diabetes tipe 1:

  1. Memiliki anggota keluarga yang mengidap diabetes tipe 1

  2. Terkena infeksi virus

  3. Orang berkulit putih dipercaya lebih berisiko mengalami diabetes tipe 1 dibandingkan ras lain

  4. Bepergian ke daerah yang jauh dari khatulistiwa (ekuator)

  5. Usia. Meskipun diabetes tipe 1 bisa muncul pada usia berapapun, tapi penyakit ini banyak dialami oleh anak-anak berumur 4–7 tahun dan 10–14 tahun.

Sedangkan faktor risiko diabetes mellitus tipe 2 adalah sebagai berikut:

  1. Mengalami obesitas atau kelebihan berat badan.

  2. Memiliki riwayat keluarga dengan diabetes tipe 2.

  3. Kurang aktif bergerak. Aktivitas fisik bisa membantu seseorang untuk mengontrol berat badan, membakar glukosa sebagai energi, dan membuat sel tubuh lebih sensitif terhadap insulin. Itulah mengapa, orang yang kurang beraktivitas fisik akan lebih mudah terkena diabetes tipe 2.

  4. Usia. Risiko terkena diabetes tipe 2 akan meningkat seiring bertambahnya usia.

5.Mengidap tekanan darah tinggi atau hipertensi.

  1. Memiliki kadar kolesterol dan trigliserida yang tidak normal. Orang yang memiliki kadar kolesterol baik atau HDL (high-density lipoprotein) yang rendah, tapi kadar trigliseridanya tinggi lebih berisiko mengalami diabetes tipe 2.

  2. Mengidap polycystic ovarian syndrome (PCOS). Khusus pada wanita, memiliki riwayat penyakit PCOS membuat seorang wanita berisiko tinggi mengalami diabetes tipe 2.

Sedangkan pada ibu hamil, risiko mengalami diabetes gestasional semakin besar bila ibu mengidap diabetes tipe 2.

Setelah mengetahui tentang Diabetes Militus kita akan menggunakan Dataset yang berasal dari National Institute of Diabetes and Digestive and Ginjal Diseases. Tujuan dari Analisis ini adalah membangun model untuk memprediksi secara diagnostik apakah pasien memiliki diabetes atau tidak.

Data Preparation

# package yang diperlukan
library(readr)
library(tidyverse)
library(gtools)
library(ggplot2)                  
library(readr)                    
library(ggcorrplot)
library(corrplot)
library(PerformanceAnalytics)     
library(ROCR)
library(tidyverse)
library(psych)                    
library(GGally)
library(caret)
#Load dataset
db = read.csv('diabetes.csv', header=TRUE)
head(db,3)

Datase ini terdiri dari beberapa variabel :

  • Pregnancies = Jumlah kehamilan

  • Glucose = konsentrasi glukosa 2 jam dalam tes toleransi glukosa oral

  • BloodPressure = Tekanan darah diastolik (mm Hg)

  • SkinThickness = Ketebalan lipatan kulit (mm)

  • Insulin = 2-Jam serum insulin (mu U / ml)

  • BMI = Indeks massa tubuh (berat dalam kg / (tinggi dalam m) ^ 2)

  • DiabetesPedigreeFunction = Riwayat keturunan diabetes

  • Age = Umur (tahun)

  • Variabel Outcome = Class (0 atau 1) 268 dari 768 adalah 1, yang lain adalah 0

#cek type Data
str(db)
> '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 ...
summary(db)
>   Pregnancies        Glucose      BloodPressure    SkinThickness  
>  Min.   : 0.000   Min.   :  0.0   Min.   :  0.00   Min.   : 0.00  
>  1st Qu.: 1.000   1st Qu.: 99.0   1st Qu.: 62.00   1st Qu.: 0.00  
>  Median : 3.000   Median :117.0   Median : 72.00   Median :23.00  
>  Mean   : 3.845   Mean   :120.9   Mean   : 69.11   Mean   :20.54  
>  3rd Qu.: 6.000   3rd Qu.:140.2   3rd Qu.: 80.00   3rd Qu.:32.00  
>  Max.   :17.000   Max.   :199.0   Max.   :122.00   Max.   :99.00  
>     Insulin           BMI        DiabetesPedigreeFunction      Age       
>  Min.   :  0.0   Min.   : 0.00   Min.   :0.0780           Min.   :21.00  
>  1st Qu.:  0.0   1st Qu.:27.30   1st Qu.:0.2437           1st Qu.:24.00  
>  Median : 30.5   Median :32.00   Median :0.3725           Median :29.00  
>  Mean   : 79.8   Mean   :31.99   Mean   :0.4719           Mean   :33.24  
>  3rd Qu.:127.2   3rd Qu.:36.60   3rd Qu.:0.6262           3rd Qu.:41.00  
>  Max.   :846.0   Max.   :67.10   Max.   :2.4200           Max.   :81.00  
>     Outcome     
>  Min.   :0.000  
>  1st Qu.:0.000  
>  Median :0.000  
>  Mean   :0.349  
>  3rd Qu.:1.000  
>  Max.   :1.000
#cek dimensi
dim(db)
> [1] 768   9
#cek missing value
db %>% 
  is.na() %>% 
  colSums()
>              Pregnancies                  Glucose            BloodPressure 
>                        0                        0                        0 
>            SkinThickness                  Insulin                      BMI 
>                        0                        0                        0 
> DiabetesPedigreeFunction                      Age                  Outcome 
>                        0                        0                        0
#Konversikan Outcome pada db : 0 = No  &  1 = Yes
db$Outcome <- as.factor(db$Outcome)
levels(db$Outcome) <- c("No","Yes")

Data Exploration

Analisis Kelompok Usia

ggplot(aes(x = Age), data=db) +
  geom_histogram(binwidth=1, color='white', fill = "#FF00FF") +
  scale_x_continuous(limits=c(20,90), breaks=seq(20,90,5)) +
  xlab("Usia") +
  ylab("Jumlah Orang Berdasarkan Usia")

# Membuat kolom kategori usia
db$Age_Cat <- ifelse(db$Age < 21, "<21", 
                   ifelse((db$Age>=21) & (db$Age<=25), "21-25", 
                   ifelse((db$Age>25) & (db$Age<=30), "25-30",
                   ifelse((db$Age>30) & (db$Age<=35), "30-35",
                   ifelse((db$Age>35) & (db$Age<=40), "35-40",
                   ifelse((db$Age>40) & (db$Age<=50), "40-50",
                   ifelse((db$Age>50) & (db$Age<=60), "50-60",">60")))))))
db$Age_Cat <- factor(db$Age_Cat, levels = c('<21','21-25','25-30','30-35','35-40','40-50','50-60','>60'))
# Barplot by Age_Cat
ggplot(aes(x = Age_Cat), data = db) +
            geom_bar(fill='#FF00FF')

Sebagian besar subjek berada diantara umur 21 - 30

Analisis Korelasi

db_cor <- round(cor(db[1:8]),1)
ggcorrplot(db_cor)

corrplot.mixed(corr = cor(db[1:8]))

ggcorr(db[,-9], name = "corr", label = TRUE) + theme(legend.position="none")+
  labs(title="Korelasi Variansi ") + theme(plot.title=element_text(face='bold',color='black',hjust=0.5,size=12))

Tidak ada korelasi kuat antar variabel, jadi tidak ada yang perlu dihilangkan dari variabel- variabel tersebut

Spiliting Data

RNGkind(sample.kind = "Rounding")
set.seed(417) 

index_db <- sample(x = nrow(db) , size = nrow(db)*0.75) 
train <- db[index_db , ]
test <- db[-index_db, ] # tanda - berarti negasi
# cek spliting data train dan test
nrow(train)
> [1] 576
nrow(test)
> [1] 192
# re-check class imbalance
train$Outcome %>% 
  table() %>% 
  prop.table()
> .
>        No       Yes 
> 0.6579861 0.3420139

proporsi kelas yang balance penting untuk data train karena kita akan melatih model menggunakan data train.

Model Fitting

#fitting model dengan semua variabel independen
model <- glm(Outcome ~ ., data = train, family = binomial)
summary(model)
> 
> Call:
> glm(formula = Outcome ~ ., family = binomial, data = train)
> 
> Deviance Residuals: 
>     Min       1Q   Median       3Q      Max  
> -2.9840  -0.6773  -0.3777   0.6768   3.0355  
> 
> Coefficients:
>                            Estimate Std. Error z value Pr(>|z|)    
> (Intercept)              -7.5033789  1.5481132  -4.847 1.25e-06 ***
> Pregnancies               0.0483106  0.0396768   1.218  0.22337    
> Glucose                   0.0380749  0.0044887   8.482  < 2e-16 ***
> BloodPressure            -0.0089633  0.0060536  -1.481  0.13870    
> SkinThickness            -0.0043738  0.0080374  -0.544  0.58631    
> Insulin                  -0.0009301  0.0010123  -0.919  0.35820    
> BMI                       0.0885507  0.0183439   4.827 1.38e-06 ***
> DiabetesPedigreeFunction  1.0955133  0.3639698   3.010  0.00261 ** 
> Age                      -0.0577335  0.0565531  -1.021  0.30731    
> Age_Cat25-30              0.4993353  0.4417268   1.130  0.25830    
> Age_Cat30-35              1.7282904  0.6819322   2.534  0.01126 *  
> Age_Cat35-40              1.6482267  0.9433394   1.747  0.08060 .  
> Age_Cat40-50              2.3472893  1.2709452   1.847  0.06476 .  
> Age_Cat50-60              2.4660464  1.8691410   1.319  0.18705    
> Age_Cat>60                1.9010668  2.4512114   0.776  0.43801    
> ---
> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> 
> (Dispersion parameter for binomial family taken to be 1)
> 
>     Null deviance: 740.00  on 575  degrees of freedom
> Residual deviance: 517.29  on 561  degrees of freedom
> AIC: 547.29
> 
> Number of Fisher Scoring iterations: 5

Lakukan feature selection menggunakan stepwise yang berfungsi untuk menghilangkan predictor satu persatu sampai mendapatkan nilai AIC Terendah

model2 <- step(object = model, direction="backward", trace = 0)
summary(model2)
> 
> Call:
> glm(formula = Outcome ~ Glucose + BloodPressure + BMI + DiabetesPedigreeFunction + 
>     Age_Cat, family = binomial, data = train)
> 
> Deviance Residuals: 
>     Min       1Q   Median       3Q      Max  
> -3.0603  -0.6912  -0.3712   0.6827   2.9678  
> 
> Coefficients:
>                           Estimate Std. Error z value Pr(>|z|)    
> (Intercept)              -8.423954   0.825604 -10.203  < 2e-16 ***
> Glucose                   0.036091   0.004156   8.685  < 2e-16 ***
> BloodPressure            -0.009652   0.005929  -1.628 0.103571    
> BMI                       0.082832   0.017043   4.860 1.17e-06 ***
> DiabetesPedigreeFunction  0.975840   0.352484   2.768 0.005632 ** 
> Age_Cat25-30              0.300968   0.334728   0.899 0.368577    
> Age_Cat30-35              1.350286   0.369192   3.657 0.000255 ***
> Age_Cat35-40              1.070794   0.381820   2.804 0.005040 ** 
> Age_Cat40-50              1.450773   0.341591   4.247 2.17e-05 ***
> Age_Cat50-60              0.953620   0.457424   2.085 0.037091 *  
> Age_Cat>60               -0.190051   0.636899  -0.298 0.765397    
> ---
> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
> 
> (Dispersion parameter for binomial family taken to be 1)
> 
>     Null deviance: 740.00  on 575  degrees of freedom
> Residual deviance: 521.91  on 565  degrees of freedom
> AIC: 543.91
> 
> Number of Fisher Scoring iterations: 5
exp(coef(model2))
>              (Intercept)                  Glucose            BloodPressure 
>             0.0002195447             1.0367505821             0.9903948793 
>                      BMI DiabetesPedigreeFunction             Age_Cat25-30 
>             1.0863595163             2.6533954738             1.3511666735 
>             Age_Cat30-35             Age_Cat35-40             Age_Cat40-50 
>             3.8585299013             2.9176965649             4.2664127801 
>             Age_Cat50-60               Age_Cat>60 
>             2.5950879825             0.8269166880

Interpretasi untuk parameter:

Glucose: Kemungkinan seseorang dengan glukosa yang tinggi 1.03 KALI lebih mungkin untuk terindikasi diabetes dengan catatan variabel lainnya memiliki nilai yang sama.

Prediksi Pada Data Train

# prediksikan outcome pada data train

pred_train <- predict(model2, type = "response")
tapply(pred_train, train$Outcome, mean)
>        No       Yes 
> 0.2218039 0.5732809

Confusion Matrix

Informasi pada Confusion Matrix

  • TP (True Positive) = Ketika kita memprediksi kelas positive, dan itu benar

  • TN (True Negative) = Ketika kita memprediksi kelas negative, dan itu benar

  • FP (False Positive) = Ketika kita memprediksi kelas positive, dan itu salah

  • FN (False Negative) = Ketika kita memprediksi kelas negative, dan itu salah

  • Accuracy: seberapa tepat model kita memprediksi kelas target (secara global)

  • Sensitivity/ Recall: ukuran kebaikan model terhadap kelas positif (rujukannya adalah data actual)

  • Specificity: ukuran kebaikan model terhadap kelas negatif

  • Treshold:

Hasil dari model regresi logistik adalah probabilitas. Kita dapat melakukan ini dengan menggunakan nilai ambang t

Jika P(y=1) >= t, prediksi 1 Jika P(y=1) < t, prediksi 0

Treshold 0.3

TH_0.3 <- table(train$Outcome, pred_train > 0.3)
TH_0.3
>      
>       FALSE TRUE
>   No    279  100
>   Yes    33  164
acc_0.3 <- round(sum(diag(TH_0.3))/sum(TH_0.3),2)
sensitivity0.3 <- round(161/(40+161),2)
specificity0.3 <- round(270/(270+105),2)
sprintf("Nilai Akurasi sebesar %s", acc_0.3)
> [1] "Nilai Akurasi sebesar 0.77"
sprintf("Nilai Sensitivitas sebesar %s", sensitivity0.3)
> [1] "Nilai Sensitivitas sebesar 0.8"
sprintf("Nilai Spesifikasi sebesar %s", specificity0.3)
> [1] "Nilai Spesifikasi sebesar 0.72"

Treshold 0.5

TH_0.5 <- table(train$Outcome, pred_train > 0.5)
TH_0.5
>      
>       FALSE TRUE
>   No    338   41
>   Yes    81  116
acc_0.5 <- round(sum(diag(TH_0.5))/sum(TH_0.5),2)
sensitivity0.5 <- round(180/(21+180),2)
specificity0.5 <- round(215/(215+160),2)
sprintf("Nilai Akurasi sebesar %s", acc_0.5)
> [1] "Nilai Akurasi sebesar 0.79"
sprintf("Nilai Sensitivitas sebesar %s", sensitivity0.5)
> [1] "Nilai Sensitivitas sebesar 0.9"
sprintf("Nilai Spesifikasi sebesar %s", specificity0.5)
> [1] "Nilai Spesifikasi sebesar 0.57"

Untuk melihat kebaikan model dalam mendiagnosis penyakit Diabetes dapat dilihat dari Sensitivity/Recall yang menggunakan treshold 0.5 karena menghasilkan nilai sensitivitas sebesar 0.9 dibandingkan dengan menggunakan treshold 0.3 yang hanya menghasilkan sensitivitas sebesar 0.8. Nilai Sensitivity/Recall sendiri artinya, nilai proporsi kasus positif (Diabetes) yang sebenarnya yang diprediksi positif secara benar.

ROC

ROCRprediction = prediction(pred_train, train$Outcome)
ROCRperfomance = performance(ROCRprediction, "tpr", "fpr")

# Adding threshold labels
plot(ROCRperfomance, colorize=TRUE, print.cutoffs.at = seq(0,1,0.1), text.adj = c(-0.2, 1.7))
abline(a=0, b=1)

auc_train <- round(as.numeric(performance(ROCRprediction, "auc")@y.values),2)
legend(.8, .2, auc_train, title = "AUC", cex=1)

Pada area di bawah kurva ROC atau nilai AUC sebesar 86% artinya, menunjukkan model cukup memuaskan.

Prediksi Pada Data Test

pred_test <- predict(model2, type = "response", newdata = test)

# Berdasarkan kurva ROC di atas, dipilih ambang batas 0,5
test_tab <- table(test$Outcome, pred_test > 0.5)
test_tab
>      
>       FALSE TRUE
>   No    113    8
>   Yes    34   37
acc_test <- round(sum(diag(test_tab))/sum(test_tab),2)
sprintf("Nilai Akurasi pada Data Test sebesar %s", acc_test)
> [1] "Nilai Akurasi pada Data Test sebesar 0.78"
# ROC pada Data Test

ROCRPredTest = prediction(pred_test, test$Outcome)
auc = round(as.numeric(performance(ROCRPredTest, "auc")@y.values),2)
sprintf("Nilai AUC pada Data Test sebesar %s", auc)
> [1] "Nilai AUC pada Data Test sebesar 0.84"

AUC pada data test menunjukkan bahwa kemampuan prediksi model baik

Kesimpulan

  1. Semua variabel yang dipilih setelah proses eliminasi menggunakan stepwise menunjukkan P-values lebih rendah dari 0.05 artinya, model signifikan dalam memprediksi penyakit Diabetes.

  2. Model dengan ambang batas yang lebih tinggi memiliki Sensitivitas yang lebih rendah tetapi spesifisitas yang lebih tinggi.

  3. Model dengan ambang batas yang lebih rendah memiliki Sensitivitas yang lebih tinggi tetapi spesifisitas yang lebih rendah.

  4. BMI yang tinggi memiliki resiko 1.07 kali terkena penyakit Diabetes.

  5. Kehamilan, glukosa, tekanan darah, dan Riwayat Keturunan juga berpengaruh dengan terjadinya penyakit Diabetes.

  6. Model diprediksi dengan akurasi 79%. Model ini lebih spesifik daripada sensitif.

  7. Area di bawah kurva ROC adalah 86% yang menunjukkan model cukup memuaskan.

  8. Model yang lebih baik dapat ditingkatkan dengan lebih banyak data.