Airline_Dealys

Author

Reginald Dorcely

Quarto

Quarto enables you to weave together content and executable code into a finished document. To learn more about Quarto see https://quarto.org.

Running Code

When you click the Render button a document will be generated that includes both content and the output of embedded code. You can embed code like this:

# ============================================================
# AIRLINE DELAYS
# ============================================================

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(knitr)
library(scales)

Attaching package: 'scales'

The following object is masked from 'package:purrr':

    discard

The following object is masked from 'package:readr':

    col_factor
 # Original Wide Data

airline_wide <- tibble(
  Airline = c("ALASKA", NA, "AM WEST", NA),
  Status = c("On Time", "Delayed", "On Time", "Delayed"),
  `Los Angeles` = c(497, 62, 694, 117),
  Phoenix = c(221, 12, 4840, 415),
  `San Diego` = c(212, 20, 383, 65),
  `San Francisco` = c(503, 102, 320, 129),
  Seattle = c(1841, 305, 201, 61)
)

print(airline_wide)
# A tibble: 4 × 7
  Airline Status  `Los Angeles` Phoenix `San Diego` `San Francisco` Seattle
  <chr>   <chr>           <dbl>   <dbl>       <dbl>           <dbl>   <dbl>
1 ALASKA  On Time           497     221         212             503    1841
2 <NA>    Delayed            62      12          20             102     305
3 AM WEST On Time           694    4840         383             320     201
4 <NA>    Delayed           117     415          65             129      61
kable(
  airline_wide,
  caption = "Original Wide-Format Airline Delay Data"
)
Original Wide-Format Airline Delay Data
Airline Status Los Angeles Phoenix San Diego San Francisco Seattle
ALASKA On Time 497 221 212 503 1841
NA Delayed 62 12 20 102 305
AM WEST On Time 694 4840 383 320 201
NA Delayed 117 415 65 129 61
write.csv(
  airline_wide,
  "airline_delays_wide.csv",
  row.names = FALSE
)

# Populate Missing Data

# Check for missing values

colSums(is.na(airline_wide))
      Airline        Status   Los Angeles       Phoenix     San Diego 
            2             0             0             0             0 
San Francisco       Seattle 
            0             0 
# Fill the missing airline names
airline_filled <- airline_wide %>%
  fill(
    Airline,
    .direction = "down"
  )

print(airline_filled)
# A tibble: 4 × 7
  Airline Status  `Los Angeles` Phoenix `San Diego` `San Francisco` Seattle
  <chr>   <chr>           <dbl>   <dbl>       <dbl>           <dbl>   <dbl>
1 ALASKA  On Time           497     221         212             503    1841
2 ALASKA  Delayed            62      12          20             102     305
3 AM WEST On Time           694    4840         383             320     201
4 AM WEST Delayed           117     415          65             129      61
kable(
  airline_filled,
  caption = "Airline Data After Populating Missing Values"
)
Airline Data After Populating Missing Values
Airline Status Los Angeles Phoenix San Diego San Francisco Seattle
ALASKA On Time 497 221 212 503 1841
ALASKA Delayed 62 12 20 102 305
AM WEST On Time 694 4840 383 320 201
AM WEST Delayed 117 415 65 129 61
# Count Analysis

count_analysis <- airline_filled %>%
  rowwise() %>%
  mutate(
    Row_Total = sum(
      c_across(`Los Angeles`:Seattle)
    )
  ) %>%
  ungroup()

print(count_analysis)
# A tibble: 4 × 8
  Airline Status  `Los Angeles` Phoenix `San Diego` `San Francisco` Seattle
  <chr>   <chr>           <dbl>   <dbl>       <dbl>           <dbl>   <dbl>
