Lab 2: Introduction to Data

Author

Sarah Abdelrahman

Introduction

In this lab, I will explore a sample of domestic flights departing from the three major New York City airports in 2013. I will use R to examine departure and arrival delays, compare airports and airlines, and explore the relationship between flight distance and average speed.

Setup

First, I loaded the packages needed for the analysis.

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(openintro)
Loading required package: airports
Loading required package: cherryblossom
Loading required package: usdata

Load the Data

I loaded the nycflights dataset.

data(nycflights)

I checked the variable names and structure of the dataset.

names(nycflights)
 [1] "year"      "month"     "day"       "dep_time"  "dep_delay" "arr_time" 
 [7] "arr_delay" "carrier"   "tailnum"   "flight"    "origin"    "dest"     
[13] "air_time"  "distance"  "hour"      "minute"   
glimpse(nycflights)
Rows: 32,735
Columns: 16
$ year      <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, …
$ month     <int> 6, 5, 12, 5, 7, 1, 12, 8, 9, 4, 6, 11, 4, 3, 10, 1, 2, 8, 10…
$ day       <int> 30, 7, 8, 14, 21, 1, 9, 13, 26, 30, 17, 22, 26, 25, 21, 23, …
$ dep_time  <int> 940, 1657, 859, 1841, 1102, 1817, 1259, 1920, 725, 1323, 940…
$ dep_delay <dbl> 15, -3, -1, -4, -3, -3, 14, 85, -10, 62, 5, 5, -2, 115, -4, …
$ arr_time  <int> 1216, 2104, 1238, 2122, 1230, 2008, 1617, 2032, 1027, 1549, …
$ arr_delay <dbl> -4, 10, 11, -34, -8, 3, 22, 71, -8, 60, -4, -2, 22, 91, -6, …
$ carrier   <chr> "VX", "DL", "DL", "DL", "9E", "AA", "WN", "B6", "AA", "EV", …
$ tailnum   <chr> "N626VA", "N3760C", "N712TW", "N914DL", "N823AY", "N3AXAA", …
$ flight    <int> 407, 329, 422, 2391, 3652, 353, 1428, 1407, 2279, 4162, 20, …
$ origin    <chr> "JFK", "JFK", "JFK", "JFK", "LGA", "LGA", "EWR", "JFK", "LGA…
$ dest      <chr> "LAX", "SJU", "LAX", "TPA", "ORF", "ORD", "HOU", "IAD", "MIA…
$ air_time  <dbl> 313, 216, 376, 135, 50, 138, 240, 48, 148, 110, 50, 161, 87,…
$ distance  <dbl> 2475, 1598, 2475, 1005, 296, 733, 1411, 228, 1096, 820, 264,…
$ hour      <dbl> 9, 16, 8, 18, 11, 18, 12, 19, 7, 13, 9, 13, 8, 20, 12, 20, 6…
$ minute    <dbl> 40, 57, 59, 41, 2, 17, 59, 20, 25, 23, 40, 20, 9, 54, 17, 24…

Departure Delays

I first examined the distribution of departure delays.

ggplot(data = nycflights, aes(x = dep_delay)) +
  geom_histogram()
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

I then compared the distribution using different histogram bin widths.

ggplot(data = nycflights, aes(x = dep_delay)) +
  geom_histogram(binwidth = 15)

ggplot(data = nycflights, aes(x = dep_delay)) +
  geom_histogram(binwidth = 150)

Question 1

The three histograms show the same departure-delay data, but changing the bin width changes how much detail is visible. A smaller bin width shows more detail, while a larger bin width gives a smoother and more general view.

Most flights have relatively small departure delays, while a smaller number of flights have very large delays. Therefore, the distribution is strongly right-skewed.

Flights to Los Angeles

Next, I created a subset containing only flights traveling to Los Angeles.

lax_flights <- nycflights %>%
  filter(dest == "LAX")

I created a histogram of departure delays for these flights.

ggplot(data = lax_flights, aes(x = dep_delay)) +
  geom_histogram()
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

I also calculated summary statistics.

lax_flights %>%
  summarise(
    mean_dd = mean(dep_delay, na.rm = TRUE),
    median_dd = median(dep_delay, na.rm = TRUE),
    n = n()
  )
