Group 4 Programming Data Science Assignment

0. Project Details

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. Business Understanding

1.1 Business Objective

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

  • Increase revenue by optimizing dynamic flight pricing
    • Achieve revenue increment by implementing machine learning models that set competitive ticket prices based on market conditions
  • Improve customer retention
    • Retain and enhance customer loyalty through tailored pricing strategies for frequent travelers
  • Enhance customer satisfaction ratings
    • Improve customer satisfaction metrics with competitive fares in each class while maintaining service quality

1.1.3 Business Success Criteria

  • Enhance forecasting
    • Achieve a measurable accuracy in flight fare prediction and classification by implementing machine learning model
  • Revenue optimization
    • Help airlines optimize their pricing strategy to maximize revenue and minimize seat wastage. Tools to assist customer to find the best time to book flight ticket can also be implemented to avoid overspending.
  • Operational efficiency
    • The implementation of machine learning model reduce the need for manual fare trends analysis as the model continuously learned from collected datasets

1.2 Situation Assessment

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.

1.3 Data Mining Goals

  • To implement machine learning models in airline flight ticket price prediction
  • To apply machine learning models in airline flight ticket classes classification
  • To evaluate the prediction and classification performance of the models with and without feature selection
  • To identify factors influencing airline flight ticket pricing and flight ticket classes

1.4 Project Plan

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. Data Understanding

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

2.2 Describe Data

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

2.3 Explore Data

  • Univariate
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)          )

  • Bivariate
# 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)
  )

  • Multivariate
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")

2.4 Verify Data Quality

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

3. Data Preparation

3.1 Select Data

Look at the data we have on hand
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-…

3.2 Clean Data

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 …

3.3 Construct Data

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

  • Republic Holiday / Basant Panchami / Sri Panchami : 2023-01-26
  • Hazarat Ali’s Birthday / Guru Ravi Das’ Birthday : 2023-02-05
  • Birthday of Swami Dayananda Saraswati : 2023-02-15
  • Maha Shiratri : 2023-02-18
  • Shiva ji Jayanti : 2023-02-19
# 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]])
}

3.4 Format Data

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

4. Modeling

4.1 Select Modeling Technique

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

  1. Naive Bayes Classification
  2. Support Vector Machine
  3. Multinomial Logistic Regression

4.2 Generate Test Design

# 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

4.3 Build Model

Flight Fare prediction model

  1. Linear Regression 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))

  1. Lasso Regressor Model
# 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))

  1. Ridge Regression Model
# 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)
  1. Support Vector Machine Classification Model
# 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)
  1. Multinomial Logistic Regression Model
# 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)

4.4 Assess Model

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

5. Evaluation

5.1 Evaluate Results & Discussions

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.

5.2 Review Process

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.

5.3 Determine Next Steps

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.

5.4 Deployment Plan (Including Monitoring and Maintenance)

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.

6. Conclusion

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.

7. Members’ Contributions

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