1 ALASKA  On Time           497     221         212             503    1841
2 ALASKA  Delayed            62      12          20             102     305
3 AM WEST On Time           694    4840         383             320     201
4 AM WEST Delayed           117     415          65             129      61
# ℹ 1 more variable: Row_Total <dbl>
kable(
  count_analysis,
  caption = "Flight Count Analysis"
)
Flight Count Analysis
Airline Status Los Angeles Phoenix San Diego San Francisco Seattle Row_Total
ALASKA On Time 497 221 212 503 1841 3274
ALASKA Delayed 62 12 20 102 305 501
AM WEST On Time 694 4840 383 320 201 6438
AM WEST Delayed 117 415 65 129 61 787
# Count by Status

count_summary <- count_analysis %>%
  select(
    Airline,
    Status,
    Row_Total
  )

print(count_summary)
# A tibble: 4 × 3
  Airline Status  Row_Total
  <chr>   <chr>       <dbl>
1 ALASKA  On Time      3274
2 ALASKA  Delayed       501
3 AM WEST On Time      6438
4 AM WEST Delayed       787
kable(
  count_summary,
  caption = "Total Flight Counts by Airline and Status"
)
Total Flight Counts by Airline and Status
Airline Status Row_Total
ALASKA On Time 3274
ALASKA Delayed 501
AM WEST On Time 6438
AM WEST Delayed 787
# Transform Wide Data to Long Format

airline_long <- airline_filled %>%
  pivot_longer(
    cols = `Los Angeles`:Seattle,
    names_to = "City",
    values_to = "Flights"
  )

print(airline_long)
# A tibble: 20 × 4
   Airline Status  City          Flights
   <chr>   <chr>   <chr>           <dbl>
 1 ALASKA  On Time Los Angeles       497
 2 ALASKA  On Time Phoenix           221
 3 ALASKA  On Time San Diego         212
 4 ALASKA  On Time San Francisco     503
 5 ALASKA  On Time Seattle          1841
 6 ALASKA  Delayed Los Angeles        62
 7 ALASKA  Delayed Phoenix            12
 8 ALASKA  Delayed San Diego          20
 9 ALASKA  Delayed San Francisco     102
10 ALASKA  Delayed Seattle           305
11 AM WEST On Time Los Angeles       694
12 AM WEST On Time Phoenix          4840
13 AM WEST On Time San Diego         383
14 AM WEST On Time San Francisco     320
15 AM WEST On Time Seattle           201
16 AM WEST Delayed Los Angeles       117
17 AM WEST Delayed Phoenix           415
18 AM WEST Delayed San Diego          65
19 AM WEST Delayed San Francisco     129
20 AM WEST Delayed Seattle            61
kable(
  airline_long,
  caption = "Long-Format Airline Delay Data"
)
Long-Format Airline Delay Data
Airline Status City Flights
ALASKA On Time Los Angeles 497
ALASKA On Time Phoenix 221
ALASKA On Time San Diego 212
ALASKA On Time San Francisco 503
ALASKA On Time Seattle 1841
ALASKA Delayed Los Angeles 62
ALASKA Delayed Phoenix 12
ALASKA Delayed San Diego 20
ALASKA Delayed San Francisco 102
ALASKA Delayed Seattle 305
AM WEST On Time Los Angeles 694
AM WEST On Time Phoenix 4840
AM WEST On Time San Diego 383
AM WEST On Time San Francisco 320
AM WEST On Time Seattle 201
AM WEST Delayed Los Angeles 117
AM WEST Delayed Phoenix 415
AM WEST Delayed San Diego 65
AM WEST Delayed San Francisco 129
AM WEST Delayed Seattle 61
# Now reshape the status variable for analysis

airline_tidy <- airline_long %>%
  pivot_wider(
    names_from = Status,
    values_from = Flights
  ) %>%
  mutate(
    Total = `On Time` + Delayed,
    Delay_Rate = Delayed / Total,
    On_Time_Rate = `On Time` / Total
  ) %>%
  arrange(
    City,
    Airline
  )

