Pendahuluan

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


Import & Eksplorasi Data

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).


Data Cleaning

# Hapus kolom yang tidak penting
data <- data[, !(names(data) %in% c("X", "id"))]

# Rapikan nama kolom
colnames(data) <- make.names(colnames(data))

Penanganan Missing Value

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.


Konversi Tipe Data

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.


Pembentukan Variabel Respons Ordinal

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.


Visualisasi Distribusi Kepuasan

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.


Uji Independensi (Chi-Square)

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.


Uji Multikolinearitas (VIF)

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 Regresi Logistik Ordinal — POLR

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).


Uji Serentak (Likelihood Ratio Test)

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.


Uji Parsial (P-Value Koefisien)

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.

Odds Ratio (POLR)

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:

  • ClassEco (OR = 0,577): Penumpang kelas ekonomi memiliki peluang berada di kategori kepuasan lebih tinggi sebesar 0,58 kali dibanding kelas bisnis, atau sekitar 42% lebih kecil.
  • ClassEco Plus (OR = 0,541): Penumpang kelas ekonomi plus 46% lebih kecil peluangnya berada di kepuasan tinggi dibanding bisnis.
  • Loyal Customer (OR = 1,851): Pelanggan loyal hampir 2 kali lebih mungkin berada di kategori kepuasan lebih tinggi.
  • Personal Travel (OR = 0,666): Penumpang perjalanan pribadi 33% lebih kecil peluangnya berada di kepuasan tinggi dibanding perjalanan bisnis.
  • Age (OR = 1,004): Setiap tambahan satu tahun usia meningkatkan peluang kepuasan tinggi sedikit namun signifikan.

Uji Asumsi Proportional Odds (Brant Test)

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).


Goodness of Fit — POLR

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:

  • McFadden R² = 0,031: Tergolong rendah, menunjukkan bahwa variabel dalam model hanya mampu menjelaskan sebagian kecil variasi kepuasan. Ini wajar mengingat variabel layanan inflight utama tidak dimasukkan langsung sebagai prediktor (hanya dijadikan variabel respons).
  • Nagelkerke R² = 0,073: Konsisten dengan nilai McFadden, model memiliki daya prediksi yang terbatas dengan prediktor demografis dan perjalanan saja.

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.


Generalized Ordinal Logistic Model (GOLM)

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.

Perbandingan Model: POLR vs. GOLM

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.


Evaluasi Prediksi — POLR

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.


Evaluasi Prediksi — GOLM

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.

Linear Discriminant Analysis (LDA)

# 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.

Kesimpulan

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.