NYC Flights 2023 Analysis

Author

George Bothos

Loading Libraries

I am loading the tidyverse and nycflights23 packages so I can access the flight data

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(nycflights23)

Loading and Filtering Flight Data

I am just loading the flights and airlines dataset and underneath it filtering it so that I can filter out the missing values for arrival delay.

data(flights)
data(airlines)

flights_clean <- flights |>
  filter(!is.na(arr_delay))

Converting the Carrier codes to get the Full Names

I am going to join the dataset from flights with the airlines dataset so that the carrier codes that are 2 letters can be converted into a full airline name, making it more clean and not having the corporate suffixes.

flights_joined <- left_join(flights_clean, airlines, by = "carrier")
flights_joined$name <- gsub("Inc\\.|Co\\.", "", flights_joined$name)
flights_joined$name <- trimws(flights_joined$name)

Calculating Average Arrival Delay for Airline

The flights will be grouped by the airline name, and I will get the average arrival delay and flight count for each carrier. Then I am going to create a status category that shows if the airline arrives delayed or on time on average.

airline_summary <- flights_joined |>
  group_by(name) |>
  summarise(
    total_flights = n(),
    avg_arr_delay = mean(arr_delay),
    .groups = "drop"
  ) |>
  filter(total_flights >= 1000) |>
  mutate(status = ifelse(avg_arr_delay > 0, "Average Delay", "Average Early / On-Time"))

airline_summary
# A tibble: 11 × 4
   name               total_flights avg_arr_delay status                 
   <chr>                      <int>         <dbl> <chr>                  
 1 Alaska Airlines             7734        0.0844 Average Delay          
 2 American Airlines          39750        5.27   Average Delay          
 3 Delta Air Lines            60364        1.64   Average Delay          
 4 Endeavor Air               52204       -2.23   Average Early / On-Time
 5 Frontier Airlines           1218       26.2    Average Delay          
 6 JetBlue Airways            64280       15.6    Average Delay          
 7 Republic Airline           85431       -4.64   Average Early / On-Time
 8 SkyWest Airlines            6199       13.7    Average Delay          
 9 Southwest Airlines         12048        5.76   Average Delay          
10 Spirit Air Lines           14769        9.89   Average Delay          
11 United Air Lines           77438        9.04   Average Delay          

Average Arrival Delay by Airline

I will create a horizontal bar chart displaying average arrival delays for major carriers departing New York City airports, with bars colored by performance status.

I am creating a horizontal bar chart that shows the average arrival delays for the big and major carriers that depart from New York City airports. The bars are colored by their performance status.

ggplot(airline_summary, aes(x = avg_arr_delay, y = reorder(name, avg_arr_delay), fill = status)) +
  geom_col(width = 0.7) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray40") +
  scale_fill_manual(
    values = c("Average Delay" = "#E5484D", "Average Early / On-Time" = "#46A758")
  ) +
  labs(
    title = "Average Arrival Delay by Major Airline Departing NYC (2023)",
    subtitle = "Carriers with at least 1,000 scheduled flights",
    x = "Average Arrival Delay (Minutes)",
    y = "Airline",
    fill = "Performance Status",
    caption = "Source: FAA Aircraft Registry via nycflights23"
  ) +
  theme_minimal()

While building this visualization from the nycflights23 dataset I made sure to follow the professor’s rules from the notes by restraining from using na.omit() on the whole dataset because that would make some useful data be deleted and not be able to get it back. Therefore, instead, I decided to only filter out the missing values for the arrival delay. Then, just like in our Unit 5 notes, I used left_join() with the airlines table, and then I cleaned the names with gsub(). That way, the chart could show real airline names instead of the two-letter codes, just like the assignment instructions told me to do so.

Now, looking beyond the instructions and further into the visualization I created, I decided to group the data by airline, and I used summarise() to be able to get the average delay and the total flights for carriers that had at least 1,000 trips. I decided to create a horizontal bar chart because it’s easier for me to understand and read, and it helps me. My horizontal bar chart orders the airlines by their average delay that they had. It gave them the color red if their average was a delay, and on the other hand, if they averaged arriving early, then they got a green color assigned to them.

Something that I noticed from this, which was also a really big takeaway, is that the different airlines had different results, which was pretty interesting to me. In addition, Frontier had the worst record, with over 25 minutes of average delay, which is suprising to me. Some other regional carriers, on the other hand, like Republic Airlines and Endeavor Air, were actually averaging negative delays, which means that they were landing early. This showed me that the risk of my flight getting delayed, or anyone’s flight, changes a lot, and it’s pretty dependent on which airline you decide to actually book out of New York City.