A. Introduction

The COVID-19 pandemic impacted many areas of life for people around the world. In 2023, WHO declared the pandemic to be over but people, industries, and economies globally still feel COVID-19’s lasting impact (Centers for Disease Control and Prevention, 2023). One industry severely affected by COVID-19 is the airline industry. As countries rushed to contain the virus, borders closed, travel plans were cancelled and flights were grounded, halting an entire sector overnight.

Has airline travel recovered to pre-pandemic levels? To investigate, I am using enplanement data retrieved from National Capital Region Transportation Planning Board to analyze the three DMV international airports: Dulles International Airport (IAD), Washington National Airport (DCA), and Baltimore/Washington International Thurgood Marshall Airport (BWI).

Source: Washington Metropolitan Council of Governments, Enplanement data 2000-2023. (https://rtdc-mwcog.opendata.arcgis.com/documents/b58ae0e96b034867afd809a9896b9442/about)

#import the libraries and data sets
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(dslabs)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.1     ✔ readr     2.2.0
## ✔ ggplot2   4.0.3     ✔ stringr   1.6.0
## ✔ lubridate 1.9.5     ✔ tibble    3.3.1
## ✔ purrr     1.2.2     ✔ tidyr     1.3.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(readxl)
## Warning: package 'readxl' was built under R version 4.6.1
setwd("/Users/cassidystauffer/Documents/MCCC/Data 101/Week 6") #Set the working directory to the correct folder

enplanement_19 <- read_excel("Enplanement_Data.xlsx", #Read the excel file
                          sheet = "2019" #Choose the sheet from 2019
                                    )
enplanement_19
## # A tibble: 36 × 11
##     Year Month    Airport Enplaned Deplaned Enplaned_Deplaned Dom_Enplaned
##    <dbl> <chr>    <chr>      <dbl>    <dbl>             <dbl>        <dbl>
##  1  2019 January  BWI       894637   898974           1793611       845630
##  2  2019 January  DCA       789540   830426           1619966       777640
##  3  2019 January  IAD       774129   827238           1601367       529654
##  4  2019 February BWI       835130   824399           1659529       789757
##  5  2019 February DCA       820575   814965           1635540       809281
##  6  2019 February IAD       728391   724784           1453175       497127
##  7  2019 March    BWI      1104285  1117183           2221468      1046214
##  8  2019 March    DCA      1041578  1055493           2097071      1025050
##  9  2019 March    IAD       971146   991241           1962387       661039
## 10  2019 April    BWI      1137744  1114088           2251832      1090516
## # ℹ 26 more rows
## # ℹ 4 more variables: Intl_Enplaned <dbl>, Dom_Intl_Enplaned <dbl>,
## #   Year_txt <chr>, YM <chr>
#excel_sheets("Enplanement_Data.xlsx")

B. Data Analysis

For my exploratory data analysis, I used the head function to get an understanding of the data in the file. I then went back and I chose to filter the data by airport and by year and to do that I needed to first import the individual sheets I would need. Next I used the “anyNA” function to check for empty values. Fortunately, my data had none. I then removed the columns I would not need. I repeated these steps for all three airports for from 2019-2021. I then used the mean function to find the average enplaned value from each airport, each year to see if there was a anything that stood out. Before plotting, I used the rbind function to combine the nine data frames I had cleaned.

head(enplanement_19)
## # A tibble: 6 × 11
##    Year Month    Airport Enplaned Deplaned Enplaned_Deplaned Dom_Enplaned
##   <dbl> <chr>    <chr>      <dbl>    <dbl>             <dbl>        <dbl>
## 1  2019 January  BWI       894637   898974           1793611       845630
## 2  2019 January  DCA       789540   830426           1619966       777640
## 3  2019 January  IAD       774129   827238           1601367       529654
## 4  2019 February BWI       835130   824399           1659529       789757
## 5  2019 February DCA       820575   814965           1635540       809281
## 6  2019 February IAD       728391   724784           1453175       497127
## # ℹ 4 more variables: Intl_Enplaned <dbl>, Dom_Intl_Enplaned <dbl>,
## #   Year_txt <chr>, YM <chr>
str(enplanement_19)
## tibble [36 × 11] (S3: tbl_df/tbl/data.frame)
##  $ Year             : num [1:36] 2019 2019 2019 2019 2019 ...
##  $ Month            : chr [1:36] "January" "January" "January" "February" ...
##  $ Airport          : chr [1:36] "BWI" "DCA" "IAD" "BWI" ...
##  $ Enplaned         : num [1:36] 894637 789540 774129 835130 820575 ...
##  $ Deplaned         : num [1:36] 898974 830426 827238 824399 814965 ...
##  $ Enplaned_Deplaned: num [1:36] 1793611 1619966 1601367 1659529 1635540 ...
##  $ Dom_Enplaned     : num [1:36] 845630 777640 529654 789757 809281 ...
##  $ Intl_Enplaned    : num [1:36] 49008 11900 244475 45373 11294 ...
##  $ Dom_Intl_Enplaned: num [1:36] 894637 789540 774129 835130 820575 ...
##  $ Year_txt         : chr [1:36] "2019" "2019" "2019" "2019" ...
##  $ YM               : chr [1:36] "2019-01" "2019-01" "2019-01" "2019-02" ...
#Clean the data
anyNA(enplanement_19) #Check for NAs
## [1] FALSE
#Get rid of the columns I won't need
enplanement_19[c("Enplaned_Deplaned", "Dom_Intl_Enplaned", "YM", "NM")] <- list(NULL)
#Filter by airport
iad_19 <- enplanement_19 %>% filter(Airport == "IAD")
iad_19
## # A tibble: 12 × 8
##     Year Month     Airport Enplaned Deplaned Dom_Enplaned Intl_Enplaned Year_txt
##    <dbl> <chr>     <chr>      <dbl>    <dbl>        <dbl>         <dbl> <chr>   
##  1  2019 January   IAD       774129   827238       529654        244475 2019    
##  2  2019 February  IAD       728391   724784       497127        231264 2019    
##  3  2019 March     IAD       971146   991241       661039        310107 2019    
##  4  2019 April     IAD      1002803  1027129       673277        329526 2019    
##  5  2019 May       IAD      1132554  1103661       731276        401278 2019    
##  6  2019 June      IAD      1220533  1169625       769138        451395 2019    
##  7  2019 July      IAD      1218537  1242379       790993        427544 2019    
##  8  2019 August    IAD      1165068  1205995       746671        418397 2019    
##  9  2019 September IAD       998394  1021301       648148        350246 2019    
## 10  2019 October   IAD      1077888  1079480       733527        344361 2019    
## 11  2019 November  IAD       979843   963309       670758        309221 2019    
## 12  2019 December  IAD      1059640  1005350       700370        359270 2019
iad_19_avg <-mean(iad_19$Enplaned) #Average enplanements a month in 2019 at IAD
iad_19_avg
## [1] 1027410
bwi_19 <- enplanement_19 %>% filter(Airport == "BWI") #Filter for BWI
bwi_19_avg <-mean(bwi_19$Enplaned) #Average enplanements a month in 2019 at BWI
bwi_19_avg
## [1] 1128479
dca_19 <- enplanement_19 %>% filter(Airport == "DCA")
dca_19_avg <-mean(dca_19$Enplaned) #Average enplanements a month in 2019 at DCA
#2020 data

enplanement_20 <- read_excel("Enplanement_Data.xlsx", #Read the excel file
                          sheet = "2020" #Choose the sheet from 2020
                                    )

anyNA(enplanement_20) #Check for NAs
## [1] FALSE
#Get rid of the columns I won't need
enplanement_20[c("Enplaned_Deplaned", "Dom_Intl_Enplaned", "YM", "NM")] <- list(NULL)
#Filter by airport
iad_20 <- enplanement_20 %>% filter(Airport == "IAD")
#iad_20
iad_20_avg <-mean(iad_20$Enplaned) #Average enplanements a month in 2020 at IAD
iad_20_avg
## [1] 340614
bwi_20 <- enplanement_20 %>% filter(Airport == "BWI") #Filter for BWI
bwi_20_avg <-mean(bwi_20$Enplaned) #Average enplanements a month in 2020 at BWI
bwi_20_avg
## [1] 467233.4
dca_20 <- enplanement_20 %>% filter(Airport == "DCA")
dca_20_avg <-mean(dca_20$Enplaned) #Average enplanements a month in 2020 at DCA
dca_20_avg
## [1] 313961.4
#2021 data

enplanement_21 <- read_excel("Enplanement_Data.xlsx", #Read the excel file
                          sheet = "2021" #Choose the sheet from 2021
                                    )

anyNA(enplanement_21) #Check for NAs
## [1] FALSE
#Get rid of the columns I won't need
enplanement_21[c("Enplaned_Deplaned", "Dom_Intl_Enplaned", "YM", "NM")] <- list(NULL)
#Filter by airport
iad_21 <- enplanement_21 %>% filter(Airport == "IAD")
#iad_20
iad_21_avg <-mean(iad_21$Enplaned) #Average enplanements a month in 2021 at IAD
iad_21_avg
## [1] 614618.2
bwi_21 <- enplanement_21 %>% filter(Airport == "BWI") #Filter for BWI
bwi_21_avg <-mean(bwi_21$Enplaned) #Average enplanements a month in 2021 at BWI
bwi_21_avg
## [1] 784436.3
dca_21 <- enplanement_21 %>% filter(Airport == "DCA")
dca_21_avg <-mean(dca_21$Enplaned) #Average enplanements a month in 2021 at DCA
dca_21_avg
## [1] 587413.6
#Combine the data from 2019-2021
updated_enplanement <- rbind(iad_19, iad_20, iad_21, dca_19, dca_20, dca_21, bwi_19, bwi_20, bwi_21)

updated_enplanement
## # A tibble: 108 × 8
##     Year Month     Airport Enplaned Deplaned Dom_Enplaned Intl_Enplaned Year_txt
##    <dbl> <chr>     <chr>      <dbl>    <dbl>        <dbl>         <dbl> <chr>   
##  1  2019 January   IAD       774129   827238       529654        244475 2019    
##  2  2019 February  IAD       728391   724784       497127        231264 2019    
##  3  2019 March     IAD       971146   991241       661039        310107 2019    
##  4  2019 April     IAD      1002803  1027129       673277        329526 2019    
##  5  2019 May       IAD      1132554  1103661       731276        401278 2019    
##  6  2019 June      IAD      1220533  1169625       769138        451395 2019    
##  7  2019 July      IAD      1218537  1242379       790993        427544 2019    
##  8  2019 August    IAD      1165068  1205995       746671        418397 2019    
##  9  2019 September IAD       998394  1021301       648148        350246 2019    
## 10  2019 October   IAD      1077888  1079480       733527        344361 2019    
## # ℹ 98 more rows
iad_19_avg
## [1] 1027410
iad_20_avg
## [1] 340614
iad_21_avg 
## [1] 614618.2
dca_19_avg
## [1] 995753.5
dca_20_avg
## [1] 313961.4
dca_21_avg
## [1] 587413.6
bwi_19_avg
## [1] 1128479
bwi_20_avg
## [1] 467233.4
bwi_21_avg
## [1] 784436.3
#Graph the data

library(ggplot2)
ggplot(updated_enplanement,
       aes(x = Airport,
           y = Enplaned,
           fill = factor(Year))) +
  geom_col(position = "dodge") +
  scale_y_continuous(
    labels = scales::label_comma())+
  labs(
    title = "Enplanement Trends of DC Area Airports from 2019-2021",
    x = "Airport",
    y = "Number of Enplanements",
    fill = "Year"
  ) +
  theme_minimal() +
  theme(
     axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(
      color = "gray80",
      linewidth = 0.4
    ),
    panel.grid.minor.y = element_line(
      color = "gray90",
      linewidth = 0.2
    ),
    panel.grid.major.x = element_blank()
  )

C. Conclusion

In conclusion, the pandemic impacted all three airports and airport travel has not returned to pre-pandemic levels as of 2021. BWI and DCA saw a positive recovery while IAD’s total enplanements for 2021 decreased compared to 2020.

To further the analysis of this data, I think looking at the emplacements by month in addition to year would be a good indicator of how busy each airport is throughout the year. While COVID-19 is one event that impacts air travel, there are many other that could be taking place concurrently such as severe weather.

D. References

Centers for Disease Control and Prevention. (2023, September 12). End of the federal COVID-19 public health emergency (PHE) declaration. https://archive.cdc.gov/www_cdc_gov/coronavirus/2019-ncov/your-health/end-of-phe.html

Metropolitan Washington Council of Governments. (n.d.). Enplanement data: 2000–2023 [Data set]. Regional Transportation Data Clearinghouse. https://rtdc-mwcog.opendata.arcgis.com/documents/b58ae0e96b034867afd809a9896b9442/about