print(airline_tidy)
# A tibble: 10 × 7
   Airline City          `On Time` Delayed Total Delay_Rate On_Time_Rate
   <chr>   <chr>             <dbl>   <dbl> <dbl>      <dbl>        <dbl>
 1 ALASKA  Los Angeles         497      62   559     0.111         0.889
 2 AM WEST Los Angeles         694     117   811     0.144         0.856
 3 ALASKA  Phoenix             221      12   233     0.0515        0.948
 4 AM WEST Phoenix            4840     415  5255     0.0790        0.921
 5 ALASKA  San Diego           212      20   232     0.0862        0.914
 6 AM WEST San Diego           383      65   448     0.145         0.855
 7 ALASKA  San Francisco       503     102   605     0.169         0.831
 8 AM WEST San Francisco       320     129   449     0.287         0.713
 9 ALASKA  Seattle            1841     305  2146     0.142         0.858
10 AM WEST Seattle             201      61   262     0.233         0.767
# Formatted Table

kable(
  airline_tidy %>%
    mutate(
      Delay_Rate = percent(
        Delay_Rate,
        accuracy = 0.1
      ),
      On_Time_Rate = percent(
        On_Time_Rate,
        accuracy = 0.1
      )
    ),
  caption = "Tidied Airline Data with Percentages"
)
Tidied Airline Data with Percentages
Airline City On Time Delayed Total Delay_Rate On_Time_Rate
ALASKA Los Angeles 497 62 559 11.1% 88.9%
AM WEST Los Angeles 694 117 811 14.4% 85.6%
ALASKA Phoenix 221 12 233 5.2% 94.8%
AM WEST Phoenix 4840 415 5255 7.9% 92.1%
ALASKA San Diego 212 20 232 8.6% 91.4%
AM WEST San Diego 383 65 448 14.5% 85.5%
ALASKA San Francisco 503 102 605 16.9% 83.1%
AM WEST San Francisco 320 129 449 28.7% 71.3%
ALASKA Seattle 1841 305 2146 14.2% 85.8%
AM WEST Seattle 201 61 262 23.3% 76.7%
# Overall Airline Delay Comparison

overall_summary <- airline_tidy %>%
  group_by(Airline) %>%
  summarise(
    On_Time = sum(`On Time`),
    Delayed = sum(Delayed),
    Total = sum(Total),
    Delay_Rate = Delayed / Total,
    On_Time_Rate = On_Time / Total,
    .groups = "drop"
  )

print(overall_summary)
# A tibble: 2 × 6
  Airline On_Time Delayed Total Delay_Rate On_Time_Rate
  <chr>     <dbl>   <dbl> <dbl>      <dbl>        <dbl>
1 ALASKA     3274     501  3775      0.133        0.867
2 AM WEST    6438     787  7225      0.109        0.891
overall_display <- overall_summary %>%
  mutate(
    Delay_Rate = percent(
      Delay_Rate,
      accuracy = 0.1
    ),
    On_Time_Rate = percent(
      On_Time_Rate,
      accuracy = 0.1
    )
  )

kable(
  overall_display,
  caption = "Overall Airline Performance"
)
Overall Airline Performance
Airline On_Time Delayed Total Delay_Rate On_Time_Rate
ALASKA 3274 501 3775 13.3% 86.7%
AM WEST 6438 787 7225 10.9% 89.1%
overall_display <- overall_summary %>%
  mutate(
    Delay_Rate = percent(
      Delay_Rate,
      accuracy = 0.1
    ),
    On_Time_Rate = percent(
      On_Time_Rate,
      accuracy = 0.1
    )
  )

kable(
  overall_display,
  caption = "Overall Airline Performance"
)
Overall Airline Performance
Airline On_Time Delayed Total Delay_Rate On_Time_Rate
ALASKA 3274 501 3775 13.3% 86.7%
AM WEST 6438 787 7225 10.9% 89.1%
ggplot(
  overall_summary,
  aes(
    x = Airline,
    y = Delay_Rate,
    fill = Airline
  )
) +
  geom_col(
    width = 0.6
  ) +
  geom_text(
    aes(
      label = percent(
        Delay_Rate,
        accuracy = 0.1
      )
    ),
    vjust = -0.4
  ) +
  scale_y_continuous(
    labels = percent_format()
  ) +
  labs(
    title = "Overall Percentage of Delayed Flights",
    x = "Airline",
    y = "Delay Rate"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none"
  )

