Analisis ini bertujuan untuk memodelkan tingkat kepuasan penumpang maskapai penerbangan menggunakan metode Regresi Logistik Ordinal. Kepuasan penumpang merupakan indikator penting dalam menilai kualitas layanan yang diberikan oleh maskapai, serta berpengaruh terhadap loyalitas pelanggan di masa mendatang.
Variabel respons dalam penelitian ini dibentuk dari rata-rata skor layanan inflight yang meliputi wifi, kenyamanan kursi, makanan dan minuman, kebersihan, hiburan, serta layanan on-board. Nilai rata-rata tersebut kemudian dikategorikan menjadi tiga tingkat kepuasan, yaitu Low, Medium, dan High.
Variabel prediktor yang digunakan dalam model meliputi karakteristik penumpang dan perjalanan, yaitu Age, Flight Distance, Class, Customer Type, dan Type of Travel. Variabel-variabel ini dipilih untuk melihat pengaruh faktor demografis dan tipe perjalanan terhadap tingkat kepuasan penumpang.
Data yang digunakan dalam penelitian ini berasal dari dataset Airline Passenger Satisfaction yang tersedia di Kaggle dengan jumlah observasi lebih dari 100.000 data. Tujuan dari analisis ini adalah untuk mengidentifikasi faktor-faktor yang mempengaruhi tingkat kepuasan penumpang serta menentukan model terbaik dalam memodelkan data kepuasan yang bersifat ordinal.
Dataset: https://www.kaggle.com/datasets/teejmahal20/airline-passenger-satisfaction
data <- read.csv("C:/Users/niaay/Downloads/train.csv")
head(data)
## X id Gender Customer.Type Age Type.of.Travel Class
## 1 0 70172 Male Loyal Customer 13 Personal Travel Eco Plus
## 2 1 5047 Male disloyal Customer 25 Business travel Business
## 3 2 110028 Female Loyal Customer 26 Business travel Business
## 4 3 24026 Female Loyal Customer 25 Business travel Business
## 5 4 119299 Male Loyal Customer 61 Business travel Business
## 6 5 111157 Female Loyal Customer 26 Personal Travel Eco
## Flight.Distance Inflight.wifi.service Departure.Arrival.time.convenient
## 1 460 3 4
## 2 235 3 2
## 3 1142 2 2
## 4 562 2 5
## 5 214 3 3
## 6 1180 3 4
## Ease.of.Online.booking Gate.location Food.and.drink Online.boarding
## 1 3 1 5 3
## 2 3 3 1 3
## 3 2 2 5 5
## 4 5 5 2 2
## 5 3 3 4 5
## 6 2 1 1 2
## Seat.comfort Inflight.entertainment On.board.service Leg.room.service
## 1 5 5 4 3
## 2 1 1 1 5
## 3 5 5 4 3
## 4 2 2 2 5
## 5 5 3 3 4
## 6 1 1 3 4
## Baggage.handling Checkin.service Inflight.service Cleanliness
## 1 4 4 5 5
## 2 3 1 4 1
## 3 4 4 4 5
## 4 3 1 4 2
## 5 4 3 3 3
## 6 4 4 4 1
## Departure.Delay.in.Minutes Arrival.Delay.in.Minutes satisfaction
## 1 25 18 neutral or dissatisfied
## 2 1 6 neutral or dissatisfied
## 3 0 0 satisfied
## 4 11 9 neutral or dissatisfied
## 5 0 0 satisfied
## 6 0 0 neutral or dissatisfied
str(data)
## 'data.frame': 103904 obs. of 25 variables:
## $ X : int 0 1 2 3 4 5 6 7 8 9 ...
## $ id : int 70172 5047 110028 24026 119299 111157 82113 96462 79485 65725 ...
## $ Gender : chr "Male" "Male" "Female" "Female" ...
## $ Customer.Type : chr "Loyal Customer" "disloyal Customer" "Loyal Customer" "Loyal Customer" ...
## $ Age : int 13 25 26 25 61 26 47 52 41 20 ...
## $ Type.of.Travel : chr "Personal Travel" "Business travel" "Business travel" "Business travel" ...
## $ Class : chr "Eco Plus" "Business" "Business" "Business" ...
## $ Flight.Distance : int 460 235 1142 562 214 1180 1276 2035 853 1061 ...
## $ Inflight.wifi.service : int 3 3 2 2 3 3 2 4 1 3 ...
## $ Departure.Arrival.time.convenient: int 4 2 2 5 3 4 4 3 2 3 ...
## $ Ease.of.Online.booking : int 3 3 2 5 3 2 2 4 2 3 ...
## $ Gate.location : int 1 3 2 5 3 1 3 4 2 4 ...
## $ Food.and.drink : int 5 1 5 2 4 1 2 5 4 2 ...
## $ Online.boarding : int 3 3 5 2 5 2 2 5 3 3 ...
## $ Seat.comfort : int 5 1 5 2 5 1 2 5 3 3 ...
## $ Inflight.entertainment : int 5 1 5 2 3 1 2 5 1 2 ...
## $ On.board.service : int 4 1 4 2 3 3 3 5 1 2 ...
## $ Leg.room.service : int 3 5 3 5 4 4 3 5 2 3 ...
## $ Baggage.handling : int 4 3 4 3 4 4 4 5 1 4 ...
## $ Checkin.service : int 4 1 4 1 3 4 3 4 4 4 ...
## $ Inflight.service : int 5 4 4 4 3 4 5 5 1 3 ...
## $ Cleanliness : int 5 1 5 2 3 1 2 4 2 2 ...
## $ Departure.Delay.in.Minutes : int 25 1 0 11 0 0 9 4 0 0 ...
## $ Arrival.Delay.in.Minutes : num 18 6 0 9 0 0 23 0 0 0 ...
## $ satisfaction : chr "neutral or dissatisfied" "neutral or dissatisfied" "satisfied" "neutral or dissatisfied" ...
summary(data)
## X id Gender Customer.Type
## Min. : 0 Min. : 1 Length:103904 Length:103904
## 1st Qu.: 25976 1st Qu.: 32534 Class :character Class :character
## Median : 51952 Median : 64857 Mode :character Mode :character
## Mean : 51952 Mean : 64924
## 3rd Qu.: 77927 3rd Qu.: 97368
## Max. :103903 Max. :129880
##
## Age Type.of.Travel Class Flight.Distance
## Min. : 7.00 Length:103904 Length:103904 Min. : 31
## 1st Qu.:27.00 Class :character Class :character 1st Qu.: 414
## Median :40.00 Mode :character Mode :character Median : 843
## Mean :39.38 Mean :1189
## 3rd Qu.:51.00 3rd Qu.:1743
## Max. :85.00 Max. :4983
##
## Inflight.wifi.service Departure.Arrival.time.convenient Ease.of.Online.booking
## Min. :0.00 Min. :0.00 Min. :0.000
## 1st Qu.:2.00 1st Qu.:2.00 1st Qu.:2.000
## Median :3.00 Median :3.00 Median :3.000
## Mean :2.73 Mean :3.06 Mean :2.757
## 3rd Qu.:4.00 3rd Qu.:4.00 3rd Qu.:4.000
## Max. :5.00 Max. :5.00 Max. :5.000
##
## Gate.location Food.and.drink Online.boarding Seat.comfort
## Min. :0.000 Min. :0.000 Min. :0.00 Min. :0.000
## 1st Qu.:2.000 1st Qu.:2.000 1st Qu.:2.00 1st Qu.:2.000
## Median :3.000 Median :3.000 Median :3.00 Median :4.000
## Mean :2.977 Mean :3.202 Mean :3.25 Mean :3.439
## 3rd Qu.:4.000 3rd Qu.:4.000 3rd Qu.:4.00 3rd Qu.:5.000
## Max. :5.000 Max. :5.000 Max. :5.00 Max. :5.000
##
## Inflight.entertainment On.board.service Leg.room.service Baggage.handling
## Min. :0.000 Min. :0.000 Min. :0.000 Min. :1.000
## 1st Qu.:2.000 1st Qu.:2.000 1st Qu.:2.000 1st Qu.:3.000
## Median :4.000 Median :4.000 Median :4.000 Median :4.000
## Mean :3.358 Mean :3.382 Mean :3.351 Mean :3.632
## 3rd Qu.:4.000 3rd Qu.:4.000 3rd Qu.:4.000 3rd Qu.:5.000
## Max. :5.000 Max. :5.000 Max. :5.000 Max. :5.000
##
## Checkin.service Inflight.service Cleanliness Departure.Delay.in.Minutes
## Min. :0.000 Min. :0.00 Min. :0.000 Min. : 0.00
## 1st Qu.:3.000 1st Qu.:3.00 1st Qu.:2.000 1st Qu.: 0.00
## Median :3.000 Median :4.00 Median :3.000 Median : 0.00
## Mean :3.304 Mean :3.64 Mean :3.286 Mean : 14.82
## 3rd Qu.:4.000 3rd Qu.:5.00 3rd Qu.:4.000 3rd Qu.: 12.00
## Max. :5.000 Max. :5.00 Max. :5.000 Max. :1592.00
##
## Arrival.Delay.in.Minutes satisfaction
## Min. : 0.00 Length:103904
## 1st Qu.: 0.00 Class :character
## Median : 0.00 Mode :character
## Mean : 15.18
## 3rd Qu.: 13.00
## Max. :1584.00
## NA's :310
Catatan: Dataset memiliki 103.904 observasi dan 25 variabel. Sebagian besar variabel layanan bertipe integer (skala 0–5).
# Hapus kolom yang tidak penting
data <- data[, !(names(data) %in% c("X", "id"))]
# Rapikan nama kolom
colnames(data) <- make.names(colnames(data))
colSums(is.na(data))
## Gender Customer.Type
## 0 0
## Age Type.of.Travel
## 0 0
## Class Flight.Distance
## 0 0
## Inflight.wifi.service Departure.Arrival.time.convenient
## 0 0
## Ease.of.Online.booking Gate.location
## 0 0
## Food.and.drink Online.boarding
## 0 0
## Seat.comfort Inflight.entertainment
## 0 0
## On.board.service Leg.room.service
## 0 0
## Baggage.handling Checkin.service
## 0 0
## Inflight.service Cleanliness
## 0 0
## Departure.Delay.in.Minutes Arrival.Delay.in.Minutes
## 0 310
## satisfaction
## 0
data <- na.omit(data)
Hanya kolom Arrival.Delay.in.Minutes yang memiliki
missing value (310 baris). Baris tersebut dihapus, sehingga data bersih
tersisa 103.594 observasi.
data$Gender <- as.factor(data$Gender)
data$Customer.Type <- as.factor(data$Customer.Type)
data$Type.of.Travel <- as.factor(data$Type.of.Travel)
data$Class <- as.factor(data$Class)
Variabel Gender, Customer.Type,
Type.of.Travel, dan Class dikonversi menjadi
faktor agar dapat diperlakukan sebagai variabel kategorik dalam
pemodelan.
data$service_score <- rowMeans(data[, c(
"Inflight.wifi.service",
"Seat.comfort",
"Food.and.drink",
"Cleanliness",
"Inflight.entertainment",
"On.board.service"
)])
data$satisfaction_ord <- cut(
data$service_score,
breaks = c(0, 2.5, 3.5, 5),
labels = c("Low", "Medium", "High"),
include.lowest = TRUE,
ordered_result = TRUE
)
table(data$satisfaction_ord)
##
## Low Medium High
## 25819 35650 42125
prop.table(table(data$satisfaction_ord))
##
## Low Medium High
## 0.2492326 0.3441319 0.4066355
Variabel respons ordinal dibentuk dari rata-rata (service_score) enam indikator layanan inflight, kemudian dikategorikan menjadi tiga level: Low (skor 0–2,5), Medium (2,5–3,5), dan High (3,5–5). Hasil distribusi menunjukkan proporsi yang cukup seimbang: Low ~24,9%, Medium ~34,4%, dan High ~40,7%. Distribusi ini mengindikasikan tidak adanya dominasi kelas tunggal yang ekstrem, sehingga pemodelan ordinal dapat dilakukan dengan baik.
ggplot(data, aes(x = satisfaction_ord)) +
geom_bar(fill = c("#e74c3c", "#f39c12", "#2ecc71"), width = 0.6) +
labs(
title = "Distribusi Tingkat Kepuasan Penumpang",
x = "Kategori Kepuasan",
y = "Jumlah Penumpang"
) +
theme_minimal()
Diagram batang memperlihatkan bahwa kategori High memiliki jumlah penumpang terbanyak, diikuti oleh Medium, dan Low. Pola ini mengindikasikan bahwa secara umum penumpang merasa puas terhadap layanan inflight, meskipun masih terdapat sebagian besar penumpang yang menilai layanan di bawah harapan.
chisq.test(table(data$satisfaction_ord, data$Class))
##
## Pearson's Chi-squared test
##
## data: table(data$satisfaction_ord, data$Class)
## X-squared = 5110.9, df = 4, p-value < 2.2e-16
chisq.test(table(data$satisfaction_ord, data$Customer.Type))
##
## Pearson's Chi-squared test
##
## data: table(data$satisfaction_ord, data$Customer.Type)
## X-squared = 1479.5, df = 2, p-value < 2.2e-16
chisq.test(table(data$satisfaction_ord, data$Type.of.Travel))
##
## Pearson's Chi-squared test
##
## data: table(data$satisfaction_ord, data$Type.of.Travel)
## X-squared = 2293.2, df = 2, p-value < 2.2e-16
Uji chi-square dilakukan untuk menguji apakah terdapat hubungan
antara variabel kategorik prediktor dengan tingkat kepuasan. Ketiga
variabel Class, Customer.Type, dan
Type.of.Travelmenghasilkan p-value < 0,001, berarti
terdapat hubungan yang signifikan antara ketiga variabel tersebut dengan
tingkat kepuasan penumpang, sehingga ketiganya layak diikutsertakan
dalam model.
model_vif <- lm(
as.numeric(satisfaction_ord) ~ Age + Flight.Distance,
data = data
)
vif(model_vif)
## Age Flight.Distance
## 1.010068 1.010068
Uji VIF (Variance Inflation Factor) dilakukan terhadap dua variabel
numerik yaitu Age dan Flight.Distance. Kedua
variabel menghasilkan nilai VIF ≈ 1,01, yang jauh di bawah ambang batas
5 (atau 10 sesuai kriteria yang digunakan). Hal ini menunjukkan tidak
ada masalah multikolinearitas di antara prediktor numerik, asumsi ini
terpenuhi dengan baik.
model <- polr(
satisfaction_ord ~
Age +
Flight.Distance +
Class +
Customer.Type +
Type.of.Travel,
data = data,
Hess = TRUE
)
summary(model)
## Call:
## polr(formula = satisfaction_ord ~ Age + Flight.Distance + Class +
## Customer.Type + Type.of.Travel, data = data, Hess = TRUE)
##
## Coefficients:
## Value Std. Error t value
## Age 3.620e-03 4.053e-04 8.932
## Flight.Distance 2.153e-05 8.754e-06 2.459
## ClassEco -5.494e-01 1.626e-02 -33.777
## ClassEco Plus -6.145e-01 2.495e-02 -24.625
## Customer.TypeLoyal Customer 6.158e-01 1.828e-02 33.686
## Type.of.TravelPersonal Travel -4.063e-01 1.688e-02 -24.067
##
## Intercepts:
## Value Std. Error t value
## Low|Medium -0.9032 0.0232 -38.8956
## Medium|High 0.6584 0.0230 28.5953
##
## Residual Deviance: 216706.56
## AIC: 216722.56
Model POLR dibangun menggunakan fungsi polr dari package
MASS dengan asumsi proportional odds. Model ini
meregresikan variabel satisfaction_ord terhadap lima
prediktor: Age, Flight.Distance,
Class, Customer.Type, dan
Type.of.Travel. Output menampilkan estimasi koefisien untuk
setiap prediktor serta dua nilai intercept yang memisahkan ketiga
kategori (Low|Medium dan Medium|High).
model_null <- polr(satisfaction_ord ~ 1, data = data, Hess = TRUE)
anova(model_null, model)
## Likelihood ratio tests of ordinal regression models
##
## Response: satisfaction_ord
## Model Resid. df
## 1 1 103592
## 2 Age + Flight.Distance + Class + Customer.Type + Type.of.Travel 103586
## Resid. Dev Test Df LR stat. Pr(Chi)
## 1 223613.4
## 2 216706.6 1 vs 2 6 6906.885 0
Uji serentak menggunakan Likelihood Ratio Test (LRT) membandingkan model lengkap dengan model null (tanpa prediktor). Hasil menunjukkan nilai statistik LR = 6906,885 dengan df = 6 dan p-value = 0. Keputusan: tolak H₀, artinya secara bersama-sama minimal ada satu variabel prediktor yang berpengaruh signifikan terhadap tingkat kepuasan penumpang.
coef_table <- coef(summary(model))
p_values <- pnorm(abs(coef_table[, "t value"]), lower.tail = FALSE) * 2
coef_table <- cbind(coef_table, p_value = p_values)
coef_table
## Value Std. Error t value
## Age 3.619827e-03 4.052832e-04 8.931598
## Flight.Distance 2.152729e-05 8.754036e-06 2.459127
## ClassEco -5.493615e-01 1.626450e-02 -33.776721
## ClassEco Plus -6.144883e-01 2.495394e-02 -24.624902
## Customer.TypeLoyal Customer 6.158084e-01 1.828111e-02 33.685506
## Type.of.TravelPersonal Travel -4.063328e-01 1.688351e-02 -24.066850
## Low|Medium -9.032170e-01 2.322157e-02 -38.895603
## Medium|High 6.583985e-01 2.302470e-02 28.595309
## p_value
## Age 4.198980e-19
## Flight.Distance 1.392753e-02
## ClassEco 4.333639e-250
## ClassEco Plus 6.836699e-134
## Customer.TypeLoyal Customer 9.424367e-249
## Type.of.TravelPersonal Travel 5.561692e-128
## Low|Medium 0.000000e+00
## Medium|High 7.684492e-180
Karena polr tidak secara otomatis menampilkan p-value,
nilai tersebut dihitung manual menggunakan distribusi normal standar.
Seluruh variabel prediktor signifikan secara statistik (p-value <
0,05):
Age (p ≈ 4,20e-19): Semakin tua usia penumpang, semakin
besar peluang berada di kategori kepuasan lebih tinggi.Flight.Distance (p ≈ 0,014): Jarak penerbangan
berpengaruh signifikan meskipun efeknya sangat kecil.ClassEco dan ClassEco Plus (p ≈ 0):
Penumpang kelas ekonomi dan ekonomi plus memiliki peluang kepuasan lebih
rendah dibanding kelas bisnis.Customer.TypeLoyal Customer (p ≈ 0): Pelanggan loyal
memiliki peluang berada di kategori kepuasan lebih tinggi.Type.of.TravelPersonal Travel (p ≈ 0): Perjalanan
pribadi berkaitan dengan kepuasan yang lebih rendah dibanding perjalanan
bisnis.exp(coef(model))
## Age Flight.Distance
## 1.0036264 1.0000215
## ClassEco ClassEco Plus
## 0.5773183 0.5409176
## Customer.TypeLoyal Customer Type.of.TravelPersonal Travel
## 1.8511524 0.6660884
Nilai odds ratio (OR) diperoleh dengan mengeksponensialkan koefisien model. Beberapa interpretasi kunci:
brant(model)
## --------------------------------------------------------------------
## Test for X2 df probability
## --------------------------------------------------------------------
## Omnibus 485.88 6 0
## Age 296.05 1 0
## Flight.Distance 12.4 1 0
## ClassEco 55.16 1 0
## ClassEco Plus 31.97 1 0
## Customer.TypeLoyal Customer 9.89 1 0
## Type.of.TravelPersonal Travel 122.97 1 0
## --------------------------------------------------------------------
##
## H0: Parallel Regression Assumption holds
Uji Brant digunakan untuk menguji apakah asumsi proportional odds yaitu koefisien yang sama di setiap transisi kategori terpenuhi. Hasil menunjukkan bahwa uji Omnibus menghasilkan p-value < 0,05, yang berarti asumsi proportional odds secara keseluruhan tidak terpenuhi. Pelanggaran ini mengindikasikan bahwa model POLR kurang tepat secara teoritis karena efek prediktor tidak seragam di semua transisi kategori. Oleh karena itu, diperlukan model yang lebih fleksibel, seperti Generalized Ordinal Logistic Model (GOLM).
pR2(model)
## fitting null model for pseudo-r2
## llh llhNull G2 McFadden r2ML
## -1.083533e+05 -1.118067e+05 6.906885e+03 3.088761e-02 6.449860e-02
## r2CU
## 7.292029e-02
Nilai Pseudo R² dari model POLR menunjukkan:
Nilai pseudo R² yang rendah bukan berarti model salah, melainkan mencerminkan bahwa variabel demografis dan tipe perjalanan saja tidak cukup untuk menjelaskan penuh variasi kepuasan yang wajar karena faktor layanan aktual tidak dimasukkan sebagai prediktor.
model_golm <- vglm(
satisfaction_ord ~
Age +
Flight.Distance +
Class +
Customer.Type +
Type.of.Travel,
family = cumulative(parallel = FALSE),
data = data
)
summary(model_golm)
##
## Call:
## vglm(formula = satisfaction_ord ~ Age + Flight.Distance + Class +
## Customer.Type + Type.of.Travel, family = cumulative(parallel = FALSE),
## data = data)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept):1 -7.405e-01 2.757e-02 -26.861 < 2e-16 ***
## (Intercept):2 5.100e-01 2.492e-02 20.464 < 2e-16 ***
## Age:1 -8.649e-03 4.996e-04 -17.313 < 2e-16 ***
## Age:2 2.401e-04 4.571e-04 0.525 0.5994
## Flight.Distance:1 -4.733e-05 9.396e-06 -5.037 4.72e-07 ***
## Flight.Distance:2 -1.336e-05 7.401e-06 -1.806 0.0709 .
## ClassEco:1 6.369e-01 2.023e-02 31.483 < 2e-16 ***
## ClassEco:2 4.835e-01 1.784e-02 27.096 < 2e-16 ***
## ClassEco Plus:1 7.178e-01 2.985e-02 24.050 < 2e-16 ***
## ClassEco Plus:2 5.384e-01 2.807e-02 19.179 < 2e-16 ***
## Customer.TypeLoyal Customer:1 -5.660e-01 2.186e-02 -25.889 < 2e-16 ***
## Customer.TypeLoyal Customer:2 -6.357e-01 2.037e-02 -31.198 < 2e-16 ***
## Type.of.TravelPersonal Travel:1 2.870e-01 2.062e-02 13.920 < 2e-16 ***
## Type.of.TravelPersonal Travel:2 5.108e-01 1.901e-02 26.873 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Names of linear predictors: logitlink(P[Y<=1]), logitlink(P[Y<=2])
##
## Residual deviance: 216186.1 on 207174 degrees of freedom
##
## Log-likelihood: -108093.1 on 207174 degrees of freedom
##
## Number of Fisher scoring iterations: 5
##
##
## Exponentiated coefficients:
## Age:1 Age:2
## 0.9913883 1.0002402
## Flight.Distance:1 Flight.Distance:2
## 0.9999527 0.9999866
## ClassEco:1 ClassEco:2
## 1.8905456 1.6216664
## ClassEco Plus:1 ClassEco Plus:2
## 2.0498695 1.7133110
## Customer.TypeLoyal Customer:1 Customer.TypeLoyal Customer:2
## 0.5677993 0.5295888
## Type.of.TravelPersonal Travel:1 Type.of.TravelPersonal Travel:2
## 1.3323667 1.6665989
GOLM dibangun menggunakan fungsi vglm dari package
VGAM dengan argumen parallel = FALSE, yang
membebaskan setiap koefisien untuk berbeda di masing-masing transisi
kategori. Model ini menghasilkan dua set koefisien: satu untuk transisi
Low -> Medium (label :1) dan satu lagi untuk transisi
Medium -> High (label :2).
Beberapa temuan penting:
Age:1 signifikan (p < 0,001) namun
Age:2 tidak signifikan (p = 0,599): Usia hanya berpengaruh
pada transisi dari Low ke Medium, bukan dari Medium ke High inilah bukti
nyata pelanggaran proportional odds.ClassEco dan ClassEco Plus keduanya
signifikan di kedua transisi, namun dengan magnitude berbeda, yang
konsisten dengan hasil uji Brant.Customer.TypeLoyal Customer dan
Type.of.TravelPersonal Travel signifikan di kedua
transisi.AIC(model)
## [1] 216722.6
AIC(model_golm)
## [1] 216214.1
| Model | AIC |
|---|---|
| POLR | 216.722,56 |
| GOLM | 216.214,10 |
Nilai AIC GOLM lebih rendah dibanding POLR (selisih ≈ 508), yang mengonfirmasi bahwa GOLM lebih sesuai untuk data ini. Penurunan AIC yang substansial menunjukkan bahwa fleksibilitas tambahan GOLM (koefisien berbeda per transisi) memberikan fit yang jauh lebih baik tanpa overfitting yang berlebihan.
pred <- predict(model, data)
pred <- factor(pred, levels = levels(data$satisfaction_ord), ordered = TRUE)
table(Actual = data$satisfaction_ord, Predicted = pred)
## Predicted
## Actual Low Medium High
## Low 4098 10738 10983
## Medium 3815 12533 19302
## High 3171 10258 28696
accuracy_polr <- mean(pred == data$satisfaction_ord)
cat("Akurasi POLR:", round(accuracy_polr * 100, 2), "%\n")
## Akurasi POLR: 43.75 %
Confusion matrix POLR menunjukkan bahwa model cenderung memprediksi kategori High untuk sebagian besar observasi. Akurasi keseluruhan sebesar 43,75% terbilang rendah, yang mengindikasikan bahwa dengan hanya lima prediktor demografis dan tipe perjalanan, model POLR belum mampu membedakan ketiga kategori kepuasan dengan baik.
pred_golm <- predict(model_golm, type = "response")
pred_class <- apply(pred_golm, 1, function(x) {
colnames(pred_golm)[which.max(x)]
})
pred_class <- factor(
pred_class,
levels = levels(data$satisfaction_ord),
ordered = TRUE
)
table(Actual = data$satisfaction_ord, Predicted = pred_class)
## Predicted
## Actual Low Medium High
## Low 6747 7981 11091
## Medium 6418 10026 19206
## High 5451 7909 28765
accuracy_golm <- mean(pred_class == data$satisfaction_ord)
cat("Akurasi GOLM:", round(accuracy_golm * 100, 2), "%\n")
## Akurasi GOLM: 43.96 %
Confusion matrix GOLM menunjukkan pola serupa dengan POLR, namun dengan sedikit peningkatan akurasi menjadi 43,96%. Perbedaan akurasi antara kedua model relatif kecil (~0,2%), yang wajar karena akurasi klasifikasi tidak selalu mencerminkan keunggulan model ordinal. Keunggulan GOLM lebih terlihat dari AIC yang lebih rendah dan kesesuaian teoritis yang lebih baik berdasarkan hasil uji Brant.
# Korelasi antar variabel prediktor
lda_vars <- data[, c(
"Inflight.wifi.service",
"Seat.comfort",
"Food.and.drink",
"Cleanliness",
"Online.boarding",
"Inflight.entertainment"
)]
cor(lda_vars)
## Inflight.wifi.service Seat.comfort Food.and.drink
## Inflight.wifi.service 1.0000000 0.1226168 0.1346027
## Seat.comfort 0.1226168 1.0000000 0.5745609
## Food.and.drink 0.1346027 0.5745609 1.0000000
## Cleanliness 0.1326519 0.6784785 0.6576477
## Online.boarding 0.4570021 0.4200670 0.2344920
## Inflight.entertainment 0.2095132 0.6106142 0.6223738
## Cleanliness Online.boarding Inflight.entertainment
## Inflight.wifi.service 0.1326519 0.4570021 0.2095132
## Seat.comfort 0.6784785 0.4200670 0.6106142
## Food.and.drink 0.6576477 0.2344920 0.6223738
## Cleanliness 1.0000000 0.3314981 0.6917352
## Online.boarding 0.3314981 1.0000000 0.2851945
## Inflight.entertainment 0.6917352 0.2851945 1.0000000
# Cek distribusi (Indikasi Normalitas)
ggplot(data, aes(x = Inflight.wifi.service)) +
geom_histogram(bins = 30, fill = "skyblue") +
theme_minimal()
ggplot(data, aes(x = satisfaction_ord, y = Seat.comfort)) +
geom_boxplot(fill = "lightgreen") +
theme_minimal()
Evaluasi asumsi LDA dilakukan secara eksploratif melalui analisis korelasi antar variabel untuk mendeteksi potensi multikolinearitas serta visualisasi distribusi data menggunakan histogram. Pendekatan ini dianggap cukup untuk memastikan tidak terdapat pelanggaran asumsi yang signifikan sebelum model LDA diterapkan.
# Model LDA
model_lda <- lda(
satisfaction_ord ~
Inflight.wifi.service +
Seat.comfort +
Food.and.drink +
Cleanliness +
Online.boarding +
Inflight.entertainment,
data = data
)
# Prediksi
pred_lda <- predict(model_lda)
pred_class_lda <- pred_lda$class
# Confusion Matrix
table(
Actual = data$satisfaction_ord,
Predicted = pred_class_lda
)
## Predicted
## Actual Low Medium High
## Low 22978 2841 0
## Medium 1510 31639 2501
## High 0 2181 39944
# Akurasi
accuracy_lda <- mean(
as.character(pred_class_lda) == as.character(data$satisfaction_ord)
)
accuracy_lda
## [1] 0.9128038
Hasil: Model Linear Discriminant Analysis menghasilkan akurasi sebesar 91.28%. Hasil confusion matrix menunjukkan bahwa model mampu mengklasifikasikan kelas High dan Low dengan sangat baik, sementara kesalahan lebih banyak terjadi pada kelas Medium yang cenderung overlap dengan kedua kelas lainnya.
Penelitian ini menganalisis faktor-faktor yang memengaruhi tingkat kepuasan penumpang maskapai penerbangan menggunakan Regresi Logistik Ordinal. Hasil analisis menunjukkan bahwa variabel seperti Class, Customer Type, dan Type of Travel berpengaruh signifikan terhadap tingkat kepuasan. Model POLR menghasilkan seluruh prediktor signifikan, namun uji Brant menunjukkan bahwa asumsi proportional odds tidak terpenuhi, sehingga model kurang sesuai secara teoritis. Oleh karena itu digunakan Generalized Ordinal Logistic Model (GOLM) yang lebih fleksibel dalam menangkap perbedaan pengaruh variabel pada setiap transisi kategori.
Hasil perbandingan menunjukkan bahwa GOLM memiliki nilai AIC yang lebih rendah dibandingkan POLR, sehingga menjadi model yang lebih baik untuk data ini. Selain itu, model pembanding Linear Discriminant Analysis (LDA) menghasilkan akurasi yang tinggi, namun tidak mempertimbangkan sifat ordinal dari variabel respon sehingga kurang sesuai secara konsep dibandingkan GOLM. Dengan demikian, GOLM dipilih sebagai model terbaik dalam penelitian ini karena lebih sesuai secara teoritis dan memiliki performa yang lebih baik dalam pemodelan kepuasan penumpang.