Homework Assignment: Analyzing NYC Flight Data

This homework assignment uses the flights dataset from the nycflights13 package, which contains real-world data on over 336,000 flights departing from New York City airports (JFK, LGA, EWR) in 2013. The dataset includes variables such as departure and arrival times (with date components), airline carrier (categorical), origin and destination airports (categorical), delays (with missing values for cancelled flights), distance, and more. It is sourced from the US Bureau of Transportation Statistics.

Objectives

This assignment reinforces the Week 4 topics:

  • Parsing and manipulating dates/times using lubridate.
  • Creating and analyzing time series with zoo.
  • Working with factors, inspecting levels, and recoding them.
  • Identifying and handling missing data (e.g., removal, imputation).

All questions (except the final reflection) require you to write and run R code to solve them. Submit your URL for your RPubs. Make sure to comment your code, along with key outputs (e.g., summaries, plots, or tables). Use the provided setup code to load the data.

Setup

Install and load the necessary packages if not already done:

#install.packages(c("nycflights13", "dplyr", "lubridate", "zoo", "forcats"))  # If needed
library(nycflights13)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(zoo)
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(forcats)  # For factor recoding; base R alternatives are acceptable
data(flights)  # Load the dataset

Explore the data briefly with str(flights) and head(flights) to understand the structure. Note: Dates are in separate year, month, day columns; times are in dep_time and arr_time (as integers like 517 for 5:17 AM).

#Explore your data here

Question 1: Creating Dates with lubridate

Create a column dep_datetime by combining year, month, day, and dep_time into a POSIXct datetime using lubridate. (Hint: Use make_datetime function to combine: year, month, day, for hour and min use division, e.g., hour = dep_time %/% 100, min = dep_time %% 100.)

Show the first 5 rows of flights with dep_datetime.

Output: First 5 rows showing year, month, day, dep_time, and dep_datetime.

# Create a departure date and time column
flights <- flights %>%
  mutate(
    dep_datetime = make_datetime(
      year = year,
      month = month,
      day = day,
      hour = dep_time %/% 100,
      min = dep_time %% 100
    )
  )

# Display the first five rows
head(
  flights %>%
    select(year, month, day, dep_time, dep_datetime),
  5
)
## # A tibble: 5 × 5
##    year month   day dep_time dep_datetime       
##   <int> <int> <int>    <int> <dttm>             
## 1  2013     1     1      517 2013-01-01 05:17:00
## 2  2013     1     1      533 2013-01-01 05:33:00
## 3  2013     1     1      542 2013-01-01 05:42:00
## 4  2013     1     1      544 2013-01-01 05:44:00
## 5  2013     1     1      554 2013-01-01 05:54:00

Question 2: Simple Date Manipulations with lubridate

Using dep_datetime from Question 1, create a column weekday with the day of the week (e.g., “Mon”) using wday(dep_datetime, label = TRUE). Use table() to show how many flights occur on each weekday.

Output: The table of flight counts by weekday.

# Create a column showing the weekday for each flight
flights <- flights %>%
  mutate(
    weekday = wday(dep_datetime, label = TRUE, abbr = TRUE)
  )

# Display the number of flights for each weekday
table(flights$weekday)
## 
##   Sun   Mon   Tue   Wed   Thu   Fri   Sat 
## 45643 49468 49273 48858 48654 48703 37922

Question 3: Time Series with zoo

