Dalam berbagai bidang penelitian, terutama kesehatan, ekonomi, dan ilmu sosial, sering dijumpai variabel respon yang berbentuk kategori. Pada kondisi seperti ini, metode regresi linear tidak lagi sesuai digunakan karena asumsi normalitas dan sifat kontinu dari variabel respon tidak terpenuhi. Salah satu metode yang dapat digunakan untuk mengatasi permasalahan tersebut adalah regresi logistik.
Regresi logistik merupakan metode statistika yang digunakan untuk memodelkan hubungan antara satu atau lebih variabel prediktor dengan variabel respon kategorik. Metode ini mengestimasi peluang suatu kejadian berdasarkan karakteristik yang dimiliki objek pengamatan.
| Jenis | Variabel Respon | Contoh |
|---|---|---|
| Regresi Logistik Biner | Dua kategori (binary) | Ya / Tidak, Lulus / Tidak Lulus |
| Regresi Logistik Multinomial | Lebih dari dua kategori nominal | Excellent / Incomplete / Indeterminate |
| Regresi Logistik Ordinal | Lebih dari dua kategori ordinal | Rendah < Sedang < Tinggi |
| Regresi Poisson | Data cacahan (count data) | Jumlah kunjungan, Jumlah kecelakaan |
Regresi logistik biner digunakan ketika variabel respon hanya memiliki dua kategori. Model menggunakan fungsi logit:
\[\ln \left(\frac{p}{1-p}\right) = \beta_0+\beta_1X_1+\beta_2X_2+\cdots+\beta_kX_k\]
| Notasi | Keterangan |
|---|---|
| \(p\) | Probabilitas terjadinya kejadian |
| \(\beta_0\) | Intercept model |
| \(\beta_i\) | Koefisien regresi untuk prediktor ke-\(i\) |
| \(X_i\) | Variabel prediktor ke-\(i\) |
| Variabel | Tipe | Keterangan |
|---|---|---|
| duration | Numerik | Durasi panggilan terakhir (detik) |
| balance | Numerik | Saldo rata-rata tahunan |
| campaign | Numerik | Jumlah kontak selama kampanye |
| housing | Kategorik | Kepemilikan kredit rumah |
| poutcome | Kategorik | Hasil kampanye pemasaran sebelumnya |
library(readxl)
data <- read_excel("C:/Users/Lenovo/Downloads/bank.xlsx")
data2 <- data
data2$y <- as.factor(data2$y)
data2$duration <- as.numeric(data2$duration)
data2$balance <- as.numeric(data2$balance)
data2$campaign <- as.numeric(data2$campaign)
data2$housing <- as.factor(data2$housing)
data2$poutcome <- as.factor(data2$poutcome)
str(data2)
## tibble [45,211 × 17] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:45211] 58 44 33 47 33 35 28 42 58 43 ...
## $ job : chr [1:45211] "management" "technician" "entrepreneur" "blue-collar" ...
## $ marital : chr [1:45211] "married" "single" "married" "married" ...
## $ education: chr [1:45211] "tertiary" "secondary" "secondary" "unknown" ...
## $ default : chr [1:45211] "no" "no" "no" "no" ...
## $ balance : num [1:45211] 2143 29 2 1506 1 ...
## $ housing : Factor w/ 2 levels "no","yes": 2 2 2 2 1 2 2 2 2 2 ...
## $ loan : chr [1:45211] "no" "no" "yes" "no" ...
## $ contact : chr [1:45211] "unknown" "unknown" "unknown" "unknown" ...
## $ day : num [1:45211] 5 5 5 5 5 5 5 5 5 5 ...
## $ month : chr [1:45211] "may" "may" "may" "may" ...
## $ duration : num [1:45211] 261 151 76 92 198 139 217 380 50 55 ...
## $ campaign : num [1:45211] 1 1 1 1 1 1 1 1 1 1 ...
## $ pdays : num [1:45211] -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
## $ previous : num [1:45211] 0 0 0 0 0 0 0 0 0 0 ...
## $ poutcome : Factor w/ 4 levels "failure","other",..: 4 4 4 4 4 4 4 4 4 4 ...
## $ y : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
Dataset terdiri dari 45211 observasi dengan 17 variabel.
Distribusi variabel respon: 5289 nasabah berlangganan deposito (yes) dan 39922 nasabah tidak berlangganan (no), sehingga proporsi nasabah yang berlangganan adalah 11.7%.
chr — harus sudah
Factor atau num sebelum masuk model.
model_biner <- glm(
y ~ duration + balance + campaign + housing + poutcome,
data = data2,
family = binomial(link = "logit")
)
summary(model_biner)
##
## Call:
## glm(formula = y ~ duration + balance + campaign + housing + poutcome,
## family = binomial(link = "logit"), data = data2)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.314e+00 5.752e-02 -40.227 < 2e-16 ***
## duration 3.922e-03 6.032e-05 65.021 < 2e-16 ***
## balance 2.489e-05 4.635e-06 5.370 7.86e-08 ***
## campaign -1.101e-01 9.730e-03 -11.321 < 2e-16 ***
## housingyes -1.053e+00 3.627e-02 -29.025 < 2e-16 ***
## poutcomeother 2.693e-01 8.532e-02 3.157 0.0016 **
## poutcomesuccess 2.315e+00 7.555e-02 30.642 < 2e-16 ***
## poutcomeunknown -6.512e-01 5.263e-02 -12.373 < 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: 32631 on 45210 degrees of freedom
## Residual deviance: 23613 on 45203 degrees of freedom
## AIC: 23629
##
## Number of Fisher Scoring iterations: 6
Model regresi logistik biner berhasil dibentuk dengan 8 parameter (termasuk intercept).
Null Deviance sebesar 3.263095^{4} menunjukkan deviasi model tanpa prediktor, sedangkan Residual Deviance sebesar 2.361339^{4} menunjukkan deviasi setelah prediktor dimasukkan. Penurunan deviance sebesar 9017.57 mengindikasikan bahwa prediktor yang digunakan mampu meningkatkan kemampuan model dalam menjelaskan data.
*).
= sangat signifikan (p < 0,001),
= p < 0,01, = p < 0,05.
H₀ : Model sesuai dengan data (tidak ada perbedaan
signifikan antara nilai observasi dan prediksi).
H₁
: Model tidak sesuai dengan data.
Tolak H₀ jika p-value
< 0,05.
hl_test <- hoslem.test(as.numeric(data2$y)-1, fitted(model_biner), g=10)
hl_test
##
## Hosmer and Lemeshow goodness of fit (GOF) test
##
## data: as.numeric(data2$y) - 1, fitted(model_biner)
## X-squared = 466.27, df = 8, p-value < 2.2e-16
Hasil Hosmer-Lemeshow Test menghasilkan statistik uji χ² = 466.2675 dengan derajat bebas 8 dan p-value = 0.
Karena p-value < 0,05, maka H₀ ditolak — model tidak sesuai dengan data, perlu dilakukan perbaikan model.
g=10) berdasarkan
nilai prediksi, lalu membandingkan frekuensi observasi vs ekspektasi per
kelompok.
H₀ : Semua koefisien regresi = 0 (prediktor tidak
berpengaruh).
H₁ : Minimal satu koefisien ≠ 0.
Tolak H₀ jika p-value < 0,05.
anova_biner <- anova(model_biner, test="Chisq")
anova_biner
## Analysis of Deviance Table
##
## Model: binomial, link: logit
##
## Response: y
##
## Terms added sequentially (first to last)
##
##
## Df Deviance Resid. Df Resid. Dev Pr(>Chi)
## NULL 45210 32631
## duration 1 5129.3 45209 27502 < 2.2e-16 ***
## balance 1 84.7 45208 27417 < 2.2e-16 ***
## campaign 1 285.6 45207 27131 < 2.2e-16 ***
## housing 1 1107.2 45206 26024 < 2.2e-16 ***
## poutcome 3 2410.8 45203 23613 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Berdasarkan Likelihood Ratio Test secara simultan, variabel yang memberikan kontribusi signifikan terhadap model adalah: duration, balance, campaign, housing, poutcome.
Penambahan setiap variabel ke dalam model dievaluasi secara bertahap. Variabel yang menghasilkan penurunan deviance dengan p-value < 0,05 terbukti meningkatkan kemampuan prediksi model secara signifikan.
OR_b <- exp(coef(model_biner))
CI_b <- exp(confint(model_biner))
hasil_or <- data.frame(
Variabel = names(OR_b),
Odds_Ratio = round(OR_b, 4),
Lower_CI = round(CI_b[,1], 4),
Upper_CI = round(CI_b[,2], 4)
)
kable(hasil_or, col.names=c("Variabel","Odds Ratio","Lower CI (95%)","Upper CI (95%)"),
align=c("l","c","c","c")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
column_spec(1, bold=TRUE, monospace=TRUE, color="#2F6B3E") |>
column_spec(2, bold=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| Variabel | Odds Ratio | Lower CI (95%) | Upper CI (95%) | |
|---|---|---|---|---|
| (Intercept) | (Intercept) | 0.0989 | 0.0883 | 0.1106 |
| duration | duration | 1.0039 | 1.0038 | 1.0040 |
| balance | balance | 1.0000 | 1.0000 | 1.0000 |
| campaign | campaign | 0.8957 | 0.8785 | 0.9127 |
| housingyes | housingyes | 0.3490 | 0.3250 | 0.3746 |
| poutcomeother | poutcomeother | 1.3091 | 1.1065 | 1.5460 |
| poutcomesuccess | poutcomesuccess | 10.1262 | 8.7377 | 11.7499 |
| poutcomeunknown | poutcomeunknown | 0.5214 | 0.4706 | 0.5784 |
Interpretasi Odds Ratio (OR) menunjukkan perubahan peluang (odds) seorang nasabah berlangganan deposito (yes) dibandingkan tidak berlangganan (no) untuk setiap satu satuan kenaikan prediktor, dengan asumsi variabel lain tetap.
Variabel dengan OR tertinggi adalah poutcomesuccess (OR = 10.1262), artinya setiap kenaikan satu satuan poutcomesuccess meningkatkan odds berlangganan sebesar 912.6%.
Variabel dengan OR terendah adalah housingyes (OR = 0.349), yang artinya setiap kenaikan satu satuan menurunkan odds berlangganan sebesar 65.1%.
pr2_biner <- pR2(model_biner)
## fitting null model for pseudo-r2
pr2_biner
## llh llhNull G2 McFadden r2ML
## -1.180669e+04 -1.631548e+04 9.017569e+03 2.763502e-01 1.808231e-01
## r2CU
## 3.517289e-01
Nilai McFadden Pseudo R² = 0.2764, yang berarti model mampu menjelaskan sekitar 27.6% variasi pada log-likelihood dibandingkan model tanpa prediktor.
Interpretasi: nilai McFadden 0,20–0,40 umumnya dianggap sebagai model dengan fit yang baik. Nilai saat ini menunjukkan model memiliki fit yang baik (0,20–0,40).
aic_biner <- AIC(model_biner)
aic_biner
## [1] 23629.39
Nilai AIC model regresi logistik biner adalah 2.362939^{4}. AIC digunakan untuk membandingkan beberapa model — semakin kecil AIC, semakin baik model. Nilai ini menjadi acuan jika dilakukan seleksi atau perbandingan model alternatif.
prob_b <- predict(model_biner, type="response")
pred_b <- ifelse(prob_b > 0.5, "yes", "no")
cm_b <- table(Aktual=data2$y, Prediksi=pred_b)
kable(as.data.frame.matrix(cm_b), caption="Confusion Matrix — Regresi Logistik Biner") |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=FALSE) |>
row_spec(0, background="#1A3220", color="white")
| no | yes | |
|---|---|---|
| no | 38994 | 928 |
| yes | 3656 | 1633 |
accuracy_b <- mean(pred_b == data2$y)
cat("Accuracy:", round(accuracy_b, 4))
## Accuracy: 0.8986
Model mengklasifikasikan dengan benar sebanyak 40627 dari 45211 observasi.
True Positive (TP): 1633 nasabah diprediksi
yes dan memang yes.
True Negative
(TN): 38994 nasabah diprediksi no dan memang
no.
False Positive (FP): 928 nasabah
diprediksi yes padahal no (kesalahan tipe I).
False Negative (FN): 3656 nasabah diprediksi
no padahal yes (kesalahan tipe II).
Accuracy = 89.86% — model benar dalam 89.86% kasus.
Sensitivity = 30.88% — kemampuan mendeteksi nasabah
yang benar-benar berlangganan.
Specificity = 97.68%
— kemampuan mendeteksi nasabah yang tidak berlangganan.
roc_obj <- roc(response=data2$y, predictor=prob_b, levels=c("no","yes"))
plot(roc_obj,
main="ROC Curve — Regresi Logistik Biner",
col="#2F6B3E", lwd=2.5)
abline(a=0, b=1, lty=2, col="gray60")
auc_val <- auc(roc_obj)
auc_val
## Area under the curve: 0.8756
Nilai AUC (Area Under Curve) = 0.8756.
AUC sebesar 0.8756 berarti model memiliki probabilitas 87.6% untuk memberikan skor lebih tinggi pada nasabah yang benar-benar berlangganan dibandingkan yang tidak. Model ini tergolong baik (Good, AUC 0,80–0,90).
Regresi logistik multinomial memodelkan variabel respon dengan lebih dari dua kategori nominal. Model membentuk \((k-1)\) persamaan logit dibandingkan kategori referensi:
\[\ln \left(\frac{P(Y=j)}{P(Y=ref)}\right) = \beta_{0j}+\beta_{1j}X_1+\cdots+\beta_{pj}X_p, \quad j=1,\ldots,k-1\]
library(nnet)
data_t <- read.csv("C:/Users/Lenovo/Downloads/Thyroid_Diff.csv")
data_t$Response <- as.factor(data_t$Response)
data_t$Gender <- as.factor(data_t$Gender)
data_t$N <- as.factor(data_t$N)
data_t$Smoking <- as.factor(data_t$Smoking)
data_t$Response <- relevel(data_t$Response, ref="Excellent")
kable(as.data.frame(table(data_t$Response)),
col.names=c("Kategori Respon","Frekuensi"), align=c("l","c")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=FALSE) |>
column_spec(1, bold=TRUE, color="#2F6B3E") |>
row_spec(0, background="#1A3220", color="white")
| Kategori Respon | Frekuensi |
|---|---|
| Excellent | 208 |
| Biochemical Incomplete | 23 |
| Indeterminate | 61 |
| Structural Incomplete | 91 |
Dataset terdiri dari 383 observasi. Kategori respon terbanyak adalah Excellent dengan 208 pasien (54.3%), yang menjadi dasar pemilihan kategori ini sebagai referensi. Model akan membentuk 3 persamaan logit yang masing-masing membandingkan kategori lain terhadap Excellent.
barplot(table(data_t$Response),
main="Distribusi Kategori Respons Terapi",
ylab="Frekuensi",
col=c("#1A3220","#3D8B52","#6AAF7A","#A8D5B5"),
border=NA, las=2)
Grafik di atas menunjukkan distribusi frekuensi kategori respons terapi pasien. Ketimpangan distribusi antar kategori perlu diperhatikan karena dapat memengaruhi stabilitas estimasi koefisien pada kategori dengan observasi sedikit.
model_multi <- multinom(
Response ~ Age + Gender + N + Smoking,
data = data_t
)
## # weights: 28 (18 variable)
## initial value 530.950740
## iter 10 value 331.467129
## iter 20 value 327.807321
## final value 327.806194
## converged
summary(model_multi)
## Call:
## multinom(formula = Response ~ Age + Gender + N + Smoking, data = data_t)
##
## Coefficients:
## (Intercept) Age GenderM NN1a NN1b
## Biochemical Incomplete -4.568000 0.04587630 0.1388960 2.316448 1.221233
## Indeterminate -3.030102 0.03419525 0.4967793 2.218744 1.627351
## Structural Incomplete -4.709110 0.04809395 0.7506216 2.971610 4.110625
## SmokingYes
## Biochemical Incomplete 1.4793534
## Indeterminate 0.4083896
## Structural Incomplete 1.5348387
##
## Std. Errors:
## (Intercept) Age GenderM NN1a NN1b
## Biochemical Incomplete 0.7525488 0.01526594 0.7474279 0.8000636 0.7088506
## Indeterminate 0.4992522 0.01090909 0.5094144 0.6102069 0.4502097
## Structural Incomplete 0.6275635 0.01235733 0.5226747 0.6862816 0.4365898
## SmokingYes
## Biochemical Incomplete 0.8073093
## Indeterminate 0.6715223
## Structural Incomplete 0.6425248
##
## Residual Deviance: 655.6124
## AIC: 691.6124
Model regresi logistik multinomial menghasilkan 3 set koefisien, masing-masing untuk perbandingan:
Nilai Residual Deviance = 655.61 dan AIC = 691.61.
H₀ : Model tanpa prediktor sudah cukup (semua
koefisien = 0).
H₁ : Model dengan prediktor lebih
baik.
Tolak H₀ jika p-value < 0,05.
model_null_m <- multinom(Response~1, data=data_t, trace=FALSE)
LR_m <- -2*(as.numeric(logLik(model_null_m))-as.numeric(logLik(model_multi)))
df_m <- attr(logLik(model_multi),"df") - attr(logLik(model_null_m),"df")
pv_m <- pchisq(LR_m, df=df_m, lower.tail=FALSE)
hasil_lrt_m <- data.frame(
Statistik=c("Chi-Square","Derajat Bebas","P-Value"),
Nilai=c(round(LR_m,4), df_m, round(pv_m,6))
)
kable(hasil_lrt_m, col.names=c("Statistik","Nilai"), align=c("l","c")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=FALSE) |>
column_spec(1, bold=TRUE, color="#2F6B3E") |>
row_spec(0, background="#1A3220", color="white")
| Statistik | Nilai |
|---|---|
| Chi-Square | 213.4308 |
| Derajat Bebas | 15.0000 |
| P-Value | 0.0000 |
Likelihood Ratio Test menghasilkan statistik χ² = 213.4308 dengan derajat bebas 15 dan p-value = 0.
Karena p-value < 0,05, maka H₀ ditolak — minimal satu prediktor berpengaruh signifikan terhadap kategori respons terapi. Model dengan prediktor terbukti lebih baik dari model tanpa prediktor.
H₀ : βij = 0 | H₁ :
βij ≠ 0
Variabel dengan p-value < 0,05 berpengaruh
signifikan.
z_m <- summary(model_multi)$coefficients / summary(model_multi)$standard.errors
p_m <- 2*(1-pnorm(abs(z_m)))
kable(round(p_m,4), caption="P-Value Uji Wald Parsial") |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| (Intercept) | Age | GenderM | NN1a | NN1b | SmokingYes | |
|---|---|---|---|---|---|---|
| Biochemical Incomplete | 0 | 0.0027 | 0.8526 | 0.0038 | 0.0849 | 0.0669 |
| Indeterminate | 0 | 0.0017 | 0.3295 | 0.0003 | 0.0003 | 0.5431 |
| Structural Incomplete | 0 | 0.0001 | 0.1510 | 0.0000 | 0.0000 | 0.0169 |
Berdasarkan uji Wald parsial, kombinasi persamaan-variabel yang berpengaruh signifikan (p-value < 0,05) adalah: Biochemical Incomplete ~ (Intercept); Indeterminate ~ (Intercept); Structural Incomplete ~ (Intercept); Biochemical Incomplete ~ Age; Indeterminate ~ Age; Structural Incomplete ~ Age; Biochemical Incomplete ~ NN1a; Indeterminate ~ NN1a; Structural Incomplete ~ NN1a; Indeterminate ~ NN1b; Structural Incomplete ~ NN1b; Structural Incomplete ~ SmokingYes.
Setiap sel pada tabel di atas menunjukkan p-value untuk koefisien prediktor tertentu pada persamaan logit tertentu (kategori vs referensi). Nilai p-value < 0,05 berarti variabel tersebut secara statistik berpengaruh signifikan terhadap log-odds berada di kategori tersebut dibandingkan Excellent.
OR_m <- exp(coef(model_multi))
kable(round(OR_m,4), caption="Odds Ratio Regresi Logistik Multinomial") |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| (Intercept) | Age | GenderM | NN1a | NN1b | SmokingYes | |
|---|---|---|---|---|---|---|
| Biochemical Incomplete | 0.0104 | 1.0469 | 1.1490 | 10.1396 | 3.3914 | 4.3901 |
| Indeterminate | 0.0483 | 1.0348 | 1.6434 | 9.1958 | 5.0904 | 1.5044 |
| Structural Incomplete | 0.0090 | 1.0493 | 2.1183 | 19.5233 | 60.9848 | 4.6406 |
Tabel Odds Ratio di atas menunjukkan perubahan peluang relatif berada di kategori respons tertentu dibandingkan kategori Excellent untuk setiap satu satuan perubahan prediktor.
OR > 1: prediktor meningkatkan peluang berada di
kategori tersebut vs Excellent.
OR < 1:
prediktor menurunkan peluang berada di kategori tersebut vs
Excellent.
OR = 1: prediktor tidak
berpengaruh terhadap perbandingan kategori tersebut vs
Excellent.
pR2(model_multi)
## fitting null model for pseudo-r2
## # weights: 8 (3 variable)
## initial value 530.950740
## final value 434.521594
## converged
## llh llhNull G2 McFadden r2ML r2CU
## -327.8061944 -434.5215938 213.4307989 0.2455929 0.4272240 0.4764994
cat("AIC:", AIC(model_multi))
## AIC: 691.6124
## fitting null model for pseudo-r2
## # weights: 8 (3 variable)
## initial value 530.950740
## final value 434.521594
## converged
Nilai McFadden Pseudo R² = 0.2456, menunjukkan model menjelaskan sekitar 24.6% variasi log-likelihood. Model tergolong baik.
Nilai AIC = 691.61 digunakan sebagai tolok ukur perbandingan jika ada model alternatif — semakin kecil semakin baik.
pred_m <- predict(model_multi)
cm_m <- table(Aktual=data_t$Response, Prediksi=pred_m)
acc_m <- mean(pred_m == data_t$Response)
kable(as.data.frame.matrix(cm_m), caption="Confusion Matrix — Regresi Logistik Multinomial") |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| Excellent | Biochemical Incomplete | Indeterminate | Structural Incomplete | |
|---|---|---|---|---|
| Excellent | 189 | 0 | 4 | 15 |
| Biochemical Incomplete | 14 | 0 | 3 | 6 |
| Indeterminate | 39 | 0 | 7 | 15 |
| Structural Incomplete | 17 | 0 | 3 | 71 |
cat("Accuracy:", round(acc_m,4))
## Accuracy: 0.6971
Model mengklasifikasikan dengan benar 69.71% dari seluruh observasi. Diagonal utama confusion matrix menunjukkan prediksi yang benar untuk setiap kategori. Sel di luar diagonal menunjukkan kesalahan klasifikasi antar kategori.
Perhatikan kategori dengan observasi sedikit — model cenderung lebih sulit mengklasifikasikan kategori minoritas dengan tepat.
Regresi logistik ordinal (Proportional Odds Model) digunakan untuk variabel respon dengan kategori berurutan:
\[\log \left(\frac{P(Y \le j)}{P(Y > j)}\right) = \alpha_j - (\beta_1X_1+\cdots+\beta_kX_k)\]
data_o <- read.csv("C:/Users/Lenovo/Downloads/ObesityDataSet_raw_and_data_sinthetic.csv")
data2_o <- data_o
data2_o$NObeyesdad <- factor(data2_o$NObeyesdad, ordered=TRUE)
str(data2_o)
## 'data.frame': 2111 obs. of 17 variables:
## $ Gender : chr "Female" "Female" "Male" "Male" ...
## $ Age : num 21 21 23 27 22 29 23 22 24 22 ...
## $ Height : num 1.62 1.52 1.8 1.8 1.78 1.62 1.5 1.64 1.78 1.72 ...
## $ Weight : num 64 56 77 87 89.8 53 55 53 64 68 ...
## $ family_history_with_overweight: chr "yes" "yes" "yes" "no" ...
## $ FAVC : chr "no" "no" "no" "no" ...
## $ FCVC : num 2 3 2 3 2 2 3 2 3 2 ...
## $ NCP : num 3 3 3 3 1 3 3 3 3 3 ...
## $ CAEC : chr "Sometimes" "Sometimes" "Sometimes" "Sometimes" ...
## $ SMOKE : chr "no" "yes" "no" "no" ...
## $ CH2O : num 2 3 2 2 2 2 2 2 2 2 ...
## $ SCC : chr "no" "yes" "no" "no" ...
## $ FAF : num 0 3 2 2 0 0 1 3 1 1 ...
## $ TUE : num 1 0 1 0 0 0 0 0 1 1 ...
## $ CALC : chr "no" "Sometimes" "Frequently" "Frequently" ...
## $ MTRANS : chr "Public_Transportation" "Public_Transportation" "Public_Transportation" "Walking" ...
## $ NObeyesdad : Ord.factor w/ 7 levels "Insufficient_Weight"<..: 2 2 2 6 7 2 2 2 2 2 ...
Dataset terdiri dari 2111 observasi. Variabel respon
NObeyesdad bersifat ordinal dengan 7
kategori berurutan: Insufficient_Weight < Normal_Weight
< Obesity_Type_I < Obesity_Type_II < Obesity_Type_III <
Overweight_Level_I < Overweight_Level_II.
library(MASS)
model_ord <- polr(
NObeyesdad ~ Age + Height + Weight + FCVC + FAF,
data=data2_o, Hess=TRUE
)
summary(model_ord)
## Call:
## polr(formula = NObeyesdad ~ Age + Height + Weight + FCVC + FAF,
## data = data2_o, Hess = TRUE)
##
## Coefficients:
## Value Std. Error t value
## Age 0.05349 0.006878 7.776
## Height -4.15456 0.539889 -7.695
## Weight 0.04063 0.002072 19.614
## FCVC -0.44440 0.078116 -5.689
## FAF -0.10139 0.049621 -2.043
##
## Intercepts:
## Value Std. Error t value
## Insufficient_Weight|Normal_Weight -5.7227 0.9081 -6.3016
## Normal_Weight|Obesity_Type_I -4.4169 0.9004 -4.9055
## Obesity_Type_I|Obesity_Type_II -3.3316 0.8990 -3.7058
## Obesity_Type_II|Obesity_Type_III -2.6502 0.8983 -2.9502
## Obesity_Type_III|Overweight_Level_I -1.9887 0.8976 -2.2157
## Overweight_Level_I|Overweight_Level_II -1.1927 0.8993 -1.3262
##
## Residual Deviance: 7624.358
## AIC: 7646.358
Model ordinal menghasilkan 5 koefisien regresi dan 6 threshold (intercept) yang memisahkan antar kategori. Nilai Residual Deviance = 7624.36.
H₀ : Model tanpa prediktor sudah cukup.
H₁ : Model dengan prediktor lebih baik.
Tolak
H₀ jika p-value < 0,05.
model_null_o <- polr(NObeyesdad~1, data=data2_o, Hess=TRUE)
LR_o <- 2*(as.numeric(logLik(model_ord))-as.numeric(logLik(model_null_o)))
df_o <- attr(logLik(model_ord),"df")-attr(logLik(model_null_o),"df")
pv_o <- pchisq(LR_o, df=df_o, lower.tail=FALSE)
hasil_lrt_o <- data.frame(
Statistik=c("Chi-Square","Derajat Bebas","P-Value"),
Nilai=c(round(LR_o,4), df_o, round(pv_o,6))
)
kable(hasil_lrt_o, col.names=c("Statistik","Nilai"), align=c("l","c")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=FALSE) |>
column_spec(1, bold=TRUE, color="#2F6B3E") |>
row_spec(0, background="#1A3220", color="white")
| Statistik | Nilai |
|---|---|
| Chi-Square | 577.2705 |
| Derajat Bebas | 5.0000 |
| P-Value | 0.0000 |
Likelihood Ratio Test menghasilkan χ² = 577.2705, df = 5, p-value = 0.
Karena p-value < 0,05, H₀ ditolak — prediktor secara simultan berpengaruh signifikan terhadap tingkat obesitas. Model dengan prediktor jauh lebih baik dari model tanpa prediktor.
H₀ : βi = 0 | H₁ : βi ≠ 0
ctable_o <- coef(summary(model_ord))
p_o <- 2*pnorm(abs(ctable_o[,"t value"]), lower.tail=FALSE)
hasil_w <- cbind(ctable_o, "p value"=round(p_o,4))
kable(round(hasil_w,4), caption="Hasil Uji Wald Parsial") |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| Value | Std. Error | t value | p value | |
|---|---|---|---|---|
| Age | 0.0535 | 0.0069 | 7.7759 | 0.0000 |
| Height | -4.1546 | 0.5399 | -7.6952 | 0.0000 |
| Weight | 0.0406 | 0.0021 | 19.6144 | 0.0000 |
| FCVC | -0.4444 | 0.0781 | -5.6889 | 0.0000 |
| FAF | -0.1014 | 0.0496 | -2.0433 | 0.0410 |
| Insufficient_Weight|Normal_Weight | -5.7227 | 0.9081 | -6.3016 | 0.0000 |
| Normal_Weight|Obesity_Type_I | -4.4169 | 0.9004 | -4.9055 | 0.0000 |
| Obesity_Type_I|Obesity_Type_II | -3.3316 | 0.8990 | -3.7058 | 0.0002 |
| Obesity_Type_II|Obesity_Type_III | -2.6502 | 0.8983 | -2.9502 | 0.0032 |
| Obesity_Type_III|Overweight_Level_I | -1.9887 | 0.8976 | -2.2157 | 0.0267 |
| Overweight_Level_I|Overweight_Level_II | -1.1927 | 0.8993 | -1.3262 | 0.1848 |
Variabel yang berpengaruh signifikan terhadap tingkat obesitas (p-value < 0,05): Age, Height, Weight, FCVC, FAF.
Variabel yang tidak berpengaruh signifikan: tidak ada.
Baris dengan pemisah | (misal Normal
Weight|Overweight Level I) adalah threshold antar kategori, bukan
koefisien prediktor.
OR_o <- exp(coef(model_ord))
kable(data.frame(Variabel=names(OR_o), Odds_Ratio=round(OR_o,4)),
col.names=c("Variabel","Odds Ratio"), align=c("l","c")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=FALSE) |>
column_spec(1, bold=TRUE, monospace=TRUE, color="#2F6B3E") |>
column_spec(2, bold=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| Variabel | Odds Ratio | |
|---|---|---|
| Age | Age | 1.0549 |
| Height | Height | 0.0157 |
| Weight | Weight | 1.0415 |
| FCVC | FCVC | 0.6412 |
| FAF | FAF | 0.9036 |
Odds Ratio pada regresi ordinal mengukur perubahan cumulative odds berada pada kategori yang lebih tinggi (obesitas lebih berat).
Variabel Age memiliki OR tertinggi sebesar 1.0549 — setiap kenaikan satu satuan meningkatkan odds berada di tingkat obesitas lebih tinggi sebesar 5.5%.
Variabel Height memiliki OR terendah sebesar 0.0157 — setiap kenaikan satu satuan menurunkan odds berada di tingkat obesitas lebih tinggi sebesar 98.4%.
library(pscl)
pR2(model_ord)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML
## -3.812179e+03 -4.100814e+03 5.772705e+02 7.038487e-02 2.392560e-01
## r2CU
## 2.442743e-01
cat("AIC:", AIC(model_ord))
## AIC: 7646.358
## fitting null model for pseudo-r2
McFadden Pseudo R² = 0.0704 — model menjelaskan 7% variasi log-likelihood. Tergolong model perlu ditingkatkan.
AIC = 7646.36 — digunakan sebagai pembanding jika ada model alternatif (mis. dengan penambahan/pengurangan prediktor).
pred_o <- predict(model_ord)
cm_o <- table(Aktual=as.character(data2_o$NObeyesdad),
Prediksi=as.character(pred_o))
acc_o <- mean(as.character(pred_o)==as.character(data2_o$NObeyesdad))
kable(as.data.frame.matrix(cm_o), caption="Confusion Matrix — Regresi Logistik Ordinal") |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| Insufficient_Weight | Normal_Weight | Obesity_Type_I | Overweight_Level_II | |
|---|---|---|---|---|
| Insufficient_Weight | 191 | 79 | 2 | 0 |
| Normal_Weight | 37 | 180 | 69 | 1 |
| Obesity_Type_I | 0 | 1 | 271 | 79 |
| Obesity_Type_II | 0 | 0 | 69 | 228 |
| Obesity_Type_III | 0 | 0 | 15 | 309 |
| Overweight_Level_I | 0 | 68 | 221 | 1 |
| Overweight_Level_II | 0 | 15 | 254 | 21 |
cat("Accuracy:", round(acc_o,4))
## Accuracy: 0.3141
Model ordinal mengklasifikasikan dengan benar 31.41% dari seluruh observasi. Pada model ordinal, kesalahan klasifikasi ke kategori yang berdekatan (misal prediksi Obesity Type I padahal Obesity Type II) umumnya lebih dapat diterima dibandingkan kesalahan ke kategori yang sangat jauh.
Regresi Poisson digunakan untuk data cacah (count data). Model:
\[\log(\mu_i) = \beta_0+\beta_1X_1+\cdots+\beta_kX_k\]
Interpretasi koefisien menggunakan Incidence Rate Ratio (IRR).
data_p <- read.csv("C:/Users/Lenovo/Downloads/hour.csv")
data2_p <- data_p
data2_p$season <- factor(data2_p$season)
data2_p$workingday <- factor(data2_p$workingday)
str(data2_p)
## 'data.frame': 17379 obs. of 17 variables:
## $ instant : int 1 2 3 4 5 6 7 8 9 10 ...
## $ dteday : chr "2011-01-01" "2011-01-01" "2011-01-01" "2011-01-01" ...
## $ season : Factor w/ 4 levels "1","2","3","4": 1 1 1 1 1 1 1 1 1 1 ...
## $ yr : int 0 0 0 0 0 0 0 0 0 0 ...
## $ mnth : int 1 1 1 1 1 1 1 1 1 1 ...
## $ hr : int 0 1 2 3 4 5 6 7 8 9 ...
## $ holiday : int 0 0 0 0 0 0 0 0 0 0 ...
## $ weekday : int 6 6 6 6 6 6 6 6 6 6 ...
## $ workingday: Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
## $ weathersit: int 1 1 1 1 1 2 1 1 1 1 ...
## $ temp : num 0.24 0.22 0.22 0.24 0.24 0.24 0.22 0.2 0.24 0.32 ...
## $ atemp : num 0.288 0.273 0.273 0.288 0.288 ...
## $ hum : num 0.81 0.8 0.8 0.75 0.75 0.75 0.8 0.86 0.75 0.76 ...
## $ windspeed : num 0 0 0 0 0 0.0896 0 0 0 0 ...
## $ casual : int 3 8 5 3 0 0 2 1 1 8 ...
## $ registered: int 13 32 27 10 1 1 0 2 7 6 ...
## $ cnt : int 16 40 32 13 1 1 2 3 8 14 ...
Dataset terdiri dari 17379 observasi. Variabel respon
cnt menunjukkan total penyewaan sepeda per jam, berkisar
antara 1 hingga 977 dengan rata-rata
189.5 dan standar deviasi 181.4.
model_pois <- glm(
cnt ~ temp + hum + windspeed + season + workingday,
data = data2_p,
family = poisson(link="log")
)
summary(model_pois)
##
## Call:
## glm(formula = cnt ~ temp + hum + windspeed + season + workingday,
## family = poisson(link = "log"), data = data2_p)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 4.699984 0.003356 1400.37 <2e-16 ***
## temp 2.251489 0.004690 480.01 <2e-16 ***
## hum -1.418151 0.003139 -451.78 <2e-16 ***
## windspeed 0.232609 0.004708 49.41 <2e-16 ***
## season2 0.123903 0.002178 56.88 <2e-16 ***
## season3 -0.081849 0.002616 -31.29 <2e-16 ***
## season4 0.451716 0.001959 230.55 <2e-16 ***
## workingday1 0.028958 0.001200 24.13 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 2891591 on 17378 degrees of freedom
## Residual deviance: 2046114 on 17371 degrees of freedom
## AIC: 2157031
##
## Number of Fisher Scoring iterations: 5
Model regresi Poisson berhasil dibentuk dengan 8 parameter. Nilai Null Deviance = 2.8915914^{6} dan Residual Deviance = 2.046114^{6}. Penurunan deviance sebesar 8.4547739^{5} mengindikasikan prediktor mampu meningkatkan kemampuan model.
H₀ : Model sesuai dengan data.
H₁
: Model tidak sesuai dengan data.
Tolak H₀ jika p-value
< 0,05.
pv_gof <- pchisq(model_pois$deviance, df=model_pois$df.residual, lower.tail=FALSE)
kable(data.frame(
Statistik=c("Deviance","Derajat Bebas","P-Value"),
Nilai=c(round(model_pois$deviance,4), model_pois$df.residual, round(pv_gof,6))
), col.names=c("Statistik","Nilai"), align=c("l","c")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=FALSE) |>
column_spec(1, bold=TRUE, color="#2F6B3E") |>
row_spec(0, background="#1A3220", color="white")
| Statistik | Nilai |
|---|---|
| Deviance | 2046114 |
| Derajat Bebas | 17371 |
| P-Value | 0 |
Statistik deviance = 2.046114^{6} dengan df = 17371, menghasilkan p-value = 0.
Karena p-value < 0,05, H₀ ditolak — model tidak sesuai dengan data; kemungkinan terdapat overdispersi atau prediktor penting yang belum dimasukkan.
H₀ : Semua koefisien = 0.
H₁ :
Minimal satu koefisien ≠ 0.
model_null_p <- glm(cnt~1, data=data2_p, family=poisson(link="log"))
anova(model_null_p, model_pois, test="Chisq")
## Analysis of Deviance Table
##
## Model 1: cnt ~ 1
## Model 2: cnt ~ temp + hum + windspeed + season + workingday
## Resid. Df Resid. Dev Df Deviance Pr(>Chi)
## 1 17378 2891591
## 2 17371 2046114 7 845477 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Likelihood Ratio Test menghasilkan penurunan deviance sebesar 8.4547739^{5} dengan p-value = 0. Karena p-value < 0,05, H₀ ditolak — secara simultan minimal satu prediktor berpengaruh signifikan terhadap jumlah penyewaan sepeda.
IRR_p <- exp(coef(model_pois))
CI_p <- exp(confint(model_pois))
hasil_IRR <- data.frame(
Variabel = names(IRR_p),
IRR = round(IRR_p,4),
Lower_CI = round(CI_p[,1],4),
Upper_CI = round(CI_p[,2],4)
)
kable(hasil_IRR, col.names=c("Variabel","IRR","Lower CI (95%)","Upper CI (95%)"),
align=c("l","c","c","c")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=TRUE) |>
column_spec(1, bold=TRUE, monospace=TRUE, color="#2F6B3E") |>
column_spec(2, bold=TRUE) |>
row_spec(0, background="#1A3220", color="white")
| Variabel | IRR | Lower CI (95%) | Upper CI (95%) | |
|---|---|---|---|---|
| (Intercept) | (Intercept) | 109.9454 | 109.2244 | 110.6709 |
| temp | temp | 9.5019 | 9.4149 | 9.5896 |
| hum | hum | 0.2422 | 0.2407 | 0.2437 |
| windspeed | windspeed | 1.2619 | 1.2503 | 1.2736 |
| season2 | season2 | 1.1319 | 1.1271 | 1.1367 |
| season3 | season3 | 0.9214 | 0.9167 | 0.9261 |
| season4 | season4 | 1.5710 | 1.5650 | 1.5771 |
| workingday1 | workingday1 | 1.0294 | 1.0270 | 1.0318 |
IRR mengukur perubahan rata-rata jumlah penyewaan sepeda untuk setiap kenaikan satu satuan prediktor, dengan variabel lain dianggap konstan.
Variabel dengan IRR tertinggi adalah temp (IRR = 9.5019) — setiap kenaikan satu satuan meningkatkan rata-rata penyewaan sebesar 850.2%.
Variabel hum memiliki IRR terendah = 0.2422 — setiap kenaikan satu satuan menurunkan rata-rata penyewaan sebesar 75.8%.
Semua CI yang tidak mencakup angka 1 menunjukkan IRR yang signifikan secara statistik.
ll_f <- as.numeric(logLik(model_pois))
ll_n <- as.numeric(logLik(model_null_p))
pr2_p <- 1-(ll_f/ll_n)
aic_p <- AIC(model_pois)
cat("McFadden Pseudo R-Square:", round(pr2_p,4))
## McFadden Pseudo R-Square: 0.2816
cat("\nAIC:", round(aic_p,2))
##
## AIC: 2157031
McFadden Pseudo R² = 0.2816 — model menjelaskan 28.2% variasi log-likelihood. AIC = 2.1570308^{6}.
dispersion_p <- sum(residuals(model_pois, type="pearson")^2) / model_pois$df.residual
kable(data.frame(
Ukuran="Nilai Dispersi",
Nilai=round(dispersion_p,4),
Interpretasi=ifelse(abs(dispersion_p-1)<0.1,"Tidak ada overdispersi (≈ 1)",
ifelse(dispersion_p>1,"Terdapat overdispersi (> 1)","Terdapat underdispersi (< 1)"))
), align=c("l","c","l")) |>
kable_styling(bootstrap_options=c("striped","hover","condensed"), full_width=FALSE) |>
column_spec(1, bold=TRUE, color="#2F6B3E") |>
row_spec(0, background="#1A3220", color="white")
| Ukuran | Nilai | Interpretasi |
|---|---|---|
| Nilai Dispersi | 127.8894 | Terdapat overdispersi (> 1) |
Nilai dispersi Pearson = 127.8894.
Nilai jauh di atas 1 (127.89) — terdapat overdispersi. Varians data lebih besar dari rata-rata, melanggar asumsi Poisson. Disarankan untuk mempertimbangkan model Negative Binomial sebagai alternatif yang lebih robust.
Analisis Data Kategorik — Shabrina Humairoh · 2026-06-02