link dataset : https://www.kaggle.com/datasets/jessemostipak/hotel-booking-demand
install.packages(c("ordinal", "dplyr", "ggplot2"), repos = "https://cloud.r-project.org")
## Installing packages into 'C:/Users/Taufiq/AppData/Local/R/win-library/4.4'
## (as 'lib' is unspecified)
## package 'ordinal' successfully unpacked and MD5 sums checked
## package 'dplyr' successfully unpacked and MD5 sums checked
## Warning: cannot remove prior installation of package 'dplyr'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problem copying
## C:\Users\Taufiq\AppData\Local\R\win-library\4.4\00LOCK\dplyr\libs\x64\dplyr.dll
## to C:\Users\Taufiq\AppData\Local\R\win-library\4.4\dplyr\libs\x64\dplyr.dll:
## Permission denied
## Warning: restored 'dplyr'
## package 'ggplot2' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\Taufiq\AppData\Local\Temp\RtmpwfcHu4\downloaded_packages
library(ordinal)
## Warning: package 'ordinal' was built under R version 4.4.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:ordinal':
##
## slice
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
Baca data dan cek strukturnya
df <- read.csv("C:/Users/Taufiq/Downloads/archive/hotel_bookings.csv")
str(df)
## 'data.frame': 119390 obs. of 32 variables:
## $ hotel : chr "Resort Hotel" "Resort Hotel" "Resort Hotel" "Resort Hotel" ...
## $ is_canceled : int 0 0 0 0 0 0 0 0 1 1 ...
## $ lead_time : int 342 737 7 13 14 14 0 9 85 75 ...
## $ arrival_date_year : int 2015 2015 2015 2015 2015 2015 2015 2015 2015 2015 ...
## $ arrival_date_month : chr "July" "July" "July" "July" ...
## $ arrival_date_week_number : int 27 27 27 27 27 27 27 27 27 27 ...
## $ arrival_date_day_of_month : int 1 1 1 1 1 1 1 1 1 1 ...
## $ stays_in_weekend_nights : int 0 0 0 0 0 0 0 0 0 0 ...
## $ stays_in_week_nights : int 0 0 1 1 2 2 2 2 3 3 ...
## $ adults : int 2 2 1 1 2 2 2 2 2 2 ...
## $ children : int 0 0 0 0 0 0 0 0 0 0 ...
## $ babies : int 0 0 0 0 0 0 0 0 0 0 ...
## $ meal : chr "BB" "BB" "BB" "BB" ...
## $ country : chr "PRT" "PRT" "GBR" "GBR" ...
## $ market_segment : chr "Direct" "Direct" "Direct" "Corporate" ...
## $ distribution_channel : chr "Direct" "Direct" "Direct" "Corporate" ...
## $ is_repeated_guest : int 0 0 0 0 0 0 0 0 0 0 ...
## $ previous_cancellations : int 0 0 0 0 0 0 0 0 0 0 ...
## $ previous_bookings_not_canceled: int 0 0 0 0 0 0 0 0 0 0 ...
## $ reserved_room_type : chr "C" "C" "A" "A" ...
## $ assigned_room_type : chr "C" "C" "C" "A" ...
## $ booking_changes : int 3 4 0 0 0 0 0 0 0 0 ...
## $ deposit_type : chr "No Deposit" "No Deposit" "No Deposit" "No Deposit" ...
## $ agent : chr "NULL" "NULL" "NULL" "304" ...
## $ company : chr "NULL" "NULL" "NULL" "NULL" ...
## $ days_in_waiting_list : int 0 0 0 0 0 0 0 0 0 0 ...
## $ customer_type : chr "Transient" "Transient" "Transient" "Transient" ...
## $ adr : num 0 0 75 75 98 ...
## $ required_car_parking_spaces : int 0 0 0 0 0 0 0 0 0 0 ...
## $ total_of_special_requests : int 0 0 0 0 1 1 0 1 1 0 ...
## $ reservation_status : chr "Check-Out" "Check-Out" "Check-Out" "Check-Out" ...
## $ reservation_status_date : chr "2015-07-01" "2015-07-01" "2015-07-02" "2015-07-02" ...
Hapus baris dengan null pada variabel yang akan digunakan
df_clean <- df %>%
select(adr, lead_time, total_of_special_requests, is_repeated_guest) %>%
na.omit()
Buat variabel target ordinal dari ‘adr’ (average daily rate)
df_clean$rate_level <- cut(df_clean$adr,
breaks = quantile(df_clean$adr, probs = c(0, 0.33, 0.66, 1), na.rm = TRUE),
labels = c("Low", "Medium", "High"),
include.lowest = TRUE,
ordered_result = TRUE)
Pastikan variabel target adalah faktor ordinal
df_clean$rate_level <- factor(df_clean$rate_level, ordered = TRUE)
Standarisasi variabel numerik
df_clean_scaled <- df_clean %>%
mutate(
lead_time = scale(lead_time),
total_of_special_requests = scale(total_of_special_requests)
)
Model regresi logistik ordinal
model_ord_scaled <- clm(rate_level ~ lead_time + total_of_special_requests + is_repeated_guest,
data = df_clean_scaled)
Ringkasan hasil model
summary(model_ord_scaled)
## formula: rate_level ~ lead_time + total_of_special_requests + is_repeated_guest
## data: df_clean_scaled
##
## link threshold nobs logLik AIC niter max.grad cond.H
## logit flexible 119390 -127233.74 254477.49 4(0) 1.01e-09 7.0e+01
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## lead_time -0.136105 0.005486 -24.81 <2e-16 ***
## total_of_special_requests 0.362882 0.005628 64.48 <2e-16 ***
## is_repeated_guest -1.861223 0.037043 -50.24 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Threshold coefficients:
## Estimate Std. Error z value
## Low|Medium -0.791374 0.006411 -123.4
## Medium|High 0.643639 0.006268 102.7
Plot boxplot untuk visualisasi salah satu prediktor terhadap kategori target
ggplot(df_clean, aes(x = rate_level, y = lead_time)) +
geom_boxplot(fill = "lightblue") +
labs(title = "Lead Time vs Rate Level", x = "Rate Level (adr Category)", y = "Lead Time")
Analisis
Model regresi logistik ordinal digunakan untuk menganalisis pengaruh tiga variabel prediktor terhadap tingkat tarif hotel (rate level) yang bersifat ordinal (Low, Medium, High). Variabel independen yang dimasukkan dalam model meliputi lead time (waktu antara pemesanan dan tanggal kedatangan), total_of_special_requests (jumlah permintaan khusus), dan is_repeated_guest (status apakah tamu tersebut pernah menginap sebelumnya). Berdasarkan hasil estimasi model, diketahui bahwa seluruh variabel memiliki pengaruh yang signifikan terhadap pemilihan tingkat tarif, dengan nilai signifikansi p < 0.001 untuk ketiganya.
Secara khusus, variabel lead time memiliki koefisien negatif sebesar -0.136. Hal ini menunjukkan bahwa semakin jauh hari tamu melakukan pemesanan, semakin besar kemungkinan mereka memilih tarif yang lebih rendah. Sebaliknya, variabel total_of_special_requests menunjukkan koefisien positif sebesar 0.363, yang mengindikasikan bahwa tamu dengan lebih banyak permintaan khusus cenderung memilih tarif yang lebih tinggi. Adapun variabel is_repeated_guest memiliki koefisien negatif yang cukup besar, yaitu -1.861, yang berarti tamu yang pernah menginap sebelumnya lebih cenderung memilih tarif yang lebih rendah dibandingkan tamu baru.
Temuan model ini diperkuat oleh hasil visualisasi boxplot antara lead time dan rate level. Tampak bahwa kelompok tamu yang memilih tarif “Low” memiliki median lead time yang lebih tinggi dibandingkan kelompok yang memilih tarif “Medium” dan “High”. Hal ini konsisten dengan koefisien negatif lead time dalam model, menunjukkan bahwa pemesanan yang dilakukan jauh-jauh hari berasosiasi dengan pemilihan tarif yang lebih rendah.
Koefisien ambang (threshold) yang dihasilkan model sebesar -0.791 (Low vs Medium) dan 0.644 (Medium vs High) digunakan sebagai batas internal oleh model untuk menentukan probabilitas transisi antar kategori tarif. Nilai-nilai ini bersifat teknis dan tidak perlu diinterpretasikan secara substantif.
Secara keseluruhan, hasil analisis menunjukkan bahwa tamu yang melakukan pemesanan lebih awal, tidak memiliki banyak permintaan khusus, dan telah menginap sebelumnya, cenderung memilih tarif yang lebih rendah. Sebaliknya, tamu baru dengan banyak permintaan khusus lebih mungkin untuk memilih tarif yang lebih tinggi. Model ini memberikan pemahaman yang penting bagi manajemen hotel dalam menyusun strategi harga dan segmentasi pelanggan secara lebih tepat.