# A tibble: 1 × 3
  mean_dd median_dd     n
    <dbl>     <dbl> <int>
1    9.78        -1  1583

Flights to San Francisco in February

Question 2

I created a new data frame containing flights traveling to San Francisco during February.

sfo_feb_flights <- nycflights %>%
  filter(dest == "SFO", month == 2)

I counted the number of flights meeting these conditions.

nrow(sfo_feb_flights)
[1] 68

There are 68 flights traveling to San Francisco during February.

Question 3

I examined the distribution of arrival delays for the San Francisco flights.

ggplot(data = sfo_feb_flights, aes(x = arr_delay)) +
  geom_histogram(binwidth = 15)

I calculated several summary statistics.

sfo_feb_flights %>%
  summarise(
    mean_arr_delay = mean(arr_delay, na.rm = TRUE),
    median_arr_delay = median(arr_delay, na.rm = TRUE),
    sd_arr_delay = sd(arr_delay, na.rm = TRUE),
    iqr_arr_delay = IQR(arr_delay, na.rm = TRUE),
    min_arr_delay = min(arr_delay, na.rm = TRUE),
    max_arr_delay = max(arr_delay, na.rm = TRUE)
  )
# A tibble: 1 × 6
  mean_arr_delay median_arr_delay sd_arr_delay iqr_arr_delay min_arr_delay
           <dbl>            <dbl>        <dbl>         <dbl>         <dbl>
1           -4.5              -11         36.3          23.2           -66
# ℹ 1 more variable: max_arr_delay <dbl>

The distribution of arrival delays is right-skewed because most flights have smaller delays, while a few flights have much larger delays.

Because the distribution is skewed, the median and IQR are useful measures of center and spread.

The median arrival delay is -11 minutes, and the IQR is 23.25 minutes.

Question 4

Next, I grouped the flights by carrier and calculated the median and IQR of arrival delays.

carrier_summary <- sfo_feb_flights %>%
  group_by(carrier) %>%
  summarise(
    median_arr_delay = median(arr_delay, na.rm = TRUE),
    iqr_arr_delay = IQR(arr_delay, na.rm = TRUE),
    n_flights = n()
  ) %>%
  arrange(desc(iqr_arr_delay))

carrier_summary
# A tibble: 5 × 4
  carrier median_arr_delay iqr_arr_delay n_flights
  <chr>              <dbl>         <dbl>     <int>
1 DL                 -15            22          19
2 UA                 -10            22          21
3 VX                 -22.5          21.2        12
4 AA                   5            17.5        10
5 B6                 -10.5          12.2         6

I identified the airline with the largest IQR.

most_variable_carrier <- carrier_summary %>%
  slice_max(iqr_arr_delay, n = 1, with_ties = FALSE)

most_variable_carrier
# A tibble: 1 × 4
  carrier median_arr_delay iqr_arr_delay n_flights
  <chr>              <dbl>         <dbl>     <int>
1 DL                   -15            22        19

The carrier with the most variable arrival delays is DL, because it has the largest IQR of 22 minutes.

Departure Delays by Month

I calculated the mean and median departure delay for each month.

monthly_delays <- nycflights %>%
  group_by(month) %>%
  summarise(
    mean_dd = mean(dep_delay, na.rm = TRUE),
    median_dd = median(dep_delay, na.rm = TRUE)
  )

monthly_delays
# A tibble: 12 × 3
   month mean_dd median_dd
   <int>   <dbl>     <dbl>
 1     1   10.2         -2
 2     2   10.7         -2
 3     3   13.5         -1
 4     4   14.6         -2
 5     5   13.3         -1
 6     6   20.4          0
 7     7   20.8          0
 8     8   12.6         -1
 9     9    6.87        -3
10    10    5.88        -3
11    11    6.10        -2
12    12   17.4          1

I then arranged the months by average departure delay.

monthly_delays %>%
  arrange(mean_dd)
# A tibble: 12 × 3
   month mean_dd median_dd
   <int>   <dbl>     <dbl>
 1    10    5.88        -3
 2    11    6.10        -2
 3     9    6.87        -3
 4     1   10.2         -2
 5     2   10.7         -2
 6     8   12.6         -1
 7     5   13.3         -1
 8     3   13.5         -1
 9     4   14.6         -2