# Alaska had 501 delayed flights out of 3,775 total flights, for an overall
# delay rate of approximately 13.3%. AM West had 787 delayed flights out of
# 7,225 total flights, for an overall delay rate of approximately 10.9%.

# Based only on the overall percentages, AM West appears to have the lower
# delay rate.

# Delay Comparison Across Five Cities

city_summary <- airline_tidy %>%
  select(
    Airline,
    City,
    `On Time`,
    Delayed,
    Total,
    Delay_Rate
  ) %>%
  arrange(
    City,
    Airline
  )

print(city_summary)
# A tibble: 10 × 6
   Airline City          `On Time` Delayed Total Delay_Rate
   <chr>   <chr>             <dbl>   <dbl> <dbl>      <dbl>
 1 ALASKA  Los Angeles         497      62   559     0.111 
 2 AM WEST Los Angeles         694     117   811     0.144 
 3 ALASKA  Phoenix             221      12   233     0.0515
 4 AM WEST Phoenix            4840     415  5255     0.0790
 5 ALASKA  San Diego           212      20   232     0.0862
 6 AM WEST San Diego           383      65   448     0.145 
 7 ALASKA  San Francisco       503     102   605     0.169 
 8 AM WEST San Francisco       320     129   449     0.287 
 9 ALASKA  Seattle            1841     305  2146     0.142 
10 AM WEST Seattle             201      61   262     0.233 
# Table
kable(
  city_summary %>%
    mutate(
      Delay_Rate = percent(
        Delay_Rate,
        accuracy = 0.1
      )
    ),
  caption = "Delay Percentages by Airline and City"
)
Delay Percentages by Airline and City
Airline City On Time Delayed Total Delay_Rate
ALASKA Los Angeles 497 62 559 11.1%
AM WEST Los Angeles 694 117 811 14.4%
ALASKA Phoenix 221 12 233 5.2%
AM WEST Phoenix 4840 415 5255 7.9%
ALASKA San Diego 212 20 232 8.6%
AM WEST San Diego 383 65 448 14.5%
ALASKA San Francisco 503 102 605 16.9%
AM WEST San Francisco 320 129 449 28.7%
ALASKA Seattle 1841 305 2146 14.2%
AM WEST Seattle 201 61 262 23.3%
# Side-by-Side Compariosn
city_comparison <- city_summary %>%
  select(
    City,
    Airline,
    Delay_Rate
  ) %>%
  pivot_wider(
    names_from = Airline,
    values_from = Delay_Rate
  )

print(city_comparison)
# A tibble: 5 × 3
  City          ALASKA `AM WEST`
  <chr>          <dbl>     <dbl>
1 Los Angeles   0.111     0.144 
2 Phoenix       0.0515    0.0790
3 San Diego     0.0862    0.145 
4 San Francisco 0.169     0.287 
5 Seattle       0.142     0.233 
# Side-by-Side Table
city_comparison_display <- city_comparison %>%
  mutate(
    ALASKA = percent(
      ALASKA,
      accuracy = 0.1
    ),
    `AM WEST` = percent(
      `AM WEST`,
      accuracy = 0.1
    )
  )

kable(
  city_comparison_display,
  caption = "Delay Rates Across Five Cities"
)
Delay Rates Across Five Cities
City ALASKA AM WEST
Los Angeles 11.1% 14.4%
Phoenix 5.2% 7.9%
San Diego 8.6% 14.5%
San Francisco 16.9% 28.7%
Seattle 14.2% 23.3%
# City-by-city Graph
ggplot(
  city_summary,
  aes(
    x = City,
    y = Delay_Rate,
    fill = Airline
  )
) +
  geom_col(
    position = "dodge"
  ) +
  geom_text(
    aes(
      label = percent(
        Delay_Rate,
        accuracy = 0.1
      )
    ),
    position = position_dodge(
      width = 0.9
    ),
    vjust = -0.3,
    size = 3
  ) +
  scale_y_continuous(
    labels = percent_format()
  ) +
  labs(
    title = "Delay Rates Across Five Cities",
    x = "City",
    y = "Delay Rate",
    fill = "Airline"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(
      angle = 30,
      hjust = 1
    )
  )

