This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
summary(cars)
## speed dist
## Min. : 4.0 Min. : 2.00
## 1st Qu.:12.0 1st Qu.: 26.00
## Median :15.0 Median : 36.00
## Mean :15.4 Mean : 42.98
## 3rd Qu.:19.0 3rd Qu.: 56.00
## Max. :25.0 Max. :120.00
You can also embed plots, for example:
Note that the echo = FALSE parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.
hotel <- read.csv("booking.csv/booking.csv")
#Summary Statistics
head(hotel)
## Booking_ID number.of.adults number.of.children number.of.weekend.nights
## 1 INN00001 1 1 2
## 2 INN00002 1 0 1
## 3 INN00003 2 1 1
## 4 INN00004 1 0 0
## 5 INN00005 1 0 1
## 6 INN00006 1 0 0
## number.of.week.nights type.of.meal car.parking.space room.type lead.time
## 1 5 Meal Plan 1 0 Room_Type 1 224
## 2 3 Not Selected 0 Room_Type 1 5
## 3 3 Meal Plan 1 0 Room_Type 1 1
## 4 2 Meal Plan 1 0 Room_Type 1 211
## 5 2 Not Selected 0 Room_Type 1 48
## 6 2 Meal Plan 2 0 Room_Type 1 346
## market.segment.type repeated P.C P.not.C average.price special.requests
## 1 Offline 0 0 0 88.00 0
## 2 Online 0 0 0 106.68 1
## 3 Online 0 0 0 50.00 0
## 4 Online 0 0 0 100.00 1
## 5 Online 0 0 0 77.00 0
## 6 Offline 0 0 0 100.00 1
## date.of.reservation booking.status
## 1 10/2/2015 Not_Canceled
## 2 11/6/2018 Not_Canceled
## 3 2/28/2018 Canceled
## 4 5/20/2017 Canceled
## 5 4/11/2018 Canceled
## 6 9/13/2016 Canceled
dim(hotel)
## [1] 36285 17
str(hotel)
## 'data.frame': 36285 obs. of 17 variables:
## $ Booking_ID : chr "INN00001" "INN00002" "INN00003" "INN00004" ...
## $ number.of.adults : int 1 1 2 1 1 1 1 3 1 2 ...
## $ number.of.children : int 1 0 1 0 0 0 1 0 1 0 ...
## $ number.of.weekend.nights: int 2 1 1 0 1 0 1 1 0 0 ...
## $ number.of.week.nights : int 5 3 3 2 2 2 4 3 4 5 ...
## $ type.of.meal : chr "Meal Plan 1" "Not Selected" "Meal Plan 1" "Meal Plan 1" ...
## $ car.parking.space : int 0 0 0 0 0 0 0 0 0 0 ...
## $ room.type : chr "Room_Type 1" "Room_Type 1" "Room_Type 1" "Room_Type 1" ...
## $ lead.time : int 224 5 1 211 48 346 34 83 121 44 ...
## $ market.segment.type : chr "Offline" "Online" "Online" "Online" ...
## $ repeated : int 0 0 0 0 0 0 0 0 0 0 ...
## $ P.C : int 0 0 0 0 0 0 0 0 0 0 ...
## $ P.not.C : int 0 0 0 0 0 0 0 0 0 0 ...
## $ average.price : num 88 107 50 100 77 ...
## $ special.requests : int 0 1 0 1 0 1 1 1 1 3 ...
## $ date.of.reservation : chr "10/2/2015" "11/6/2018" "2/28/2018" "5/20/2017" ...
## $ booking.status : chr "Not_Canceled" "Not_Canceled" "Canceled" "Canceled" ...
summary(hotel)
## Booking_ID number.of.adults number.of.children number.of.weekend.nights
## Length :36285 Min. :0.000 Min. : 0.0000 Min. :0.0000
## N.unique :36285 1st Qu.:2.000 1st Qu.: 0.0000 1st Qu.:0.0000
## N.blank : 0 Median :2.000 Median : 0.0000 Median :1.0000
## Min.nchar: 8 Mean :1.845 Mean : 0.1054 Mean :0.8107
## Max.nchar: 8 3rd Qu.:2.000 3rd Qu.: 0.0000 3rd Qu.:2.0000
## Max. :4.000 Max. :10.0000 Max. :7.0000
## number.of.week.nights type.of.meal car.parking.space room.type
## Min. : 0.000 Length :36285 Min. :0.00000 Length :36285
## 1st Qu.: 1.000 N.unique : 4 1st Qu.:0.00000 N.unique : 7
## Median : 2.000 N.blank : 0 Median :0.00000 N.blank : 0
## Mean : 2.205 Min.nchar: 11 Mean :0.03098 Min.nchar: 11
## 3rd Qu.: 3.000 Max.nchar: 12 3rd Qu.:0.00000 Max.nchar: 11
## Max. :17.000 Max. :1.00000
## lead.time market.segment.type repeated P.C
## Min. : 0.00 Length :36285 Min. :0.00000 Min. : 0.00000
## 1st Qu.: 17.00 N.unique : 5 1st Qu.:0.00000 1st Qu.: 0.00000
## Median : 57.00 N.blank : 0 Median :0.00000 Median : 0.00000
## Mean : 85.24 Min.nchar: 6 Mean :0.02563 Mean : 0.02334
## 3rd Qu.:126.00 Max.nchar: 13 3rd Qu.:0.00000 3rd Qu.: 0.00000
## Max. :443.00 Max. :1.00000 Max. :13.00000
## P.not.C average.price special.requests date.of.reservation
## Min. : 0.0000 Min. : 0.00 Min. :0.0000 Length :36285
## 1st Qu.: 0.0000 1st Qu.: 80.30 1st Qu.:0.0000 N.unique : 553
## Median : 0.0000 Median : 99.45 Median :0.0000 N.blank : 0
## Mean : 0.1534 Mean :103.42 Mean :0.6197 Min.nchar: 8
## 3rd Qu.: 0.0000 3rd Qu.:120.00 3rd Qu.:1.0000 Max.nchar: 10
## Max. :58.0000 Max. :540.00 Max. :5.0000
## booking.status
## Length :36285
## N.unique : 2
## N.blank : 0
## Min.nchar: 8
## Max.nchar: 12
##
#Data observations
table(hotel$booking.status)
##
## Canceled Not_Canceled
## 11889 24396
prop.table(table(hotel$booking.status))
##
## Canceled Not_Canceled
## 0.3276561 0.6723439
hotel_clean <- hotel %>%
select(
booking.status,
lead.time,
average.price,
special.requests,
repeated,
P.C,
) %>%
filter(
!is.na(booking.status),
!is.na(lead.time),
!is.na(average.price),
!is.na(special.requests),
!is.na(P.C)
) %>%
mutate(
booking.status = factor(
booking.status,
levels = c("Not_Canceled", "Canceled")
),
repeated = factor(repeated,
levels = c(0,1),
labels = c("No", "Yes")
)
)
str(hotel_clean)
## 'data.frame': 36285 obs. of 6 variables:
## $ booking.status : Factor w/ 2 levels "Not_Canceled",..: 1 1 2 2 2 2 1 1 1 1 ...
## $ lead.time : int 224 5 1 211 48 346 34 83 121 44 ...
## $ average.price : num 88 107 50 100 77 ...
## $ special.requests: int 0 1 0 1 0 1 1 1 1 3 ...
## $ repeated : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
## $ P.C : int 0 0 0 0 0 0 0 0 0 0 ...
#Selecting desired variables, removing missing observations, changes variables into appropriate factors
hotel_clean %>%
group_by(booking.status) %>%
summarise(
bookings = n(),
mean_leadtime = mean(lead.time),
mean_roomprice = mean(average.price),
mean_specialrequests = mean(special.requests),
mean_previouscancellations = mean(P.C)
)
## # A tibble: 2 × 6
## booking.status bookings mean_leadtime mean_roomprice mean_specialrequests
## <fct> <int> <dbl> <dbl> <dbl>
## 1 Not_Canceled 24396 58.9 99.9 0.759
## 2 Canceled 11889 139. 111. 0.335
## # ℹ 1 more variable: mean_previouscancellations <dbl>
#Visualization of cancellation counts
ggplot(
hotel_clean,
aes(x = booking.status)
) +
geom_bar() +
labs(
title = "Hotel Reservations by Booking Status",
x = "Booking Status",
y = "Number of Reservations"
) +
theme_minimal()
#Lead time by booking status, comparing canceled and non-canceled
ggplot(
hotel_clean,
aes(x = booking.status, y = lead.time)
) +
geom_boxplot() +
labs(
title = "Lead Time by Booking Status",
x = "Booking Status",
y = "Lead Time (Days)"
) +
theme_minimal()
# Cancellation Status by the Number of requests, comparing proportion of both
ggplot(
hotel_clean,
aes(
x = factor(special.requests),
fill = booking.status
)
) +
geom_bar(position = "fill") +
labs(
title = "Cancellation Status by Number of Special Requests",
x = "Number of Special Requests",
y = "Proportion",
fill = "Booking Status"
) +
theme_minimal()
# logistic model, resulting p-values demonstrate statistically significant results
hotel_model <- glm(
booking.status ~
lead.time +
average.price +
special.requests +
repeated +
P.C,
data = hotel_clean,
family = "binomial"
)
summary(hotel_model)
##
## Call:
## glm(formula = booking.status ~ lead.time + average.price + special.requests +
## repeated + P.C, family = "binomial", data = hotel_clean)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -3.3276294 0.0528570 -62.955 < 2e-16 ***
## lead.time 0.0127696 0.0001770 72.156 < 2e-16 ***
## average.price 0.0187913 0.0004284 43.868 < 2e-16 ***
## special.requests -1.0461837 0.0211591 -49.444 < 2e-16 ***
## repeatedYes -2.8310306 0.3569922 -7.930 2.19e-15 ***
## P.C 0.2452009 0.0637074 3.849 0.000119 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 45901 on 36284 degrees of freedom
## Residual deviance: 34295 on 36279 degrees of freedom
## AIC: 34307
##
## Number of Fisher Scoring iterations: 7
#Confidence Intervals, Odds ratios
confint(hotel_model)
## Waiting for profiling to be done...
## 2.5 % 97.5 %
## (Intercept) -3.43162940 -3.22442865
## lead.time 0.01242430 0.01311804
## average.price 0.01795418 0.01963339
## special.requests -1.08784691 -1.00490229
## repeatedYes -3.59493105 -2.18696962
## P.C 0.11700428 0.36823977
exp(coef(hotel_model))
## (Intercept) lead.time average.price special.requests
## 0.03587806 1.01285149 1.01896895 0.35127578
## repeatedYes P.C
## 0.05895207 1.27787800
exp(confint(hotel_model))
## Waiting for profiling to be done...
## 2.5 % 97.5 %
## (Intercept) 0.03233421 0.0397785
## lead.time 1.01250180 1.0132045
## average.price 1.01811633 1.0198274
## special.requests 0.33694118 0.3660804
## repeatedYes 0.02746258 0.1122564
## P.C 1.12412424 1.4451885
r2 <- 1 -
(hotel_model$deviance / hotel_model$null.deviance)
r2
## [1] 0.2528464
AIC(hotel_model)
## [1] 34307.08
1 - pchisq(
hotel_model$null.deviance - hotel_model$deviance,
df = length(hotel_model$coefficients) - 1
)
## [1] 0
#Confusion Matrix
model_data <- model.frame(hotel_model)
actual_classes <- ifelse(
model_data$booking.status == "Canceled",
1,
0
)
predicted_prob <- hotel_model$fitted.values
predicted_classes <- ifelse(
predicted_prob >= 0.5,
1,
0
)
confusion <- table(
Predicted = factor(predicted_classes, levels = c(0, 1)),
Actual = factor(actual_classes, levels = c(0, 1))
)
confusion
## Actual
## Predicted 0 1
## 0 22021 5684
## 1 2375 6205
TN <- confusion["0", "0"]
FN <- confusion["0", "1"]
FP <- confusion["1", "0"]
TP <- confusion["1", "1"]
accuracy <- (TP + TN) / (TP + TN + FP + FN)
sensitivity <- TP / (TP + FN)
specificity <- TN / (TN + FP)
accuracy
## [1] 0.7778972
sensitivity
## [1] 0.521911
specificity
## [1] 0.902648
library(pROC)
roc_obj <- roc(
response = model_data$booking.status,
predictor = predicted_prob,
levels = c("Not_Canceled", "Canceled"),
direction = "<"
)
auc_value <- auc(roc_obj)
auc_value
## Area under the curve: 0.8232
plot.roc(
roc_obj,
print.auc = TRUE,
legacy.axes = TRUE,
xlab = "False Positive Rate (1 - specificity)",
ylab = "True Positive Rate (sensitivity)"
)