10    12   17.4          1
11     6   20.4          0
12     7   20.8          0

Question 5

The mean considers every departure delay value, but it can be strongly affected by a small number of extremely long delays.

The median is less affected by extreme values and may better represent the typical delay experienced by a traveler.

Because departure delays are right-skewed, I would prefer the median when selecting a month with lower typical delays.

However, the mean can still be useful because it reflects the effect of unusually large delays.

On-Time Departure Rate

For this analysis, a flight with a departure delay of less than five minutes is considered on time.

I created a new variable called dep_type to classify each flight.

nycflights <- nycflights %>%
  mutate(
    dep_type = ifelse(dep_delay < 5, "on time", "delayed")
  )

I then calculated the on-time departure rate for each airport.

airport_rates <- nycflights %>%
  group_by(origin) %>%
  summarise(
    ot_dep_rate =
      sum(dep_type == "on time", na.rm = TRUE) /
      sum(!is.na(dep_type))
  ) %>%
  arrange(desc(ot_dep_rate))

airport_rates
# A tibble: 3 × 2
  origin ot_dep_rate
  <chr>        <dbl>
1 LGA          0.728
2 JFK          0.694
3 EWR          0.637

Question 6

I identified the airport with the highest on-time departure rate.

best_airport <- airport_rates %>%
  slice_max(ot_dep_rate, n = 1, with_ties = FALSE)

best_airport
# A tibble: 1 × 2
  origin ot_dep_rate
  <chr>        <dbl>
1 LGA          0.728

If I were choosing an airport based only on on-time departure percentage, I would choose LGA.

Its on-time departure percentage is approximately 72.8%.

I also visualized the departure status for the three airports.

ggplot(data = nycflights, aes(x = origin, fill = dep_type)) +
  geom_bar()

Average Flight Speed

Question 7

I created a new variable called avg_speed.

Since air_time is measured in minutes, I converted it into hours before calculating the speed.

nycflights <- nycflights %>%
  mutate(
    avg_speed = distance / (air_time / 60)
  )

I checked the new variable.

nycflights %>%
  select(distance, air_time, avg_speed) %>%
  head()
# A tibble: 6 × 3
  distance air_time avg_speed
     <dbl>    <dbl>     <dbl>
1     2475      313      474.
2     1598      216      444.
3     2475      376      395.
4     1005      135      447.
5      296       50      355.
6      733      138      319.

The avg_speed variable represents the average speed of each flight in miles per hour.

Average Speed and Distance

Question 8

I created a scatterplot to examine the relationship between flight distance and average speed.

ggplot(
  data = nycflights,
  aes(x = distance, y = avg_speed)
) +
  geom_point(alpha = 0.3) +
  labs(
    title = "Average Speed vs. Distance",
    x = "Distance (miles)",
    y = "Average Speed (mph)"
  )

The scatterplot shows a positive relationship between distance and average speed.

In general, longer flights tend to have higher average speeds. Shorter flights have lower average speeds because takeoff and landing account for a larger proportion of their total flight time.

As distance increases, average speed tends to increase and eventually level off.

Departure Delay and Arrival Delay

Question 9

For the final analysis, I selected American Airlines, Delta Airlines, and United Airlines.

major_carriers <- nycflights %>%
  filter(carrier %in% c("AA", "DL", "UA"))

I created a scatterplot comparing departure delays and arrival delays.

ggplot(
  data = major_carriers,
  aes(
    x = dep_delay,
    y = arr_delay,
    color = carrier
  )
) +
  geom_point(alpha = 0.4) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  labs(
    title = "Departure Delay vs. Arrival Delay",
    x = "Departure Delay (minutes)",
    y = "Arrival Delay (minutes)",
    color = "Carrier"
  )

The plot shows a positive relationship between departure delays and arrival delays. Flights that leave later generally arrive later.

However, some flights are able to make up time during the trip. Based on the graph, flights departing approximately 20 minutes late or less may still arrive on time.

Conclusion

In this lab, I used the nycflights dataset to practice filtering, summarizing, grouping, creating new variables, and visualizing data in R.

The analysis showed that flight delays are generally right-skewed, airport on-time performance varies, and longer flights tend to have higher average speeds. I also observed that some flights can make up part of their departure delay while traveling.