# Identify the better airline in each city

better_by_city <- city_summary %>%
  group_by(City) %>%
  slice_min(
    order_by = Delay_Rate,
    n = 1,
    with_ties = FALSE
  ) %>%
  ungroup() %>%
  select(
    City,
    Airline,
    Delay_Rate
  )

print(better_by_city)
# A tibble: 5 × 3
  City          Airline Delay_Rate
  <chr>         <chr>        <dbl>
1 Los Angeles   ALASKA      0.111 
2 Phoenix       ALASKA      0.0515
3 San Diego     ALASKA      0.0862
4 San Francisco ALASKA      0.169 
5 Seattle       ALASKA      0.142 
# The city-by-city results show that Alaska had the lower delay percentage in
# all five destinations:
  
  # Los Angeles: Alaska 11.1% vs. AM West 14.4%
 # Phoenix: Alaska 5.2% vs. AM West 7.9%
  # San Diego: Alaska 8.6% vs. AM West 14.5%
 # San Francisco: Alaska 16.9% vs. AM West 28.7%
  # Seattle: Alaska 14.2% vs. AM West 23.3%
  
  # Therefore, Alaska performed better within each individual destination.


# Overall vs. City-by-City Discrepancy

better_overall <- overall_summary %>%
  slice_min(
    order_by = Delay_Rate,
    n = 1,
    with_ties = FALSE
  ) %>%
  select(
    Airline,
    Delay_Rate
  )

print(better_overall)
# A tibble: 1 × 2
  Airline Delay_Rate
  <chr>        <dbl>
1 AM WEST      0.109
# The overall comparison and the city-by-city comparison lead to different
# conclusions.

# Overall, AM West has the lower delay rate, approximately 10.9%, compared
# with Alaska's 13.3%. However, Alaska has the lower delay percentage in every
# one of the five individual cities.

# This discrepancy occurs because the two airlines do not operate the same
# number of flights in each city. The overall delay percentage is weighted by
# the number of flights.

# AM West operates a very large number of flights in Phoenix, where its delay
# rate is relatively low. These thousands of Phoenix flights strongly reduce
# AM West's overall delay percentage.

# As a result, AM West appears better overall even though Alaska performs
# better in every individual city.

# This type of reversal between subgroup results and combined results is known
# as Simpson's Paradox.


print(overall_summary)
# A tibble: 2 × 6
  Airline On_Time Delayed Total Delay_Rate On_Time_Rate
  <chr>     <dbl>   <dbl> <dbl>      <dbl>        <dbl>
1 ALASKA     3274     501  3775      0.133        0.867
2 AM WEST    6438     787  7225      0.109        0.891
print(city_comparison)
# A tibble: 5 × 3
  City          ALASKA `AM WEST`
  <chr>          <dbl>     <dbl>
1 Los Angeles   0.111     0.144 
2 Phoenix       0.0515    0.0790
3 San Diego     0.0862    0.145 
4 San Francisco 0.169     0.287 
5 Seattle       0.142     0.233 
print(better_by_city)
# A tibble: 5 × 3
  City          Airline Delay_Rate
  <chr>         <chr>        <dbl>
1 Los Angeles   ALASKA      0.111 
2 Phoenix       ALASKA      0.0515
3 San Diego     ALASKA      0.0862
4 San Francisco ALASKA      0.169 
5 Seattle       ALASKA      0.142 
print(better_overall)
# A tibble: 1 × 2
  Airline Delay_Rate
  <chr>        <dbl>
1 AM WEST      0.109