Filter for flights from JFK (origin == “JFK”) and create a zoo time series of departure delays (dep_delay) by dep_datetime. Plot the time series (use plot()). (Hint: Use a subset to avoid memory issues, e.g., first 1000 JFK flights using `slice_head().)

Output: The time series plot.

# Select the first 1,000 JFK flights with valid departure dates
jfk_flights <- flights %>%
  filter(origin == "JFK", !is.na(dep_datetime)) %>%
  slice_head(n = 1000)

# Create a zoo time series of departure delays
jfk_delays <- zoo(
  jfk_flights$dep_delay,
  order.by = jfk_flights$dep_datetime
)
## Warning in zoo(jfk_flights$dep_delay, order.by = jfk_flights$dep_datetime):
## some methods for "zoo" objects do not work if the index entries in 'order.by'
## are not unique
# Plot the departure delays over time
plot(
  jfk_delays,
  main = "Departure Delays for JFK Flights",
  xlab = "Departure Date and Time",
  ylab = "Departure Delay (Minutes)"
)

Question 4: Working with Factors

Convert the origin column (airports: “JFK”, “LGA”, “EWR”) to a factor called origin_factor. Show the factor levels with levels() and create a frequency table with table(). Make a bar plot of flights by airport using barplot().

Output: The levels, frequency table, and bar plot.

# Convert the origin column into a factor
flights <- flights %>%
  mutate(origin_factor = factor(origin))

# Display the factor levels
levels(flights$origin_factor)
## [1] "EWR" "JFK" "LGA"
# Count flights by airport
table(flights$origin_factor)
## 
##    EWR    JFK    LGA 
## 120835 111279 104662
# Create a bar plot of flights by airport
barplot(
  table(flights$origin_factor),
  main = "Number of Flights by Origin Airport",
  xlab = "Airport",
  ylab = "Number of Flights",
  col = "lightblue"
)

Question 5: Recoding Factors

Recode origin_factor from Question 4 into a new column origin_recoded with full names: “JFK” to “Kennedy”, “LGA” to “LaGuardia”, “EWR” to “Newark” using fct_recode() or base R. Create a bar plot of the recoded factor.

Output: The new levels and bar plot.

# Replace airport codes with full airport names
flights <- flights %>%
  mutate(
    origin_recoded = fct_recode(
      origin_factor,
      "Kennedy" = "JFK",
      "LaGuardia" = "LGA",
      "Newark" = "EWR"
    )
  )

# Display the new factor levels
levels(flights$origin_recoded)
## [1] "Newark"    "Kennedy"   "LaGuardia"
# Display the frequency table
table(flights$origin_recoded)
## 
##    Newark   Kennedy LaGuardia 
##    120835    111279    104662
# Create a bar plot using the full airport names
barplot(
  table(flights$origin_recoded),
  main = "Flights by Origin Airport",
  xlab = "Airport",
  ylab = "Number of Flights",
  col = "lightgreen"
)

Question 6: Handling Missing Data

Count missing values in dep_delay and arr_delay using colSums(is.na(flights)). Impute missing dep_delay values with 0 (assuming no delay for cancelled flights) in a new column dep_delay_imputed. Create a frequency table of dep_delay_imputed for delays between -20 and 20 minutes (use filter() to subset).

Output: NA counts, and the frequency table for imputed delays.

# Count missing values in departure and arrival delays
colSums(is.na(flights[, c("dep_delay", "arr_delay")]))
## dep_delay arr_delay 
##      8255      9430
# Create a new column that replaces missing departure delays with zero
flights <- flights %>%
  mutate(
    dep_delay_imputed = if_else(
      is.na(dep_delay),
      0,
      dep_delay
    )
  )

# Count imputed departure delays between -20 and 20 minutes
flights %>%
  filter(
    dep_delay_imputed >= -20,
    dep_delay_imputed <= 20
  ) %>%
  count(dep_delay_imputed, name = "frequency") %>%
  arrange(dep_delay_imputed)
## # A tibble: 41 × 2
##    dep_delay_imputed frequency
##                <dbl>     <int>
##  1               -20        37
##  2               -19        19
##  3               -18        81
##  4               -17       110
##  5               -16       162
##  6               -15       408
##  7               -14       498
##  8               -13       901
##  9               -12      1594
## 10               -11      2727
## # ℹ 31 more rows

Question 7: Reflection (No Coding)

Reflect on the assignment: What was easy or hard about working with flight dates or missing data? How might assuming zero delay for missing values (Question 6) affect conclusions about flight punctuality? What did you learn about NYC flights in 2013? (150-200 words)

Working on this assignment helped me understand how dates and times can be organized in R. Creating the departure datetime was useful because it combined separate date and time columns into one value that could be used for further analysis. I also learned how to use weekdays, factors, and time series to organize flight information and compare airports. One challenge was understanding missing data and how it can affect the results.

Replacing missing departure delays with zero makes the data easier to work with, but it can also be misleading. Some flights may have been cancelled, so assigning them a zero-minute delay could make it look like more flights were on time than actually were. This showed me why it is important to understand what missing values mean before changing them. I also learned that R can display flight patterns through tables and plots, making a large dataset easier to understand. Overall, this assignment helped me practice using R to organize real-world data and recognize that the way data is handled can affect the conclusions we make.