Group Number:
Group 4
Title:
Machine Learning in Aviation: Predicting Fares and Ticket Classifications
Members:
Khor Kean Teng, Loong Shih-Wai, Nur Maisarah Jalalulail, Pang Suk Min, Tioh Zi Cong
1.1.1 Background
Air travel has become an integral part of modern society with millions of passengers flying for business and leisure. The rapidly expanding airline industry is also considered one of the most sophisticated industries in employing complex pricing strategies. This is because flight fare pricing is dynamic and complex, involving numerous factors such as timing, demand, seasonality, and market conditions. The same airline ticket prices can vary dynamically and significantly, even for nearby seats within the same cabin. Research reports that the same ticket for a specific flight can change up to seven times a day.
Admittedly, flight fare volatility creates uncertainty for both travelers seeking the best deals and airlines optimizing their revenue management. This interplay of goals creates a unique tension: customers are seeking to get the lowest price for their ticket, while airline companies aim to maximize their overall revenue and profit. Mismatches between available seats and passenger demand often lead to customers paying more or airlines losing revenue. While airlines are equipped with advanced tools and capabilities to control the pricing process, customers are also becoming more strategic with the development of online tools that compare prices across various airlines. This evolving dynamic underscores the growing sophistication and challenges in the flight pricing ecosystem.
Recent advancement in machine learning has opened new possibilities for more accurate fare prediction and classification models. Through analyzing vast amount of historical flight fare data, it opens up opportunities to develop predictive models that can forecast flight fares with better accuracy as well as greater transparency and efficiency in airline pricing.
1.1.2 Business Objectives
1.1.3 Business Success Criteria
Accurate prediction of flight-level passenger traffic is of paramount importance in airline operations, influencing key decisions from pricing to route optimization (Ehsani et al., 2024). However, forecasting flight fares is a critical tasks in the rapidly expanding aviation industry as it involves numerous factors. Nowadays, aviation industry adopt dynamic pricing to assign airfare prices utilizing complex strategies and methods involving financial, marketing, commercial and social factors.
The high complexity in airfare pricing models make it very difficult for customer to purchase an air ticket in the lowest price since the price changes dynamically. According to a (Abdella et al., 2021), the same ticket price for a specific flight can change up to 7 times a day, presenting a complex predictive modeling opportunities. The best time to buy a ticket is a key issue subjected to research. Various predictions models to optimize airline ticket purchasing have been proposed and achieved promising results. (Subramanian et al., 2022) proposed the use of machine learning algorithms in airline fare prediction utilizing various regression algorithms such as KNN, Linear Regresssion, Lasso, Ridge, Decision Tree, Stacking Tree and Random Forest on scaped data from MakeMyTrip, Data World and New Zealand Domestic airlines. The research results R2 score ranges from 60.24% to 83.83%; 27.95% to 84.46%; 37.16% to 81.89% highlighting the complex and nonlinear relationships of multiple factors in airline fare prediction. However, the data used on cover specific airports limited to certain time period, thus limited the result generalizability and practicality.
(Tziridis et al., 2017) proposed a comparative study using data from the Aegean Airlines using MLP, GRNN, ELM, RF, Regression Tree, Bagging Regression Tree, SVM and LR. The research outcome ranges from 49.40% to 87.42%, improvement is made with feature selection from 57.07% to 87.59%. Nonetheless, the research lacks practicality where only 1814 data flights collected in period between December and July is used for training, thus limiting the findings application to a broader cases and demographics.
Recent advancement in deep learning also ushered in novel forecasting approach in flight fare prediction. (Degife and Lin, 2023) suggested the use of gated recurrent unit, GRU and achieved a remarkable 98% R2 score and 5.93 RMSE representing a significant advacement in prediction accuracy. Nevertheless, the use of deep learning architecture can be computational intensive during the model training stage.
Above all, the landscape of flight fare prediction demonstrates significant potential and ongoing challenges. Despite the promising advancements in machine learning and deep learning techniques, current research is constrained by limited dataset generalizability, regional specificity, and computational intensity. Future research could emphasize on the development of more comprehensive, robust models that can integrate diverse data sources, encompass broader geographic regions, and balance predictive accuracy with computational efficiency. Moreover, interdisciplinary approaches that combine machine learning algorithms with domain expertise from aviation economics, marketing, and social sciences could provide more nuanced and adaptable fare prediction models, ultimately benefiting both airlines and passengers by offering more transparent and optimized pricing strategies.
The project make use of CRISP-DM framework to streamline the project workflows. R language will be used for data processing, modeling and evaluation tasks. The report for the project will then be written in RMarkdown and published on RPubs.
###2.1 Collect Initial Data
# clear workspace variables
rm(list = ls())
# set-up: turn off warnings and set plot size
options(warn = -1)
options(repr.plot.width = 10, repr.plot.height = 5)
# set working directory
setwd("C:/Users/Khor Kean Teng/Downloads/rpubs_prog_ds")
# install the required packages
packages <- c("caret", "e1071", "tidyverse", "tidyr", "readr", "randomForest", "class", "nnet", "corrplot", "glmnet")
# Get the list of currently installed packages
installed_packages <- as.data.frame(installed.packages())['Package']
# Function to check and install missing packages
install_if_missing <- function(pkg) {
if (!(pkg %in% installed_packages$Package)) {
suppressMessages(install.packages(pkg))
}
}
# Apply the function to each package in the vector
sapply(packages, install_if_missing)
## $caret
## NULL
##
## $e1071
## NULL
##
## $tidyverse
## NULL
##
## $tidyr
## NULL
##
## $readr
## NULL
##
## $randomForest
## NULL
##
## $class
## NULL
##
## $nnet
## NULL
##
## $corrplot
## NULL
##
## $glmnet
## NULL
# import packages
suppressPackageStartupMessages({
# add the required packages here
library(tidyr)
library(readr)
library(tidyverse)
library(caret)
library(e1071)
library(randomForest)
library(class)
library(nnet)
library(corrplot)
library(glmnet)
})
# Download the dataset
system("kaggle datasets download yashdharme36/airfare-ml-predicting-flight-fares")
## [1] 0
cat("Data loaded...\n")
## Data loaded...
unzip("airfare-ml-predicting-flight-fares.zip")
cat("Done unzip...\n")
## Done unzip...
# first 5 rows of the data
data <- read_csv('Cleaned_dataset.csv', show_col_types = FALSE)
head(data, 5)
## # A tibble: 5 × 13
## Date_of_journey Journey_day Airline Flight_code Class Source Departure
## <date> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 2023-01-16 Monday SpiceJet SG-8169 Economy Delhi After 6 PM
## 2 2023-01-16 Monday Indigo 6E-2519 Economy Delhi After 6 PM
## 3 2023-01-16 Monday GO FIRST G8-354 Economy Delhi After 6 PM
## 4 2023-01-16 Monday SpiceJet SG-8709 Economy Delhi After 6 PM
## 5 2023-01-16 Monday Air India AI-805 Economy Delhi After 6 PM
## # ℹ 6 more variables: Total_stops <chr>, Arrival <chr>, Destination <chr>,
## # Duration_in_hours <dbl>, Days_left <dbl>, Fare <dbl>
cat("The dimension of the dataset is", dim(data)[1], "rows and", dim(data)[2], "columns.\n")
## The dimension of the dataset is 452088 rows and 13 columns.
# Variables list with type
str(head(data))
## tibble [6 × 13] (S3: tbl_df/tbl/data.frame)
## $ Date_of_journey : Date[1:6], format: "2023-01-16" "2023-01-16" ...
## $ Journey_day : chr [1:6] "Monday" "Monday" "Monday" "Monday" ...
## $ Airline : chr [1:6] "SpiceJet" "Indigo" "GO FIRST" "SpiceJet" ...
## $ Flight_code : chr [1:6] "SG-8169" "6E-2519" "G8-354" "SG-8709" ...
## $ Class : chr [1:6] "Economy" "Economy" "Economy" "Economy" ...
## $ Source : chr [1:6] "Delhi" "Delhi" "Delhi" "Delhi" ...
## $ Departure : chr [1:6] "After 6 PM" "After 6 PM" "After 6 PM" "After 6 PM" ...
## $ Total_stops : chr [1:6] "non-stop" "non-stop" "non-stop" "non-stop" ...
## $ Arrival : chr [1:6] "After 6 PM" "Before 6 AM" "Before 6 AM" "After 6 PM" ...
## $ Destination : chr [1:6] "Mumbai" "Mumbai" "Mumbai" "Mumbai" ...
## $ Duration_in_hours: num [1:6] 2.08 2.33 2.17 2.08 2.17 ...
## $ Days_left : num [1:6] 1 1 1 1 1 1
## $ Fare : num [1:6] 5335 5899 5801 5794 5955 ...
# Segregate variables to type
float_columns <- names(data)[sapply(data, function(x) is.numeric(x) & !is.integer(x))]
string_columns <- names(data)[sapply(data, is.character)]
datetime_columns <- names(data)[sapply(data, function(x) inherits(x, "POSIXct") | inherits(x, "Date"))]
cat("Float columns:", paste(float_columns, collapse = ", "), "\n")
## Float columns: Duration_in_hours, Days_left, Fare
cat("String columns:", paste(string_columns, collapse = ", "), "\n")
## String columns: Journey_day, Airline, Flight_code, Class, Source, Departure, Total_stops, Arrival, Destination
cat("Datetime columns:", paste(datetime_columns, collapse = ", "), "\n")
## Datetime columns: Date_of_journey
# Check unique values for each column in the dataset
unique_values <- lapply(data, unique)
# Statistical summary of dataset
summary(data)
## Date_of_journey Journey_day Airline Flight_code
## Min. :2023-01-16 Length:452088 Length:452088 Length:452088
## 1st Qu.:2023-01-28 Class :character Class :character Class :character
## Median :2023-02-10 Mode :character Mode :character Mode :character
## Mean :2023-02-09
## 3rd Qu.:2023-02-22
## Max. :2023-03-06
## Class Source Departure Total_stops
## Length:452088 Length:452088 Length:452088 Length:452088
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## Arrival Destination Duration_in_hours Days_left
## Length:452088 Length:452088 Min. : 0.750 Min. : 1.00
## Class :character Class :character 1st Qu.: 6.583 1st Qu.:13.00
## Mode :character Mode :character Median :11.333 Median :26.00
## Mean :12.349 Mean :25.63
## 3rd Qu.:16.500 3rd Qu.:38.00
## Max. :43.583 Max. :50.00
## Fare
## Min. : 1307
## 1st Qu.: 8763
## Median : 13407
## Mean : 22840
## 3rd Qu.: 35587
## Max. :143019
summary(data$Fare)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1307 8763 13407 22840 35587 143019
# Histogram for fare
ggplot(data, aes(x = Fare)) + geom_histogram(binwidth = 10, fill = "skyblue", color = "black") +
labs(title = "Distribution of Flight Fare", x = "Fare", y = "Frequency") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Days left
summary(data$Days_left)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 13.00 26.00 25.63 38.00 50.00
# Histogram for fare
ggplot(data, aes(x = Days_left)) + geom_histogram(binwidth = 10, fill = "skyblue", color = "black") +
labs(title = "Distribution of Days Left", x = "Days between Booking day and Flight day", y = "Frequency") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Journey Day - histogram
ggplot(data, aes(x = Journey_day)) + geom_bar(binwidth = 10, fill = "plum", color = "black") +
labs(title = "Journey Day", x = "Journey Day", y = "Frequency") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Journey Month
ggplot(data, aes(x = lubridate::month(Date_of_journey, label = TRUE))) +
geom_bar(fill = "palevioletred", color = "black") +
labs(title = "Frequency of Journey by Month", x = "Month of Journey", y = "Count") +
theme_minimal() +
theme(
plot.title = element_text(size = 18, face = "bold"),
axis.title.x = element_text(size = 14, face = "bold"),
axis.title.y = element_text(size = 14, face = "bold"),
axis.text = element_text(size = 12)
)
# Airline - histogram
ggplot(data, aes(x = Airline)) + geom_bar(binwidth = 10, fill = "turquoise", color = "black") +
labs(title = "Airline Frequency", x = "Airline", y = "Frequency") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Class - histogram
ggplot(data, aes(x = Class)) + geom_bar(binwidth = 10, fill = "lightpink", color = "black") +
labs(title = "Types of Classes", x = "Class", y = "Frequency") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Fare with Journey Day
ggplot(data, aes(x = Journey_day, y = Fare)) + geom_boxplot(fill = "lightcyan") +
labs(title = "Fare Distribution by Journey Day", x = "Journey Day", y = "Fare") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Fare with Airline
ggplot(data, aes(x = Airline, y = Fare)) + geom_boxplot(fill = "turquoise") +
labs(title = "Fare Distribution by Airline", x = "Airline", y = "Fare") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Fare with Class
ggplot(data, aes(x = Class, y = Fare)) + geom_boxplot(fill = "lightpink") +
labs(title = "Fare Distribution by Class", x = "Class", y = "Fare") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Class with duration of hours
ggplot(data, aes(x = Class, y = Duration_in_hours)) + geom_boxplot(fill = "lightpink") +
labs(title = "Duration of Flight by Class", x = "Class", y = "Duration in hours") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 16, angle = 45, hjust = 1),
axis.text.y = element_text(size = 16) )
# Fare with Days Left
data$days_left_group <- cut(data$Days_left, breaks = c(0, 7, 14, 30, 60, 90, Inf),
labels = c("0-7 days", "8-14 days", "15-30 days", "31-60 days", "61-90 days", "90+ days"))
ggplot(data, aes(x = days_left_group, y = Fare)) +
geom_boxplot(fill = "khaki") +
labs(title = "Fare Prices by Days Left Intervals", x = "Days Left Interval", y = "Fare") +
theme_minimal() +
theme(
plot.title = element_text(size = 18, face = "bold"),
axis.title.x = element_text(size = 14, face = "bold"),
axis.title.y = element_text(size = 14, face = "bold"),
axis.text.x = element_text(size = 12, angle = 45, hjust = 1)
)
# Average Fare with days left
avg_fare_by_days <- data %>% group_by(Days_left) %>% summarise(avg_fare = mean(Fare, na.rm = TRUE))
ggplot(avg_fare_by_days, aes(x = Days_left, y = avg_fare)) +
geom_line(color = "blue", size = 1) +
labs(title = "Average Fare vs. Days Left", x = "Days Left", y = "Average Fare") +
theme_minimal() +
theme(
plot.title = element_text(size = 18, face = "bold"),
axis.title.x = element_text(size = 14, face = "bold"),
axis.title.y = element_text(size = 14, face = "bold"),
axis.text = element_text(size = 12)
)
# Grouping by the extracted month from Date_of_journey and calculating average fare
avg_fare_by_month <- data %>%
group_by(Month_of_journey = lubridate::month(Date_of_journey, label = TRUE)) %>%
summarise(avg_fare = mean(Fare, na.rm = TRUE))
# Plotting the relationship
# Plotting the relationship with proper grouping
ggplot(avg_fare_by_month, aes(x = Month_of_journey, y = avg_fare, group = 1)) +
geom_line(color = "hotpink", size = 1) +
geom_point(color = "blue", size = 2) +
labs(title = "Average Fare vs. Month of Journey", x = "Month of Journey", y = "Average Fare") +
theme_minimal() +
theme(
plot.title = element_text(size = 18, face = "bold"),
axis.title.x = element_text(size = 14, face = "bold"),
axis.title.y = element_text(size = 14, face = "bold"),
axis.text = element_text(size = 12)
)
numeric_data <- data[sapply(data, is.numeric)]
cor_matrix <- cor(numeric_data)
print(cor_matrix)
## Duration_in_hours Days_left Fare
## Duration_in_hours 1.00000000 -0.03287841 0.17990877
## Days_left -0.03287841 1.00000000 -0.08785164
## Fare 0.17990877 -0.08785164 1.00000000
corrplot(cor_matrix, method = "circle", type = "upper", tl.col = "black", tl.srt = 30,col = colorRampPalette(c("green", "pink", "blue"))(200))
# Facet Grid for Fare by Airline and Duration with Total Stops
ggplot(data, aes(x = Duration_in_hours, y = Total_stops, color = Fare)) +
geom_point(alpha = 0.6) +
facet_wrap(~ Airline) +
labs(title = "Fare by Airline, Duration, and Total Stops", x = "Duration in Hours", y = "Total Stops") +
scale_color_gradient(low = "blue", high = "red")
# Count of missing values in each column
colSums(is.na(data))
## Date_of_journey Journey_day Airline Flight_code
## 0 0 0 0
## Class Source Departure Total_stops
## 0 0 0 0
## Arrival Destination Duration_in_hours Days_left
## 0 0 0 0
## Fare days_left_group
## 0 0
# Check rows with missing values
missing_rows <- data[!complete.cases(data), ]
print(missing_rows)
## # A tibble: 0 × 14
## # ℹ 14 variables: Date_of_journey <date>, Journey_day <chr>, Airline <chr>,
## # Flight_code <chr>, Class <chr>, Source <chr>, Departure <chr>,
## # Total_stops <chr>, Arrival <chr>, Destination <chr>,
## # Duration_in_hours <dbl>, Days_left <dbl>, Fare <dbl>, days_left_group <fct>
# Check for duplicate rows
duplicate_rows <- data[duplicated(data), ]
if (nrow(duplicate_rows) == 0) {
print("There is no duplicate row.")
} else {
print("Duplicate Rows:")
print(duplicate_rows)
}
## [1] "Duplicate Rows:"
## # A tibble: 6,722 × 14
## Date_of_journey Journey_day Airline Flight_code Class Source Departure
## <date> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 2023-01-16 Monday Vistara UK-627 Economy Delhi 12 PM - …
## 2 2023-01-16 Monday Vistara UK-627 Premium Eco… Delhi 12 PM - …
## 3 2023-01-16 Monday Vistara UK-627 Premium Eco… Delhi 12 PM - …
## 4 2023-01-17 Tuesday Vistara UK-929 Economy Delhi After 6 …
## 5 2023-01-17 Tuesday Vistara UK-627 Premium Eco… Delhi 12 PM - …
## 6 2023-01-18 Wednesday Vistara UK-975 Economy Delhi Before 6…
## 7 2023-01-18 Wednesday Vistara UK-951 Economy Delhi 12 PM - …
## 8 2023-01-18 Wednesday Vistara UK-993 Economy Delhi 12 PM - …
## 9 2023-01-18 Wednesday Vistara UK-945 Economy Delhi 6 AM - 1…
## 10 2023-01-18 Wednesday Vistara UK-995 Economy Delhi 6 AM - 1…
## # ℹ 6,712 more rows
## # ℹ 7 more variables: Total_stops <chr>, Arrival <chr>, Destination <chr>,
## # Duration_in_hours <dbl>, Days_left <dbl>, Fare <dbl>, days_left_group <fct>
# Verify data quality
verify_data_quality <- function(data) {
# 1. Check if 'Date_of_journey' is in the correct format (YYYY-MM-DD)
data$Date_of_journey <- as.Date(data$Date_of_journey, format = "%Y-%m-%d")
invalid_dates <- sum(is.na(data$Date_of_journey)) # Count invalid dates
# 2. Check if 'Duration_in_hours' contains non-negative values
negative_duration <- sum(data$Duration_in_hours < 0, na.rm = TRUE) # Count negative durations
# 3. Check if 'Days_left' contains non-negative values
negative_days_left <- sum(data$Days_left < 0, na.rm = TRUE) # Count negative days left
# Output the results
cat("Data Quality Check Results:\n")
# Invalid date check
if (invalid_dates > 0) {
cat(paste(invalid_dates, "rows have invalid date format in 'Date_of_journey'.\n"))
} else {
cat("All dates in 'Date_of_journey' are in the correct format.\n")
}
# Negative duration check
if (negative_duration > 0) {
cat(paste(negative_duration, "rows have negative values in 'Duration_in_hours'.\n"))
} else {
cat("All values in 'Duration_in_hours' are non-negative.\n")
}
# Negative days left check
if (negative_days_left > 0) {
cat(paste(negative_days_left, "rows have negative values in 'Days_left'.\n"))
} else {
cat("All values in 'Days_left' are non-negative.\n")
}
}
verify_data_quality(data)
## Data Quality Check Results:
## All dates in 'Date_of_journey' are in the correct format.
## All values in 'Duration_in_hours' are non-negative.
## All values in 'Days_left' are non-negative.
glimpse(data)
## Rows: 452,088
## Columns: 14
## $ Date_of_journey <date> 2023-01-16, 2023-01-16, 2023-01-16, 2023-01-16, 202…
## $ Journey_day <chr> "Monday", "Monday", "Monday", "Monday", "Monday", "M…
## $ Airline <chr> "SpiceJet", "Indigo", "GO FIRST", "SpiceJet", "Air I…
## $ Flight_code <chr> "SG-8169", "6E-2519", "G8-354", "SG-8709", "AI-805",…
## $ Class <chr> "Economy", "Economy", "Economy", "Economy", "Economy…
## $ Source <chr> "Delhi", "Delhi", "Delhi", "Delhi", "Delhi", "Delhi"…
## $ Departure <chr> "After 6 PM", "After 6 PM", "After 6 PM", "After 6 P…
## $ Total_stops <chr> "non-stop", "non-stop", "non-stop", "non-stop", "non…
## $ Arrival <chr> "After 6 PM", "Before 6 AM", "Before 6 AM", "After 6…
## $ Destination <chr> "Mumbai", "Mumbai", "Mumbai", "Mumbai", "Mumbai", "M…
## $ Duration_in_hours <dbl> 2.0833, 2.3333, 2.1667, 2.0833, 2.1667, 2.2500, 2.25…
## $ Days_left <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ Fare <dbl> 5335, 5899, 5801, 5794, 5955, 5955, 5955, 5899, 5829…
## $ days_left_group <fct> 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-…
Duplicate rows removed.
# Remove duplicate rows
data <- data[!duplicated(data), ]
# Count of removed duplicate rows
cat("Number of removed duplicate rows:", nrow(duplicate_rows), "\n")
## Number of removed duplicate rows: 6722
Handle missing values
# For simplicity, we can remove rows with missing values
data <- na.omit(data)
# Count of rows removed with missing values in field
cat("Number of removed rows with missing values:", nrow(missing_rows), "\n")
## Number of removed rows with missing values: 0
Removed first class since the count of data lines are insignificant, seen from the initial EDA
first_class_rows <- nrow(data %>% filter(Class == "First"))
cat("Number of rows in First class:", first_class_rows, "\n")
## Number of rows in First class: 144
# Remove rows of first class
data <- data %>% filter(Class != "First")
# Count of rows removed with first class
cat("Number of removed rows with first class:", first_class_rows, "\n")
## Number of removed rows with first class: 144
Removing columns: Flight_code, arrival, duration_in_hours
# Remove columns: Flight_code, arrival, duration_in_hours, duration_category, and fare_per_hour
data <- data %>% select(-Flight_code, -Arrival, -Duration_in_hours)
Verify data quality after cleaning and look at the data.
# Verify data quality again after cleaning
verify_data_quality(data)
## Data Quality Check Results:
## All dates in 'Date_of_journey' are in the correct format.
## All values in 'Duration_in_hours' are non-negative.
## All values in 'Days_left' are non-negative.
# Display the cleaned data
glimpse(data)
## Rows: 445,222
## Columns: 11
## $ Date_of_journey <date> 2023-01-16, 2023-01-16, 2023-01-16, 2023-01-16, 2023-…
## $ Journey_day <chr> "Monday", "Monday", "Monday", "Monday", "Monday", "Mon…
## $ Airline <chr> "SpiceJet", "Indigo", "GO FIRST", "SpiceJet", "Air Ind…
## $ Class <chr> "Economy", "Economy", "Economy", "Economy", "Economy",…
## $ Source <chr> "Delhi", "Delhi", "Delhi", "Delhi", "Delhi", "Delhi", …
## $ Departure <chr> "After 6 PM", "After 6 PM", "After 6 PM", "After 6 PM"…
## $ Total_stops <chr> "non-stop", "non-stop", "non-stop", "non-stop", "non-s…
## $ Destination <chr> "Mumbai", "Mumbai", "Mumbai", "Mumbai", "Mumbai", "Mum…
## $ Days_left <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ Fare <dbl> 5335, 5899, 5801, 5794, 5955, 5955, 5955, 5899, 5829, …
## $ days_left_group <fct> 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7 …
Feature Engineering: Create new features from existing data
# Create a binary feature indicating whether the flight is on a weekend
data$Is_weekend <- ifelse(data$Journey_day %in% c("Saturday", "Sunday"), 1, 0)
# Create a feature indicating whether the flight departs in the morning,
# afternoon, evening, or after midnight
data$Departure_period <- ifelse(data$Departure == "Before 6 AM", 1,
ifelse(data$Departure == "6 AM - 12 PM", 2,
ifelse(data$Departure == "12 PM - 6 PM", 3,
ifelse(data$Departure == "After 6 PM", 4, 0))))
# Create interaction features between Airline and Class, Source and Destination.
data$Airline_Class <- paste(data$Airline, data$Class, sep = "_")
data$Route <- paste(data$Source, data$Destination, sep = "_")
# Mutate Fare to be in thousands instead of ones and update column name to Fare(x1000)
data <- data %>% mutate(`Fare(x1000)` = Fare / 1000) %>% select(-Fare)
Create a new feature Is_Holiday if any of the flight dates align with India Holidays / Restricted Holidays based on information from Administrative offices of central government located at Delhi / New Delhi (between Jan 16 - March 06, 2023 to align with the dataset): https://cag.gov.in/uploads/media/2023-Holiday-List-062c177906f8592-90189505.pdf
# Define the list of holidays
holidays <- as.Date(c("2023-01-26", "2023-02-05", "2023-02-15", "2023-02-18", "2023-02-19"))
# Create the Is_Holiday feature
data$Is_Holiday <- ifelse(data$Date_of_journey %in% holidays, 1, 0)
# Display the constructed data
glimpse(data)
## Rows: 445,222
## Columns: 16
## $ Date_of_journey <date> 2023-01-16, 2023-01-16, 2023-01-16, 2023-01-16, 2023…
## $ Journey_day <chr> "Monday", "Monday", "Monday", "Monday", "Monday", "Mo…
## $ Airline <chr> "SpiceJet", "Indigo", "GO FIRST", "SpiceJet", "Air In…
## $ Class <chr> "Economy", "Economy", "Economy", "Economy", "Economy"…
## $ Source <chr> "Delhi", "Delhi", "Delhi", "Delhi", "Delhi", "Delhi",…
## $ Departure <chr> "After 6 PM", "After 6 PM", "After 6 PM", "After 6 PM…
## $ Total_stops <chr> "non-stop", "non-stop", "non-stop", "non-stop", "non-…
## $ Destination <chr> "Mumbai", "Mumbai", "Mumbai", "Mumbai", "Mumbai", "Mu…
## $ Days_left <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ days_left_group <fct> 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7…
## $ Is_weekend <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ Departure_period <dbl> 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 4, 4, 3, 2, 2,…
## $ Airline_Class <chr> "SpiceJet_Economy", "Indigo_Economy", "GO FIRST_Econo…
## $ Route <chr> "Delhi_Mumbai", "Delhi_Mumbai", "Delhi_Mumbai", "Delh…
## $ `Fare(x1000)` <dbl> 5.335, 5.899, 5.801, 5.794, 5.955, 5.955, 5.955, 5.89…
## $ Is_Holiday <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
Adjust the output plots to be wider.
options(repr.plot.width = 20, repr.plot.height = 10)
Preparing distinct_airline_class to plot fare distribution per airline class
# Preparing distinct_airline_class to plot fare distribution for each Airline Class
distinct_airline_class <- data %>%
distinct(Airline_Class) %>%
pull(Airline_Class)
Boxplot of fare distribution for each airline class; comparing weekend and weekday fares
# Box plot of Fare by Route for each Airline_Class comparing weekdays and weekends
# Split the plot into one plot each for each Airline_Class
plots <- list()
for (airline_class in distinct_airline_class) {
p <- ggplot(data %>% filter(Airline_Class == airline_class), aes(x = Route, y = `Fare(x1000)`, fill = factor(Is_weekend, labels = c("Weekdays", "Weekends")))) +
geom_boxplot(outlier.size = 0.7) +
labs(title = paste("Fare Distribution by Route for", airline_class, " (Weekdays vs Weekends)"), x = "Route", y = "Fare (in thousand rupees)", fill = "Day") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 12, angle = 90, hjust = 1),
axis.text.y = element_text(size = 16)
)
plots[[airline_class]] <- p
}
# Display the plots
for (airline_class in distinct_airline_class) {
print(plots[[airline_class]])
}
Boxplot of fare distribution for each airline class; comparing Holiday and non-holiday
# Box plot of Fare by Route for each Airline_Class comparing Holiday and non-holiday
# Split the plot into one plot each for each Airline_Class
plots <- list()
for (airline_class in distinct_airline_class) {
p <- ggplot(data %>% filter(Airline_Class == airline_class), aes(x = Route, y = `Fare(x1000)`, fill = factor(Is_Holiday, labels = c("Non-Holiday", "Holiday")))) +
geom_boxplot(outlier.size = 0.7) +
labs(title = paste("Fare Distribution by Route for", airline_class, " (Holiday vs Non-Holiday)"), x = "Route", y = "Fare (in thousand rupees)", fill = "Day") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 12, angle = 90, hjust = 1),
axis.text.y = element_text(size = 16)
)
plots[[airline_class]] <- p
}
# Display the plots
for (airline_class in distinct_airline_class) {
print(plots[[airline_class]])
}
Boxplot of fare distribution for each airline class; comparing departure time
# Box plot of Fare by Route for each Airline_Class comparing Departure time
# Split the plot into one plot each for each Airline_Class
plots <- list()
for (airline_class in distinct_airline_class) {
filtered_data <- data %>% filter(Airline_Class == airline_class)
filtered_data$Departure_period <- factor(filtered_data$Departure_period, levels = 1:4, labels = c("12am - 6am", "6am - 12pm", "12pm - 6pm", "6pm - 12am"))
p <- ggplot(filtered_data, aes(x = Route, y = `Fare(x1000)`, fill = Departure_period)) +
geom_boxplot(outlier.size = 0.7) +
labs(title = paste("Fare Distribution by Route for", airline_class, " (Departure Time)"), x = "Route", y = "Fare (in thousand rupees)", fill = "Departure Time") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 12, angle = 90, hjust = 1),
axis.text.y = element_text(size = 16)
)
plots[[airline_class]] <- p
}
# Display the plots
for (airline_class in distinct_airline_class) {
print(plots[[airline_class]])
}
Boxplot of fare distribution for each airline class; comparing How early the ticket is bought
# Box plot of Fare by Route for each Airline_Class comparing Days Left Group
# Split the plot into one plot each for each Airline_Class
plots <- list()
for (airline_class in distinct_airline_class) {
filtered_data <- data %>% filter(Airline_Class == airline_class)
p <- ggplot(filtered_data, aes(x = Route, y = `Fare(x1000)`, fill = days_left_group)) +
geom_boxplot(outlier.size = 0.7) +
labs(title = paste("Fare Distribution by Route for", airline_class, " (Ticket bought days prior to flight)"), x = "Route", y = "Fare (in thousand rupees)", fill = "Ticket bought days prior to flight") +
theme_minimal() +
theme(
plot.title = element_text(size = 20, face = "bold"),
axis.title.x = element_text(size = 18, face = "bold"),
axis.title.y = element_text(size = 18, face = "bold"),
axis.text.x = element_text(size = 12, angle = 90, hjust = 1),
axis.text.y = element_text(size = 16)
)
plots[[airline_class]] <- p
}
# Display the plots
for (airline_class in distinct_airline_class) {
print(plots[[airline_class]])
}
Remove the Date_of_journey column since it’s irrelevant for further prediction / classification
data <- data %>% select(-Date_of_journey)
# Check data type for each column
str(data)
## tibble [445,222 × 15] (S3: tbl_df/tbl/data.frame)
## $ Journey_day : chr [1:445222] "Monday" "Monday" "Monday" "Monday" ...
## $ Airline : chr [1:445222] "SpiceJet" "Indigo" "GO FIRST" "SpiceJet" ...
## $ Class : chr [1:445222] "Economy" "Economy" "Economy" "Economy" ...
## $ Source : chr [1:445222] "Delhi" "Delhi" "Delhi" "Delhi" ...
## $ Departure : chr [1:445222] "After 6 PM" "After 6 PM" "After 6 PM" "After 6 PM" ...
## $ Total_stops : chr [1:445222] "non-stop" "non-stop" "non-stop" "non-stop" ...
## $ Destination : chr [1:445222] "Mumbai" "Mumbai" "Mumbai" "Mumbai" ...
## $ Days_left : num [1:445222] 1 1 1 1 1 1 1 1 1 1 ...
## $ days_left_group : Factor w/ 6 levels "0-7 days","8-14 days",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Is_weekend : num [1:445222] 0 0 0 0 0 0 0 0 0 0 ...
## $ Departure_period: num [1:445222] 4 4 4 4 4 4 4 4 4 4 ...
## $ Airline_Class : chr [1:445222] "SpiceJet_Economy" "Indigo_Economy" "GO FIRST_Economy" "SpiceJet_Economy" ...
## $ Route : chr [1:445222] "Delhi_Mumbai" "Delhi_Mumbai" "Delhi_Mumbai" "Delhi_Mumbai" ...
## $ Fare(x1000) : num [1:445222] 5.33 5.9 5.8 5.79 5.96 ...
## $ Is_Holiday : num [1:445222] 0 0 0 0 0 0 0 0 0 0 ...
# Convert categorical variables to factors
data$Journey_day <- as.factor(data$Journey_day)
data$Airline <- as.factor(data$Airline)
data$Class <- as.factor(data$Class)
data$Source <- as.factor(data$Source)
data$Departure <- as.factor(data$Departure)
data$Total_stops <- as.factor(data$Total_stops)
data$Destination <- as.factor(data$Destination)
data$days_left_group <- as.factor(data$days_left_group)
data$Airline_Class <- as.factor(data$Airline_Class)
data$Route <- as.factor(data$Route)
# Ensure numerical variables are correctly formatted
data$Days_left <- as.numeric(data$Days_left)
data$Is_weekend <- as.numeric(data$Is_weekend)
data$Departure_period <- as.numeric(data$Departure_period)
# Ensure the Fare(x1000) and Fare_per_hour(x1000) are numeric
data$`Fare(x1000)` <- as.numeric(data$`Fare(x1000)`)
glimpse(data)
## Rows: 445,222
## Columns: 15
## $ Journey_day <fct> Monday, Monday, Monday, Monday, Monday, Monday, Monda…
## $ Airline <fct> SpiceJet, Indigo, GO FIRST, SpiceJet, Air India, Air …
## $ Class <fct> Economy, Economy, Economy, Economy, Economy, Economy,…
## $ Source <fct> Delhi, Delhi, Delhi, Delhi, Delhi, Delhi, Delhi, Delh…
## $ Departure <fct> After 6 PM, After 6 PM, After 6 PM, After 6 PM, After…
## $ Total_stops <fct> non-stop, non-stop, non-stop, non-stop, non-stop, non…
## $ Destination <fct> Mumbai, Mumbai, Mumbai, Mumbai, Mumbai, Mumbai, Mumba…
## $ Days_left <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ days_left_group <fct> 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7…
## $ Is_weekend <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ Departure_period <dbl> 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 4, 4, 3, 2, 2,…
## $ Airline_Class <fct> SpiceJet_Economy, Indigo_Economy, GO FIRST_Economy, S…
## $ Route <fct> Delhi_Mumbai, Delhi_Mumbai, Delhi_Mumbai, Delhi_Mumba…
## $ `Fare(x1000)` <dbl> 5.335, 5.899, 5.801, 5.794, 5.955, 5.955, 5.955, 5.89…
## $ Is_Holiday <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
# Check data type for each column again after converting
str(data)
## tibble [445,222 × 15] (S3: tbl_df/tbl/data.frame)
## $ Journey_day : Factor w/ 7 levels "Friday","Monday",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ Airline : Factor w/ 9 levels "Air India","AirAsia",..: 7 6 5 7 1 1 1 5 7 5 ...
## $ Class : Factor w/ 3 levels "Business","Economy",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ Source : Factor w/ 7 levels "Ahmedabad","Bangalore",..: 4 4 4 4 4 4 4 4 4 4 ...
## $ Departure : Factor w/ 4 levels "12 PM - 6 PM",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ Total_stops : Factor w/ 3 levels "1-stop","2+-stop",..: 3 3 3 3 3 3 3 3 1 3 ...
## $ Destination : Factor w/ 7 levels "Ahmedabad","Bangalore",..: 7 7 7 7 7 7 7 7 7 7 ...
## $ Days_left : num [1:445222] 1 1 1 1 1 1 1 1 1 1 ...
## $ days_left_group : Factor w/ 6 levels "0-7 days","8-14 days",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Is_weekend : num [1:445222] 0 0 0 0 0 0 0 0 0 0 ...
## $ Departure_period: num [1:445222] 4 4 4 4 4 4 4 4 4 4 ...
## $ Airline_Class : Factor w/ 12 levels "Air India_Business",..: 8 7 6 8 2 2 2 6 8 6 ...
## $ Route : Factor w/ 42 levels "Ahmedabad_Bangalore",..: 24 24 24 24 24 24 24 24 24 24 ...
## $ Fare(x1000) : num [1:445222] 5.33 5.9 5.8 5.79 5.96 ...
## $ Is_Holiday : num [1:445222] 0 0 0 0 0 0 0 0 0 0 ...
# Look at the data for each column again after converting
glimpse(data)
## Rows: 445,222
## Columns: 15
## $ Journey_day <fct> Monday, Monday, Monday, Monday, Monday, Monday, Monda…
## $ Airline <fct> SpiceJet, Indigo, GO FIRST, SpiceJet, Air India, Air …
## $ Class <fct> Economy, Economy, Economy, Economy, Economy, Economy,…
## $ Source <fct> Delhi, Delhi, Delhi, Delhi, Delhi, Delhi, Delhi, Delh…
## $ Departure <fct> After 6 PM, After 6 PM, After 6 PM, After 6 PM, After…
## $ Total_stops <fct> non-stop, non-stop, non-stop, non-stop, non-stop, non…
## $ Destination <fct> Mumbai, Mumbai, Mumbai, Mumbai, Mumbai, Mumbai, Mumba…
## $ Days_left <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ days_left_group <fct> 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7 days, 0-7…
## $ Is_weekend <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ Departure_period <dbl> 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 4, 4, 3, 2, 2,…
## $ Airline_Class <fct> SpiceJet_Economy, Indigo_Economy, GO FIRST_Economy, S…
## $ Route <fct> Delhi_Mumbai, Delhi_Mumbai, Delhi_Mumbai, Delhi_Mumba…
## $ `Fare(x1000)` <dbl> 5.335, 5.899, 5.801, 5.794, 5.955, 5.955, 5.955, 5.89…
## $ Is_Holiday <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
#Change name of fare to standard naming
colnames(data)[14] <- "Fare_x1000"
#Perform encoding to transform categorical variable to numerical variable for machine learning
dummy_model <- dummyVars("~ .", data = data)
data_encoded <- data.frame(predict(dummy_model, newdata = data))
glimpse(head(data_encoded))
## Rows: 6
## Columns: 105
## $ Journey_day.Friday <dbl> 0, 0, 0, 0, 0, 0
## $ Journey_day.Monday <dbl> 1, 1, 1, 1, 1, 1
## $ Journey_day.Saturday <dbl> 0, 0, 0, 0, 0, 0
## $ Journey_day.Sunday <dbl> 0, 0, 0, 0, 0, 0
## $ Journey_day.Thursday <dbl> 0, 0, 0, 0, 0, 0
## $ Journey_day.Tuesday <dbl> 0, 0, 0, 0, 0, 0
## $ Journey_day.Wednesday <dbl> 0, 0, 0, 0, 0, 0
## $ Airline.Air.India <dbl> 0, 0, 0, 0, 1, 1
## $ Airline.AirAsia <dbl> 0, 0, 0, 0, 0, 0
## $ Airline.AkasaAir <dbl> 0, 0, 0, 0, 0, 0
## $ Airline.AllianceAir <dbl> 0, 0, 0, 0, 0, 0
## $ Airline.GO.FIRST <dbl> 0, 0, 1, 0, 0, 0
## $ Airline.Indigo <dbl> 0, 1, 0, 0, 0, 0
## $ Airline.SpiceJet <dbl> 1, 0, 0, 1, 0, 0
## $ Airline.StarAir <dbl> 0, 0, 0, 0, 0, 0
## $ Airline.Vistara <dbl> 0, 0, 0, 0, 0, 0
## $ Class.Business <dbl> 0, 0, 0, 0, 0, 0
## $ Class.Economy <dbl> 1, 1, 1, 1, 1, 1
## $ Class.Premium.Economy <dbl> 0, 0, 0, 0, 0, 0
## $ Source.Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Source.Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Source.Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Source.Delhi <dbl> 1, 1, 1, 1, 1, 1
## $ Source.Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Source.Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Source.Mumbai <dbl> 0, 0, 0, 0, 0, 0
## $ Departure.12.PM...6.PM <dbl> 0, 0, 0, 0, 0, 0
## $ Departure.6.AM...12.PM <dbl> 0, 0, 0, 0, 0, 0
## $ Departure.After.6.PM <dbl> 1, 1, 1, 1, 1, 1
## $ Departure.Before.6.AM <dbl> 0, 0, 0, 0, 0, 0
## $ Total_stops.1.stop <dbl> 0, 0, 0, 0, 0, 0
## $ Total_stops.2..stop <dbl> 0, 0, 0, 0, 0, 0
## $ Total_stops.non.stop <dbl> 1, 1, 1, 1, 1, 1
## $ Destination.Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Destination.Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Destination.Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Destination.Delhi <dbl> 0, 0, 0, 0, 0, 0
## $ Destination.Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Destination.Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Destination.Mumbai <dbl> 1, 1, 1, 1, 1, 1
## $ Days_left <dbl> 1, 1, 1, 1, 1, 1
## $ days_left_group.0.7.days <dbl> 1, 1, 1, 1, 1, 1
## $ days_left_group.8.14.days <dbl> 0, 0, 0, 0, 0, 0
## $ days_left_group.15.30.days <dbl> 0, 0, 0, 0, 0, 0
## $ days_left_group.31.60.days <dbl> 0, 0, 0, 0, 0, 0
## $ days_left_group.61.90.days <dbl> 0, 0, 0, 0, 0, 0
## $ days_left_group.90..days <dbl> 0, 0, 0, 0, 0, 0
## $ Is_weekend <dbl> 0, 0, 0, 0, 0, 0
## $ Departure_period <dbl> 4, 4, 4, 4, 4, 4
## $ Airline_Class.Air.India_Business <dbl> 0, 0, 0, 0, 0, 0
## $ Airline_Class.Air.India_Economy <dbl> 0, 0, 0, 0, 1, 1
## $ Airline_Class.AirAsia_Economy <dbl> 0, 0, 0, 0, 0, 0
## $ Airline_Class.AkasaAir_Economy <dbl> 0, 0, 0, 0, 0, 0
## $ Airline_Class.AllianceAir_Economy <dbl> 0, 0, 0, 0, 0, 0
## $ Airline_Class.GO.FIRST_Economy <dbl> 0, 0, 1, 0, 0, 0
## $ Airline_Class.Indigo_Economy <dbl> 0, 1, 0, 0, 0, 0
## $ Airline_Class.SpiceJet_Economy <dbl> 1, 0, 0, 1, 0, 0
## $ Airline_Class.StarAir_Economy <dbl> 0, 0, 0, 0, 0, 0
## $ Airline_Class.Vistara_Business <dbl> 0, 0, 0, 0, 0, 0
## $ Airline_Class.Vistara_Economy <dbl> 0, 0, 0, 0, 0, 0
## $ Airline_Class.Vistara_Premium.Economy <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Ahmedabad_Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Ahmedabad_Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Ahmedabad_Delhi <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Ahmedabad_Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Ahmedabad_Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Ahmedabad_Mumbai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Bangalore_Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Bangalore_Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Bangalore_Delhi <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Bangalore_Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Bangalore_Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Bangalore_Mumbai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Chennai_Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Chennai_Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Chennai_Delhi <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Chennai_Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Chennai_Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Chennai_Mumbai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Delhi_Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Delhi_Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Delhi_Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Delhi_Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Delhi_Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Delhi_Mumbai <dbl> 1, 1, 1, 1, 1, 1
## $ Route.Hyderabad_Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Hyderabad_Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Hyderabad_Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Hyderabad_Delhi <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Hyderabad_Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Hyderabad_Mumbai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Kolkata_Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Kolkata_Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Kolkata_Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Kolkata_Delhi <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Kolkata_Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Kolkata_Mumbai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Mumbai_Ahmedabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Mumbai_Bangalore <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Mumbai_Chennai <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Mumbai_Delhi <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Mumbai_Hyderabad <dbl> 0, 0, 0, 0, 0, 0
## $ Route.Mumbai_Kolkata <dbl> 0, 0, 0, 0, 0, 0
## $ Fare_x1000 <dbl> 5.335, 5.899, 5.801, 5.794, 5.95…
## $ Is_Holiday <dbl> 0, 0, 0, 0, 0, 0
summary(head(data_encoded))
## Journey_day.Friday Journey_day.Monday Journey_day.Saturday Journey_day.Sunday
## Min. :0 Min. :1 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:1 1st Qu.:0 1st Qu.:0
## Median :0 Median :1 Median :0 Median :0
## Mean :0 Mean :1 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:1 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :1 Max. :0 Max. :0
## Journey_day.Thursday Journey_day.Tuesday Journey_day.Wednesday
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Airline.Air.India Airline.AirAsia Airline.AkasaAir Airline.AllianceAir
## Min. :0.0000 Min. :0 Min. :0 Min. :0
## 1st Qu.:0.0000 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0.0000 Median :0 Median :0 Median :0
## Mean :0.3333 Mean :0 Mean :0 Mean :0
## 3rd Qu.:0.7500 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :1.0000 Max. :0 Max. :0 Max. :0
## Airline.GO.FIRST Airline.Indigo Airline.SpiceJet Airline.StarAir
## Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0
## 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0
## Median :0.0000 Median :0.0000 Median :0.0000 Median :0
## Mean :0.1667 Mean :0.1667 Mean :0.3333 Mean :0
## 3rd Qu.:0.0000 3rd Qu.:0.0000 3rd Qu.:0.7500 3rd Qu.:0
## Max. :1.0000 Max. :1.0000 Max. :1.0000 Max. :0
## Airline.Vistara Class.Business Class.Economy Class.Premium.Economy
## Min. :0 Min. :0 Min. :1 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:1 1st Qu.:0
## Median :0 Median :0 Median :1 Median :0
## Mean :0 Mean :0 Mean :1 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:1 3rd Qu.:0
## Max. :0 Max. :0 Max. :1 Max. :0
## Source.Ahmedabad Source.Bangalore Source.Chennai Source.Delhi
## Min. :0 Min. :0 Min. :0 Min. :1
## 1st Qu.:0 1st Qu.:0 1st Qu.:0 1st Qu.:1
## Median :0 Median :0 Median :0 Median :1
## Mean :0 Mean :0 Mean :0 Mean :1
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0 3rd Qu.:1
## Max. :0 Max. :0 Max. :0 Max. :1
## Source.Hyderabad Source.Kolkata Source.Mumbai Departure.12.PM...6.PM
## Min. :0 Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0 Max. :0
## Departure.6.AM...12.PM Departure.After.6.PM Departure.Before.6.AM
## Min. :0 Min. :1 Min. :0
## 1st Qu.:0 1st Qu.:1 1st Qu.:0
## Median :0 Median :1 Median :0
## Mean :0 Mean :1 Mean :0
## 3rd Qu.:0 3rd Qu.:1 3rd Qu.:0
## Max. :0 Max. :1 Max. :0
## Total_stops.1.stop Total_stops.2..stop Total_stops.non.stop
## Min. :0 Min. :0 Min. :1
## 1st Qu.:0 1st Qu.:0 1st Qu.:1
## Median :0 Median :0 Median :1
## Mean :0 Mean :0 Mean :1
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:1
## Max. :0 Max. :0 Max. :1
## Destination.Ahmedabad Destination.Bangalore Destination.Chennai
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Destination.Delhi Destination.Hyderabad Destination.Kolkata Destination.Mumbai
## Min. :0 Min. :0 Min. :0 Min. :1
## 1st Qu.:0 1st Qu.:0 1st Qu.:0 1st Qu.:1
## Median :0 Median :0 Median :0 Median :1
## Mean :0 Mean :0 Mean :0 Mean :1
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0 3rd Qu.:1
## Max. :0 Max. :0 Max. :0 Max. :1
## Days_left days_left_group.0.7.days days_left_group.8.14.days
## Min. :1 Min. :1 Min. :0
## 1st Qu.:1 1st Qu.:1 1st Qu.:0
## Median :1 Median :1 Median :0
## Mean :1 Mean :1 Mean :0
## 3rd Qu.:1 3rd Qu.:1 3rd Qu.:0
## Max. :1 Max. :1 Max. :0
## days_left_group.15.30.days days_left_group.31.60.days
## Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0
## Median :0 Median :0
## Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0
## days_left_group.61.90.days days_left_group.90..days Is_weekend
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Departure_period Airline_Class.Air.India_Business
## Min. :4 Min. :0
## 1st Qu.:4 1st Qu.:0
## Median :4 Median :0
## Mean :4 Mean :0
## 3rd Qu.:4 3rd Qu.:0
## Max. :4 Max. :0
## Airline_Class.Air.India_Economy Airline_Class.AirAsia_Economy
## Min. :0.0000 Min. :0
## 1st Qu.:0.0000 1st Qu.:0
## Median :0.0000 Median :0
## Mean :0.3333 Mean :0
## 3rd Qu.:0.7500 3rd Qu.:0
## Max. :1.0000 Max. :0
## Airline_Class.AkasaAir_Economy Airline_Class.AllianceAir_Economy
## Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0
## Median :0 Median :0
## Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0
## Airline_Class.GO.FIRST_Economy Airline_Class.Indigo_Economy
## Min. :0.0000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:0.0000
## Median :0.0000 Median :0.0000
## Mean :0.1667 Mean :0.1667
## 3rd Qu.:0.0000 3rd Qu.:0.0000
## Max. :1.0000 Max. :1.0000
## Airline_Class.SpiceJet_Economy Airline_Class.StarAir_Economy
## Min. :0.0000 Min. :0
## 1st Qu.:0.0000 1st Qu.:0
## Median :0.0000 Median :0
## Mean :0.3333 Mean :0
## 3rd Qu.:0.7500 3rd Qu.:0
## Max. :1.0000 Max. :0
## Airline_Class.Vistara_Business Airline_Class.Vistara_Economy
## Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0
## Median :0 Median :0
## Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0
## Airline_Class.Vistara_Premium.Economy Route.Ahmedabad_Bangalore
## Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0
## Median :0 Median :0
## Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0
## Route.Ahmedabad_Chennai Route.Ahmedabad_Delhi Route.Ahmedabad_Hyderabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Ahmedabad_Kolkata Route.Ahmedabad_Mumbai Route.Bangalore_Ahmedabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Bangalore_Chennai Route.Bangalore_Delhi Route.Bangalore_Hyderabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Bangalore_Kolkata Route.Bangalore_Mumbai Route.Chennai_Ahmedabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Chennai_Bangalore Route.Chennai_Delhi Route.Chennai_Hyderabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Chennai_Kolkata Route.Chennai_Mumbai Route.Delhi_Ahmedabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Delhi_Bangalore Route.Delhi_Chennai Route.Delhi_Hyderabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Delhi_Kolkata Route.Delhi_Mumbai Route.Hyderabad_Ahmedabad
## Min. :0 Min. :1 Min. :0
## 1st Qu.:0 1st Qu.:1 1st Qu.:0
## Median :0 Median :1 Median :0
## Mean :0 Mean :1 Mean :0
## 3rd Qu.:0 3rd Qu.:1 3rd Qu.:0
## Max. :0 Max. :1 Max. :0
## Route.Hyderabad_Bangalore Route.Hyderabad_Chennai Route.Hyderabad_Delhi
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Hyderabad_Kolkata Route.Hyderabad_Mumbai Route.Kolkata_Ahmedabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Kolkata_Bangalore Route.Kolkata_Chennai Route.Kolkata_Delhi
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Kolkata_Hyderabad Route.Kolkata_Mumbai Route.Mumbai_Ahmedabad
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Mumbai_Bangalore Route.Mumbai_Chennai Route.Mumbai_Delhi
## Min. :0 Min. :0 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:0
## Median :0 Median :0 Median :0
## Mean :0 Mean :0 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0
## Max. :0 Max. :0 Max. :0
## Route.Mumbai_Hyderabad Route.Mumbai_Kolkata Fare_x1000 Is_Holiday
## Min. :0 Min. :0 Min. :5.335 Min. :0
## 1st Qu.:0 1st Qu.:0 1st Qu.:5.796 1st Qu.:0
## Median :0 Median :0 Median :5.850 Median :0
## Mean :0 Mean :0 Mean :5.790 Mean :0
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:5.941 3rd Qu.:0
## Max. :0 Max. :0 Max. :5.955 Max. :0
head(data_encoded)
## Journey_day.Friday Journey_day.Monday Journey_day.Saturday Journey_day.Sunday
## 1 0 1 0 0
## 2 0 1 0 0
## 3 0 1 0 0
## 4 0 1 0 0
## 5 0 1 0 0
## 6 0 1 0 0
## Journey_day.Thursday Journey_day.Tuesday Journey_day.Wednesday
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Airline.Air.India Airline.AirAsia Airline.AkasaAir Airline.AllianceAir
## 1 0 0 0 0
## 2 0 0 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 1 0 0 0
## 6 1 0 0 0
## Airline.GO.FIRST Airline.Indigo Airline.SpiceJet Airline.StarAir
## 1 0 0 1 0
## 2 0 1 0 0
## 3 1 0 0 0
## 4 0 0 1 0
## 5 0 0 0 0
## 6 0 0 0 0
## Airline.Vistara Class.Business Class.Economy Class.Premium.Economy
## 1 0 0 1 0
## 2 0 0 1 0
## 3 0 0 1 0
## 4 0 0 1 0
## 5 0 0 1 0
## 6 0 0 1 0
## Source.Ahmedabad Source.Bangalore Source.Chennai Source.Delhi
## 1 0 0 0 1
## 2 0 0 0 1
## 3 0 0 0 1
## 4 0 0 0 1
## 5 0 0 0 1
## 6 0 0 0 1
## Source.Hyderabad Source.Kolkata Source.Mumbai Departure.12.PM...6.PM
## 1 0 0 0 0
## 2 0 0 0 0
## 3 0 0 0 0
## 4 0 0 0 0
## 5 0 0 0 0
## 6 0 0 0 0
## Departure.6.AM...12.PM Departure.After.6.PM Departure.Before.6.AM
## 1 0 1 0
## 2 0 1 0
## 3 0 1 0
## 4 0 1 0
## 5 0 1 0
## 6 0 1 0
## Total_stops.1.stop Total_stops.2..stop Total_stops.non.stop
## 1 0 0 1
## 2 0 0 1
## 3 0 0 1
## 4 0 0 1
## 5 0 0 1
## 6 0 0 1
## Destination.Ahmedabad Destination.Bangalore Destination.Chennai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Destination.Delhi Destination.Hyderabad Destination.Kolkata
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Destination.Mumbai Days_left days_left_group.0.7.days
## 1 1 1 1
## 2 1 1 1
## 3 1 1 1
## 4 1 1 1
## 5 1 1 1
## 6 1 1 1
## days_left_group.8.14.days days_left_group.15.30.days
## 1 0 0
## 2 0 0
## 3 0 0
## 4 0 0
## 5 0 0
## 6 0 0
## days_left_group.31.60.days days_left_group.61.90.days
## 1 0 0
## 2 0 0
## 3 0 0
## 4 0 0
## 5 0 0
## 6 0 0
## days_left_group.90..days Is_weekend Departure_period
## 1 0 0 4
## 2 0 0 4
## 3 0 0 4
## 4 0 0 4
## 5 0 0 4
## 6 0 0 4
## Airline_Class.Air.India_Business Airline_Class.Air.India_Economy
## 1 0 0
## 2 0 0
## 3 0 0
## 4 0 0
## 5 0 1
## 6 0 1
## Airline_Class.AirAsia_Economy Airline_Class.AkasaAir_Economy
## 1 0 0
## 2 0 0
## 3 0 0
## 4 0 0
## 5 0 0
## 6 0 0
## Airline_Class.AllianceAir_Economy Airline_Class.GO.FIRST_Economy
## 1 0 0
## 2 0 0
## 3 0 1
## 4 0 0
## 5 0 0
## 6 0 0
## Airline_Class.Indigo_Economy Airline_Class.SpiceJet_Economy
## 1 0 1
## 2 1 0
## 3 0 0
## 4 0 1
## 5 0 0
## 6 0 0
## Airline_Class.StarAir_Economy Airline_Class.Vistara_Business
## 1 0 0
## 2 0 0
## 3 0 0
## 4 0 0
## 5 0 0
## 6 0 0
## Airline_Class.Vistara_Economy Airline_Class.Vistara_Premium.Economy
## 1 0 0
## 2 0 0
## 3 0 0
## 4 0 0
## 5 0 0
## 6 0 0
## Route.Ahmedabad_Bangalore Route.Ahmedabad_Chennai Route.Ahmedabad_Delhi
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Ahmedabad_Hyderabad Route.Ahmedabad_Kolkata Route.Ahmedabad_Mumbai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Bangalore_Ahmedabad Route.Bangalore_Chennai Route.Bangalore_Delhi
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Bangalore_Hyderabad Route.Bangalore_Kolkata Route.Bangalore_Mumbai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Chennai_Ahmedabad Route.Chennai_Bangalore Route.Chennai_Delhi
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Chennai_Hyderabad Route.Chennai_Kolkata Route.Chennai_Mumbai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Delhi_Ahmedabad Route.Delhi_Bangalore Route.Delhi_Chennai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Delhi_Hyderabad Route.Delhi_Kolkata Route.Delhi_Mumbai
## 1 0 0 1
## 2 0 0 1
## 3 0 0 1
## 4 0 0 1
## 5 0 0 1
## 6 0 0 1
## Route.Hyderabad_Ahmedabad Route.Hyderabad_Bangalore Route.Hyderabad_Chennai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Hyderabad_Delhi Route.Hyderabad_Kolkata Route.Hyderabad_Mumbai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Kolkata_Ahmedabad Route.Kolkata_Bangalore Route.Kolkata_Chennai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Kolkata_Delhi Route.Kolkata_Hyderabad Route.Kolkata_Mumbai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Mumbai_Ahmedabad Route.Mumbai_Bangalore Route.Mumbai_Chennai
## 1 0 0 0
## 2 0 0 0
## 3 0 0 0
## 4 0 0 0
## 5 0 0 0
## 6 0 0 0
## Route.Mumbai_Delhi Route.Mumbai_Hyderabad Route.Mumbai_Kolkata Fare_x1000
## 1 0 0 0 5.335
## 2 0 0 0 5.899
## 3 0 0 0 5.801
## 4 0 0 0 5.794
## 5 0 0 0 5.955
## 6 0 0 0 5.955
## Is_Holiday
## 1 0
## 2 0
## 3 0
## 4 0
## 5 0
## 6 0
The algorithm that has been selected to develop the Flight Fare Prediction Model and Class Type Classification Model are as follows:
Flight Fare Prediction Model 1. Linear Regression 2. Lasso Regressor 3. Ridge Regressor
Class Type Classification Model
# Set seed for consistency
set.seed(123)
# Set the split ratio
split <- 0.8
# Create a partition
trainIndex <- createDataPartition(data_encoded$Fare_x1000 , p = split, list = FALSE)
# Split the data into training and testing sets
data_train <- data_encoded[trainIndex, ]
data_test <- data_encoded[-trainIndex, ]
# Print the number of rows in training and testing sets
cat("Number of rows in training set:", nrow(data_train), "\n")
## Number of rows in training set: 356180
cat("Number of rows in testing set:", nrow(data_test), "\n")
## Number of rows in testing set: 89042
# Set seed for consistency
set.seed(123)
# Set the split ratio
split <- 0.8
# Splitting features (X) and target (Y)
x <- data_encoded[, !(names(data_encoded) %in% c("Class.Economy", "Class.Business", "Class.Premium.Economy"))]
y <- as.factor(apply(data_encoded[, c("Class.Economy", "Class.Business", "Class.Premium.Economy")], 1,
function(row) which(row == 1)))
# Rename factor levels for clarity
levels(y) <- c("economy", "business", "premium_economy")
# Create a partition
trainIndex <- createDataPartition(y, p = split, list = FALSE)
# Split the data into training and testing sets
x_train <- x[trainIndex, ]
x_test <- x[-trainIndex, ]
y_train <- y[trainIndex]
y_test <- y[-trainIndex]
# Print the number of rows in training and texsting sets
cat("Number of rows in training set:", nrow(x_train), "\n")
## Number of rows in training set: 356179
cat("Number of rows in testing set:", nrow(x_test), "\n")
## Number of rows in testing set: 89043
Flight Fare prediction model
# Linear Regression Model
train_control <- trainControl(method = "cv", number = 5)
model_linear_regression <- train(Fare_x1000 ~ ., data = data_train, method = "lm", trControl = train_control)
# estimate variable importance
importance_linear_regression <- varImp(model_linear_regression, scale = FALSE)
# select the top 10 most important variables
top_10_linear_regression <- importance_linear_regression$importance %>%
rownames_to_column(var = "feature") %>%
arrange(desc(Overall)) %>%
head(10)
# cross validation results
print(model_linear_regression)
## Linear Regression
##
## 356180 samples
## 104 predictor
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 284945, 284945, 284944, 284943, 284943
## Resampling results:
##
## RMSE Rsquared MAE
## 7.604541 0.8606419 4.973426
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
# plot the top 10 most important variables
ggplot(top_10_linear_regression, aes(x = reorder(feature, Overall), y = Overall, fill = Overall)) +
geom_bar(stat = "identity") +
labs(title = "Top 10 Most Important Variables for Linear Regression Machine",
x = "Feature",
y = "Importance",
subtitle = "Linear Regression Machine"
) +
scale_fill_gradient(low = "lightblue", high = "blue") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# Lasso Regression Model
train_control <- trainControl(method = "cv", number = 5)
model_lasso_regression <- train(Fare_x1000 ~ ., data = data_train, method = "glmnet", trControl = train_control, tuneGrid = expand.grid(alpha = 1, lambda = seq(0.001, 0.1, by = 0.001)))
# estimate variable importance
importance_lasso_regression <- varImp(model_lasso_regression, scale = FALSE)
# select the top 10 most important variables
top_10_lasso_regression <- importance_lasso_regression$importance %>%
rownames_to_column(var = "feature") %>%
arrange(desc(Overall)) %>%
head(10)
# cross validation results
print(model_lasso_regression)
## glmnet
##
## 356180 samples
## 104 predictor
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 284943, 284944, 284945, 284943, 284945
## Resampling results across tuning parameters:
##
## lambda RMSE Rsquared MAE
## 0.001 7.605387 0.8606149 4.963948
## 0.002 7.605387 0.8606149 4.963948
## 0.003 7.605387 0.8606149 4.963948
## 0.004 7.605387 0.8606149 4.963948
## 0.005 7.605387 0.8606149 4.963948
## 0.006 7.605387 0.8606149 4.963948
## 0.007 7.605387 0.8606149 4.963948
## 0.008 7.605387 0.8606149 4.963948
## 0.009 7.605387 0.8606149 4.963948
## 0.010 7.605387 0.8606149 4.963948
## 0.011 7.605387 0.8606149 4.963948
## 0.012 7.605387 0.8606149 4.963948
## 0.013 7.605387 0.8606149 4.963948
## 0.014 7.605387 0.8606149 4.963948
## 0.015 7.605387 0.8606149 4.963948
## 0.016 7.605387 0.8606149 4.963948
## 0.017 7.605402 0.8606144 4.963889
## 0.018 7.605523 0.8606102 4.963435
## 0.019 7.605652 0.8606058 4.962994
## 0.020 7.605787 0.8606012 4.962566
## 0.021 7.605928 0.8605963 4.962144
## 0.022 7.606077 0.8605912 4.961732
## 0.023 7.606231 0.8605859 4.961328
## 0.024 7.606392 0.8605804 4.960935
## 0.025 7.606558 0.8605747 4.960548
## 0.026 7.606729 0.8605688 4.960166
## 0.027 7.606906 0.8605627 4.959796
## 0.028 7.607089 0.8605564 4.959441
## 0.029 7.607279 0.8605499 4.959095
## 0.030 7.607473 0.8605433 4.958750
## 0.031 7.607671 0.8605365 4.958405
## 0.032 7.607876 0.8605295 4.958070
## 0.033 7.608084 0.8605224 4.957731
## 0.034 7.608296 0.8605151 4.957393
## 0.035 7.608515 0.8605077 4.957064
## 0.036 7.608741 0.8604999 4.956754
## 0.037 7.608976 0.8604919 4.956462
## 0.038 7.609217 0.8604836 4.956178
## 0.039 7.609464 0.8604751 4.955903
## 0.040 7.609715 0.8604665 4.955637
## 0.041 7.609971 0.8604577 4.955381
## 0.042 7.610234 0.8604487 4.955133
## 0.043 7.610502 0.8604395 4.954893
## 0.044 7.610774 0.8604302 4.954652
## 0.045 7.611052 0.8604206 4.954422
## 0.046 7.611336 0.8604109 4.954199
## 0.047 7.611627 0.8604009 4.953986
## 0.048 7.611927 0.8603906 4.953787
## 0.049 7.612232 0.8603801 4.953597
## 0.050 7.612545 0.8603694 4.953417
## 0.051 7.612863 0.8603584 4.953245
## 0.052 7.613186 0.8603473 4.953088
## 0.053 7.613514 0.8603360 4.952947
## 0.054 7.613848 0.8603245 4.952815
## 0.055 7.614188 0.8603128 4.952693
## 0.056 7.614534 0.8603008 4.952580
## 0.057 7.614883 0.8602888 4.952483
## 0.058 7.615233 0.8602768 4.952404
## 0.059 7.615589 0.8602645 4.952335
## 0.060 7.615951 0.8602520 4.952274
## 0.061 7.616320 0.8602393 4.952222
## 0.062 7.616694 0.8602264 4.952179
## 0.063 7.617045 0.8602144 4.952083
## 0.064 7.617400 0.8602023 4.951994
## 0.065 7.617760 0.8601899 4.951912
## 0.066 7.618126 0.8601774 4.951838
## 0.067 7.618498 0.8601647 4.951772
## 0.068 7.618875 0.8601518 4.951715
## 0.069 7.619218 0.8601401 4.951613
## 0.070 7.619561 0.8601285 4.951512
## 0.071 7.619909 0.8601167 4.951417
## 0.072 7.620262 0.8601047 4.951328
## 0.073 7.620620 0.8600925 4.951247
## 0.074 7.620983 0.8600802 4.951172
## 0.075 7.621344 0.8600679 4.951092
## 0.076 7.621689 0.8600563 4.950981
## 0.077 7.622038 0.8600445 4.950877
## 0.078 7.622391 0.8600325 4.950779
## 0.079 7.622750 0.8600204 4.950689
## 0.080 7.623113 0.8600082 4.950605
## 0.081 7.623480 0.8599957 4.950528
## 0.082 7.623852 0.8599831 4.950457
## 0.083 7.624207 0.8599712 4.950351
## 0.084 7.624566 0.8599592 4.950249
## 0.085 7.624929 0.8599470 4.950153
## 0.086 7.625296 0.8599347 4.950063
## 0.087 7.625667 0.8599222 4.949978
## 0.088 7.626043 0.8599095 4.949899
## 0.089 7.626423 0.8598968 4.949825
## 0.090 7.626808 0.8598838 4.949758
## 0.091 7.627191 0.8598709 4.949688
## 0.092 7.627579 0.8598579 4.949624
## 0.093 7.627971 0.8598447 4.949565
## 0.094 7.628367 0.8598313 4.949512
## 0.095 7.628768 0.8598179 4.949463
## 0.096 7.629173 0.8598042 4.949420
## 0.097 7.629581 0.8597904 4.949382
## 0.098 7.629995 0.8597765 4.949350
## 0.099 7.630411 0.8597625 4.949323
## 0.100 7.630825 0.8597486 4.949295
##
## Tuning parameter 'alpha' was held constant at a value of 1
## RMSE was used to select the optimal model using the smallest value.
## The final values used for the model were alpha = 1 and lambda = 0.016.
# plot the top 10 most important variables
ggplot(top_10_lasso_regression, aes(x = reorder(feature, Overall), y = Overall, fill = Overall)) +
geom_bar(stat = "identity") +
labs(title = "Top 10 Most Important Variables for Lasso Regression Machine",
x = "Feature",
y = "Importance",
subtitle = "Lasso Regression Machine"
) +
scale_fill_gradient(low = "lightblue", high = "blue") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# ridge regression
train_control <- trainControl(method = "cv", number = 5)
model_ridge_regression <- train(Fare_x1000 ~ ., data = data_train, method = "glmnet", trControl = train_control, tuneGrid = expand.grid(alpha = 0, lambda = seq(0.001, 0.1, by = 0.001)))
# estimate variable importance
importance_ridge_regression <- varImp(model_ridge_regression, scale = FALSE)
# select the top 10 most important variables
top_10_ridge_regression <- importance_ridge_regression$importance %>%
rownames_to_column(var = "feature") %>%
arrange(desc(Overall)) %>%
head(10)
# cross validation results
print(model_ridge_regression)
## glmnet
##
## 356180 samples
## 104 predictor
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 284943, 284944, 284944, 284944, 284945
## Resampling results across tuning parameters:
##
## lambda RMSE Rsquared MAE
## 0.001 7.630128 0.8604943 4.964676
## 0.002 7.630128 0.8604943 4.964676
## 0.003 7.630128 0.8604943 4.964676
## 0.004 7.630128 0.8604943 4.964676
## 0.005 7.630128 0.8604943 4.964676
## 0.006 7.630128 0.8604943 4.964676
## 0.007 7.630128 0.8604943 4.964676
## 0.008 7.630128 0.8604943 4.964676
## 0.009 7.630128 0.8604943 4.964676
## 0.010 7.630128 0.8604943 4.964676
## 0.011 7.630128 0.8604943 4.964676
## 0.012 7.630128 0.8604943 4.964676
## 0.013 7.630128 0.8604943 4.964676
## 0.014 7.630128 0.8604943 4.964676
## 0.015 7.630128 0.8604943 4.964676
## 0.016 7.630128 0.8604943 4.964676
## 0.017 7.630128 0.8604943 4.964676
## 0.018 7.630128 0.8604943 4.964676
## 0.019 7.630128 0.8604943 4.964676
## 0.020 7.630128 0.8604943 4.964676
## 0.021 7.630128 0.8604943 4.964676
## 0.022 7.630128 0.8604943 4.964676
## 0.023 7.630128 0.8604943 4.964676
## 0.024 7.630128 0.8604943 4.964676
## 0.025 7.630128 0.8604943 4.964676
## 0.026 7.630128 0.8604943 4.964676
## 0.027 7.630128 0.8604943 4.964676
## 0.028 7.630128 0.8604943 4.964676
## 0.029 7.630128 0.8604943 4.964676
## 0.030 7.630128 0.8604943 4.964676
## 0.031 7.630128 0.8604943 4.964676
## 0.032 7.630128 0.8604943 4.964676
## 0.033 7.630128 0.8604943 4.964676
## 0.034 7.630128 0.8604943 4.964676
## 0.035 7.630128 0.8604943 4.964676
## 0.036 7.630128 0.8604943 4.964676
## 0.037 7.630128 0.8604943 4.964676
## 0.038 7.630128 0.8604943 4.964676
## 0.039 7.630128 0.8604943 4.964676
## 0.040 7.630128 0.8604943 4.964676
## 0.041 7.630128 0.8604943 4.964676
## 0.042 7.630128 0.8604943 4.964676
## 0.043 7.630128 0.8604943 4.964676
## 0.044 7.630128 0.8604943 4.964676
## 0.045 7.630128 0.8604943 4.964676
## 0.046 7.630128 0.8604943 4.964676
## 0.047 7.630128 0.8604943 4.964676
## 0.048 7.630128 0.8604943 4.964676
## 0.049 7.630128 0.8604943 4.964676
## 0.050 7.630128 0.8604943 4.964676
## 0.051 7.630128 0.8604943 4.964676
## 0.052 7.630128 0.8604943 4.964676
## 0.053 7.630128 0.8604943 4.964676
## 0.054 7.630128 0.8604943 4.964676
## 0.055 7.630128 0.8604943 4.964676
## 0.056 7.630128 0.8604943 4.964676
## 0.057 7.630128 0.8604943 4.964676
## 0.058 7.630128 0.8604943 4.964676
## 0.059 7.630128 0.8604943 4.964676
## 0.060 7.630128 0.8604943 4.964676
## 0.061 7.630128 0.8604943 4.964676
## 0.062 7.630128 0.8604943 4.964676
## 0.063 7.630128 0.8604943 4.964676
## 0.064 7.630128 0.8604943 4.964676
## 0.065 7.630128 0.8604943 4.964676
## 0.066 7.630128 0.8604943 4.964676
## 0.067 7.630128 0.8604943 4.964676
## 0.068 7.630128 0.8604943 4.964676
## 0.069 7.630128 0.8604943 4.964676
## 0.070 7.630128 0.8604943 4.964676
## 0.071 7.630128 0.8604943 4.964676
## 0.072 7.630128 0.8604943 4.964676
## 0.073 7.630128 0.8604943 4.964676
## 0.074 7.630128 0.8604943 4.964676
## 0.075 7.630128 0.8604943 4.964676
## 0.076 7.630128 0.8604943 4.964676
## 0.077 7.630128 0.8604943 4.964676
## 0.078 7.630128 0.8604943 4.964676
## 0.079 7.630128 0.8604943 4.964676
## 0.080 7.630128 0.8604943 4.964676
## 0.081 7.630128 0.8604943 4.964676
## 0.082 7.630128 0.8604943 4.964676
## 0.083 7.630128 0.8604943 4.964676
## 0.084 7.630128 0.8604943 4.964676
## 0.085 7.630128 0.8604943 4.964676
## 0.086 7.630128 0.8604943 4.964676
## 0.087 7.630128 0.8604943 4.964676
## 0.088 7.630128 0.8604943 4.964676
## 0.089 7.630128 0.8604943 4.964676
## 0.090 7.630128 0.8604943 4.964676
## 0.091 7.630128 0.8604943 4.964676
## 0.092 7.630128 0.8604943 4.964676
## 0.093 7.630128 0.8604943 4.964676
## 0.094 7.630128 0.8604943 4.964676
## 0.095 7.630128 0.8604943 4.964676
## 0.096 7.630128 0.8604943 4.964676
## 0.097 7.630128 0.8604943 4.964676
## 0.098 7.630128 0.8604943 4.964676
## 0.099 7.630128 0.8604943 4.964676
## 0.100 7.630128 0.8604943 4.964676
##
## Tuning parameter 'alpha' was held constant at a value of 0
## RMSE was used to select the optimal model using the smallest value.
## The final values used for the model were alpha = 0 and lambda = 0.1.
# plot the top 10 most important variables
ggplot(top_10_ridge_regression, aes(x = reorder(feature, Overall), y = Overall, fill = Overall)) +
geom_bar(stat = "identity") +
labs(title = "Top 10 Most Important Variables for Ridge Regression Machine",
x = "Feature",
y = "Importance",
subtitle = "Ridge Regression Machine"
) +
scale_fill_gradient(low = "lightblue", high = "blue") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Class Type Classification Model 1. Naive Bayes Classification Model
# Naive Bayes Classification Model
# Train Naive Bayes model
NBClassification <- naiveBayes(x = x_train, y = y_train)
# Predict on the test set
NBClassification_predict <- predict(NBClassification, newdata = x_test)
# Train SVM model
SVMClassification <- svm(x = x_train, y = y_train, kernel = "linear")
# Predict on the test set
SVMClassification_predict <- predict(SVMClassification, newdata = x_test)
# Train a multinomial logistic regression model
MLogRegClassification <- multinom(y_train ~ ., data = cbind(x_train, y_train))
## # weights: 312 (206 variable)
## initial value 391302.626365
## iter 10 value 28981.241885
## iter 20 value 23696.693298
## iter 30 value 20785.023332
## iter 40 value 8451.159035
## iter 50 value 7372.797303
## iter 60 value 3647.293443
## iter 70 value 2686.355573
## iter 80 value 1444.918821
## iter 90 value 435.179373
## iter 100 value 153.017021
## final value 153.017021
## stopped after 100 iterations
# Predict on the test set
MLogRegClassification_predict <- predict(MLogRegClassification, newdata = x_test)
Flight Fare Prediction Model
Assess the fare prediction model by using the root mean square error (RMSE), Mean Absolute Error (MAE) and R-squared Value. The plot of predicted vs actual is also been plot to know how the predicted values match the actual values.
Linear Regression
# Generate predictions on the test set
predictions_linear_regression <- predict(model_linear_regression, newdata = data_test)
# Actual values from the test set
actual_linear_regression <- data_test$Fare_x1000
# Compute performance metrics
rmse <- sqrt(mean((predictions_linear_regression - actual_linear_regression)^2))
mae <- mean(abs(predictions_linear_regression - actual_linear_regression))
ss_total <- sum((actual_linear_regression - mean(actual_linear_regression))^2)
ss_residual <- sum((actual_linear_regression - predictions_linear_regression)^2)
r_squared <- 1 - (ss_residual / ss_total)
test_results_linear_regression <- data.frame(
RMSE = rmse,
MAE = mae,
R_Squared = r_squared
)
print(test_results_linear_regression)
## RMSE MAE R_Squared
## 1 7.648222 4.988768 0.8599075
# Create a data frame for easy plotting
results_df_linear_regression <- data.frame(actual_linear_regression, predictions_linear_regression)
# Plot Predictions vs Actual
ggplot(results_df_linear_regression, aes(x = actual_linear_regression, y = predictions_linear_regression)) +
geom_point(color = "blue") +
geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed", size = 2) +
labs(title = "Predictions vs Actual", x = "Actual Values", y = "Predicted Values") +
theme_minimal()
Lasso Regression Model
# Generate predictions on the test set
predictions_lasso_regression <- predict(model_lasso_regression, newdata = data_test)
# Actual values from the test set
actual_lasso_regression <- data_test$Fare_x1000
# Compute performance metrics
rmse <- sqrt(mean((predictions_lasso_regression - actual_lasso_regression)^2))
mae <- mean(abs(predictions_lasso_regression - actual_lasso_regression))
ss_total <- sum((actual_lasso_regression - mean(actual_lasso_regression))^2)
ss_residual <- sum((actual_lasso_regression - predictions_lasso_regression)^2)
r_squared <- 1 - (ss_residual / ss_total)
test_results_lasso_regression <- data.frame(
RMSE = rmse,
MAE = mae,
R_Squared = r_squared
)
print(test_results_lasso_regression)
## RMSE MAE R_Squared
## 1 7.649963 4.980053 0.8598437
# Create a data frame for easy plotting
results_df_lasso_regression <- data.frame(actual_lasso_regression, predictions_lasso_regression)
# Plot Predictions vs Actual
ggplot(results_df_lasso_regression, aes(x = actual_lasso_regression, y = predictions_lasso_regression)) +
geom_point(color = "blue") +
geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed", size = 2) +
labs(title = "Predictions vs Actual", x = "Actual Values", y = "Predicted Values") +
theme_minimal()
Ridge Regression Model
# Generate predictions on the test set
predictions <- predict(model_ridge_regression, newdata = data_test)
# Actual values from the test set
actual <- data_test$Fare_x1000
# Compute performance metrics
# 1. Root Mean Squared Error (RMSE)
rmse <- sqrt(mean((predictions - actual)^2))
# 2. Mean Absolute Error (MAE)
mae <- mean(abs(predictions - actual))
# 3. R-squared (Coefficient of Determination)
ss_total <- sum((actual - mean(actual))^2)
ss_residual <- sum((actual - predictions)^2)
r_squared <- 1 - (ss_residual / ss_total)
# Print the results
test_results_ridge_regression <- data.frame(
RMSE = rmse,
MAE = mae,
R_Squared = r_squared
)
print(test_results_ridge_regression)
## RMSE MAE R_Squared
## 1 7.678673 4.983582 0.8587898
Class Type Classification Model
The performance of the classification model is evaluate based on the confusion matrix and evaluation matrix.
Naive Bayes Classification
# Confusion Matrix
conf_matrix <- confusionMatrix(NBClassification_predict, y_test, mode = "everything")
print(conf_matrix)
## Confusion Matrix and Statistics
##
## Reference
## Prediction economy business premium_economy
## economy 3 0 0
## business 15985 23387 134
## premium_economy 33676 1920 13938
##
## Overall Statistics
##
## Accuracy : 0.4192
## 95% CI : (0.416, 0.4225)
## No Information Rate : 0.5578
## P-Value [Acc > NIR] : 1
##
## Kappa : 0.2611
##
## Mcnemar's Test P-Value : <2e-16
##
## Statistics by Class:
##
## Class: economy Class: business Class: premium_economy
## Sensitivity 6.041e-05 0.9241 0.9905
## Specificity 1.000e+00 0.7471 0.5252
## Pos Pred Value 1.000e+00 0.5920 0.2814
## Neg Pred Value 4.423e-01 0.9612 0.9966
## Precision 1.000e+00 0.5920 0.2814
## Recall 6.041e-05 0.9241 0.9905
## F1 1.208e-04 0.7217 0.4383
## Prevalence 5.578e-01 0.2842 0.1580
## Detection Rate 3.369e-05 0.2626 0.1565
## Detection Prevalence 3.369e-05 0.4437 0.5563
## Balanced Accuracy 5.000e-01 0.8356 0.7578
# Extract Precision, Recall, and F1 score for each class
precision <- conf_matrix$byClass[, "Pos Pred Value"]
recall <- conf_matrix$byClass[, "Sensitivity"]
f1_score <- conf_matrix$byClass[, "F1"]
# Prevalence (the proportion of each class in the actual data)
prevalence <- conf_matrix$byClass[, "Prevalence"]
# Calculate weighted metrics
weighted_precision <- sum(precision * prevalence)
weighted_recall <- sum(recall * prevalence)
weighted_f1 <- sum(f1_score * prevalence)
# Print the weighted metrics
cat("Weighted Precision:", weighted_precision, "\n")
## Weighted Precision: 0.7704705
cat("Weighted Recall:", weighted_recall, "\n")
## Weighted Recall: 0.4192132
cat("Weighted F1 Score:", weighted_f1, "\n")
## Weighted F1 Score: 0.2744366
SVM Classification Model
# Confusion Matrix
conf_matrix <- confusionMatrix(SVMClassification_predict, y_test,mode="everything")
print(conf_matrix)
## Confusion Matrix and Statistics
##
## Reference
## Prediction economy business premium_economy
## economy 49664 0 0
## business 0 25307 0
## premium_economy 0 0 14072
##
## Overall Statistics
##
## Accuracy : 1
## 95% CI : (1, 1)
## No Information Rate : 0.5578
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 1
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: economy Class: business Class: premium_economy
## Sensitivity 1.0000 1.0000 1.000
## Specificity 1.0000 1.0000 1.000
## Pos Pred Value 1.0000 1.0000 1.000
## Neg Pred Value 1.0000 1.0000 1.000
## Precision 1.0000 1.0000 1.000
## Recall 1.0000 1.0000 1.000
## F1 1.0000 1.0000 1.000
## Prevalence 0.5578 0.2842 0.158
## Detection Rate 0.5578 0.2842 0.158
## Detection Prevalence 0.5578 0.2842 0.158
## Balanced Accuracy 1.0000 1.0000 1.000
# Extract Precision, Recall, and F1 score for each class
precision <- conf_matrix$byClass[, "Pos Pred Value"]
recall <- conf_matrix$byClass[, "Sensitivity"]
f1_score <- conf_matrix$byClass[, "F1"]
# Prevalence (the proportion of each class in the actual data)
prevalence <- conf_matrix$byClass[, "Prevalence"]
# Calculate weighted metrics
weighted_precision <- sum(precision * prevalence)
weighted_recall <- sum(recall * prevalence)
weighted_f1 <- sum(f1_score * prevalence)
# Print the weighted metrics
cat("Weighted Precision:", weighted_precision, "\n")
## Weighted Precision: 1
cat("Weighted Recall:", weighted_recall, "\n")
## Weighted Recall: 1
cat("Weighted F1 Score:", weighted_f1, "\n")
## Weighted F1 Score: 1
Multinomial Logistic Regression Model
# Confusion Matrix
conf_matrix <- confusionMatrix(MLogRegClassification_predict, y_test,mode = "everything")
print(conf_matrix)
## Confusion Matrix and Statistics
##
## Reference
## Prediction economy business premium_economy
## economy 49664 0 0
## business 0 25307 0
## premium_economy 0 0 14072
##
## Overall Statistics
##
## Accuracy : 1
## 95% CI : (1, 1)
## No Information Rate : 0.5578
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 1
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: economy Class: business Class: premium_economy
## Sensitivity 1.0000 1.0000 1.000
## Specificity 1.0000 1.0000 1.000
## Pos Pred Value 1.0000 1.0000 1.000
## Neg Pred Value 1.0000 1.0000 1.000
## Precision 1.0000 1.0000 1.000
## Recall 1.0000 1.0000 1.000
## F1 1.0000 1.0000 1.000
## Prevalence 0.5578 0.2842 0.158
## Detection Rate 0.5578 0.2842 0.158
## Detection Prevalence 0.5578 0.2842 0.158
## Balanced Accuracy 1.0000 1.0000 1.000
# Overall Accuracy
accuracy <- conf_matrix$overall["Accuracy"]
cat("Overall Accuracy:", accuracy, "\n")
## Overall Accuracy: 1
# Extract Precision, Recall, and F1 score for each class
precision <- conf_matrix$byClass[, "Pos Pred Value"]
recall <- conf_matrix$byClass[, "Sensitivity"]
f1_score <- conf_matrix$byClass[, "F1"]
# Prevalence (the proportion of each class in the actual data)
prevalence <- conf_matrix$byClass[, "Prevalence"]
# Calculate weighted metrics
weighted_precision <- sum(precision * prevalence)
weighted_recall <- sum(recall * prevalence)
weighted_f1 <- sum(f1_score * prevalence)
# Print the weighted metrics
cat("Weighted Precision:", weighted_precision, "\n")
## Weighted Precision: 1
cat("Weighted Recall:", weighted_recall, "\n")
## Weighted Recall: 1
cat("Weighted F1 Score:", weighted_f1, "\n")
## Weighted F1 Score: 1
The flight fare prediction model showed different levels of performance across the three tested regression models: Linear Regression, Lasso Regression, and Ridge Regression. Linear regression is said to have achieved strong predictive ability with RMSE of 7.65, MAE of 4.99, and R2 of 0.86, whereas Lasso regression and Ridge regression produced similar results (Lasso: RSME 7.65, MAE 4.98, R2 0.86; Ridge: RSME 7.68, MAE 4.98, R2 0.86). These results indicate that Linear regression has better performance and higher accuracy than the other two models as it aligns more effectively with actual fare values. Nevertheless, the differences between the three models are minimal, thus it is suggested that all three models can be valuable depending on the deployment scenarios.
For class type classification model, Naive Bayes Classification has yielded an overall accuracy of 41.92%. The low accuracy rate may be attributed to its inability to handle dependencies between features. Although the model performed better in detecting premium economy and business classes, it is relatively weak in identifying economy class. In contrast, Support Vector Machine (SVM) and Multinomial Logistic Regression have achieved 100% accuracy with perfect sensitivity, specificity, precision, recall, and F1 scores across all classes. These indicate that both models can identify instances in each class without misclassification. Thus, the results suggest that SVM and Multinomial Logistic Regression models are superior and ideal choices for classifying flight classes.
In summary, the results suggest that Linear regression model provides reliable flight fares predictions, while SVM and Multinomial Logistic Regression are better models in classifying flight classes. These findings have set the foundation for deploying robust models to support predictions and classification in the flight industry.
The review process involves cross-validation for all the models (Linear regression, Lasso regression, Ridge regression) to ensure they provide reliable performance metrics and reduce the risks of overfitting. Hyperparameter tuning was also conducted to tweak the model performance for optimal results. For classification models, Naive Bayes model was reviewed due to its poor performance in detecting economy class. Nevertheless, the performance of each model was carefully validated using the dataset to ensure consistency across all classes.
The next steps involve refining the regression models by exploring additional pre-processing techniques, feature engineering, and hyperparameter optimisation to further reduce the errors (i.e. RMSE) and improve the model performance as well as accuracy. For classification, real-world data can be used to test SVM and Multinomial Logistic Regression models to ensure its reliability in production.
The deployment of flight fare prediction and class type classification models will follow a practical and structured plan to ensure smooth implementation. Firstly, Linear regression model and SVM/Multinomial Logistic Regression classification model will be integrated into airline’s booking system so that predictions for fare price and flight classes can be done in real time. Then, the models will be tested to ensure they performs well before launching. Once the models go live, their performance will be closely monitored to ensure they provide accurate results.
In terms of maintenance, the models will be updated regularly with new data to reflect the changes in pricing or classes. The models will be reviewed regularly to ensure they perform reliably and efficiently. Users’ feedback will also be collected to see if there is any inconsistencies and improve the models if needed.
In brief, this structured deployment plan will help to ensure that the models operate effectively and accurately while delivering long-term value for the industry.
In conclusion, the developed models for prediction and classification in this study have demonstrated potential in enhancing decision-making in airline industry. The results show that Linear regression model provides a strong foundation for the fare prediction while SVM and Multinomial Logistic Regression models excel in classifying flight classes. With the structured deployment plan, these models are ready to deliver long-term value by optimising operations and improving customers’ experience.
| Members | Roles | Contribution |
|---|---|---|
| Khor Kean Teng | Lead | Works on business understanding and data loading. Helps with notebook formatting and review. |
| Loong Shih-Wai | Member | Works on data preparation like selecting data and transforming data |
| Nur Maisarah Jalalulail | Member | Works on data understanding where visualizations and data summary are produced to understand any trends and patterns in the data |
| Pang Suk Min | Member | Works on models evaluation to interpret the model performance and deployment plan as well as conclusion |
| Tioh Zi Cong | Member | Works on modelling where machine learning models are trained and evaluated for flight fare classification and regression |