Synopsis

This analysis explores the U.S. NOAA storm dataset on Storm Data from 1950 ~ 2011 to answer questions about:

  1. the impacts of severe weather events on both population health and

  2. the economic impacts of losses on property and crops.

This analysis identifies the types of events most damaging to population health, in relation to fatalities and injuries, and event types that result in the highest economic losses. The results of this analysis would better inform disaster management strategies and resource allocations in anticipated severe weather conditions.

Data Processing

Th e storm data was loaded, which contains information on severe weather events. The data is stored in a CSV file, which was load into R. Data cleaning and some transformations ensured the data was appropriate for analysis.

Load Data

# load libraries
library(tidyverse)
library(readr)

#read in dataset
storm_data <- read_csv("/home/rstudio/Reproducible Research/week2/repdata_data_StormData1.csv")

#look at the structure of data read
str(storm_data)
## tibble [902,297 × 37] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ STATE__   : num [1:902297] 1 1 1 1 1 1 1 1 1 1 ...
##  $ BGN_DATE  : chr [1:902297] "4/18/1950 0:00:00" "4/18/1950 0:00:00" "2/20/1951 0:00:00" "6/8/1951 0:00:00" ...
##  $ BGN_TIME  : chr [1:902297] "0130" "0145" "1600" "0900" ...
##  $ TIME_ZONE : chr [1:902297] "CST" "CST" "CST" "CST" ...
##  $ COUNTY    : num [1:902297] 97 3 57 89 43 77 9 123 125 57 ...
##  $ COUNTYNAME: chr [1:902297] "MOBILE" "BALDWIN" "FAYETTE" "MADISON" ...
##  $ STATE     : chr [1:902297] "AL" "AL" "AL" "AL" ...
##  $ EVTYPE    : chr [1:902297] "TORNADO" "TORNADO" "TORNADO" "TORNADO" ...
##  $ BGN_RANGE : num [1:902297] 0 0 0 0 0 0 0 0 0 0 ...
##  $ BGN_AZI   : logi [1:902297] NA NA NA NA NA NA ...
##  $ BGN_LOCATI: logi [1:902297] NA NA NA NA NA NA ...
##  $ END_DATE  : logi [1:902297] NA NA NA NA NA NA ...
##  $ END_TIME  : logi [1:902297] NA NA NA NA NA NA ...
##  $ COUNTY_END: num [1:902297] 0 0 0 0 0 0 0 0 0 0 ...
##  $ COUNTYENDN: logi [1:902297] NA NA NA NA NA NA ...
##  $ END_RANGE : num [1:902297] 0 0 0 0 0 0 0 0 0 0 ...
##  $ END_AZI   : logi [1:902297] NA NA NA NA NA NA ...
##  $ END_LOCATI: logi [1:902297] NA NA NA NA NA NA ...
##  $ LENGTH    : num [1:902297] 14 2 0.1 0 0 1.5 1.5 0 3.3 2.3 ...
##  $ WIDTH     : num [1:902297] 100 150 123 100 150 177 33 33 100 100 ...
##  $ F         : num [1:902297] 3 2 2 2 2 2 2 1 3 3 ...
##  $ MAG       : num [1:902297] 0 0 0 0 0 0 0 0 0 0 ...
##  $ FATALITIES: num [1:902297] 0 0 0 0 0 0 0 0 1 0 ...
##  $ INJURIES  : num [1:902297] 15 0 2 2 2 6 1 0 14 0 ...
##  $ PROPDMG   : num [1:902297] 25 2.5 25 2.5 2.5 2.5 2.5 2.5 25 25 ...
##  $ PROPDMGEXP: chr [1:902297] "K" "K" "K" "K" ...
##  $ CROPDMG   : num [1:902297] 0 0 0 0 0 0 0 0 0 0 ...
##  $ CROPDMGEXP: logi [1:902297] NA NA NA NA NA NA ...
##  $ WFO       : logi [1:902297] NA NA NA NA NA NA ...
##  $ STATEOFFIC: logi [1:902297] NA NA NA NA NA NA ...
##  $ ZONENAMES : logi [1:902297] NA NA NA NA NA NA ...
##  $ LATITUDE  : num [1:902297] 3040 3042 3340 3458 3412 ...
##  $ LONGITUDE : num [1:902297] 8812 8755 8742 8626 8642 ...
##  $ LATITUDE_E: num [1:902297] 3051 0 0 0 0 ...
##  $ LONGITUDE_: num [1:902297] 8806 0 0 0 0 ...
##  $ REMARKS   : logi [1:902297] NA NA NA NA NA NA ...
##  $ REFNUM    : num [1:902297] 1 2 3 4 5 6 7 8 9 10 ...
##  - attr(*, "problems")= tibble [5,255,570 × 5] (S3: tbl_df/tbl/data.frame)
##   ..$ row     : int [1:5255570] 1671 1673 1674 1675 1678 1679 1680 1681 1682 1683 ...
##   ..$ col     : chr [1:5255570] "WFO" "WFO" "WFO" "WFO" ...
##   ..$ expected: chr [1:5255570] "1/0/T/F/TRUE/FALSE" "1/0/T/F/TRUE/FALSE" "1/0/T/F/TRUE/FALSE" "1/0/T/F/TRUE/FALSE" ...
##   ..$ actual  : chr [1:5255570] "NG" "NG" "NG" "NG" ...
##   ..$ file    : chr [1:5255570] "'/home/rstudio/Reproducible Research/week2/repdata_data_StormData1.csv'" "'/home/rstudio/Reproducible Research/week2/repdata_data_StormData1.csv'" "'/home/rstudio/Reproducible Research/week2/repdata_data_StormData1.csv'" "'/home/rstudio/Reproducible Research/week2/repdata_data_StormData1.csv'" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   STATE__ = col_double(),
##   ..   BGN_DATE = col_character(),
##   ..   BGN_TIME = col_character(),
##   ..   TIME_ZONE = col_character(),
##   ..   COUNTY = col_double(),
##   ..   COUNTYNAME = col_character(),
##   ..   STATE = col_character(),
##   ..   EVTYPE = col_character(),
##   ..   BGN_RANGE = col_double(),
##   ..   BGN_AZI = col_logical(),
##   ..   BGN_LOCATI = col_logical(),
##   ..   END_DATE = col_logical(),
##   ..   END_TIME = col_logical(),
##   ..   COUNTY_END = col_double(),
##   ..   COUNTYENDN = col_logical(),
##   ..   END_RANGE = col_double(),
##   ..   END_AZI = col_logical(),
##   ..   END_LOCATI = col_logical(),
##   ..   LENGTH = col_double(),
##   ..   WIDTH = col_double(),
##   ..   F = col_double(),
##   ..   MAG = col_double(),
##   ..   FATALITIES = col_double(),
##   ..   INJURIES = col_double(),
##   ..   PROPDMG = col_double(),
##   ..   PROPDMGEXP = col_character(),
##   ..   CROPDMG = col_double(),
##   ..   CROPDMGEXP = col_logical(),
##   ..   WFO = col_logical(),
##   ..   STATEOFFIC = col_logical(),
##   ..   ZONENAMES = col_logical(),
##   ..   LATITUDE = col_double(),
##   ..   LONGITUDE = col_double(),
##   ..   LATITUDE_E = col_double(),
##   ..   LONGITUDE_ = col_double(),
##   ..   REMARKS = col_logical(),
##   ..   REFNUM = col_double()
##   .. )

Data Cleaning

We then focus on the columns with relevant data. Empty andd missing rows were removed in the event type, fatalities, injuries, and damage estimates columns/rows.

#subset data: retain only columns for analysis - tidyverse
storm_data_clean <- storm_data %>%
  select(EVTYPE, FATALITIES, INJURIES, PROPDMG, PROPDMGEXP, CROPDMG, CROPDMGEXP)

# remove rows with missing data in the rows of interest
storm_data_clean <- storm_data_clean %>%
  filter(!is.na(EVTYPE) & (FATALITIES >= 0 | INJURIES >= 0 | PROPDMG >= 0 | CROPDMG >= 0))

#recode character columns + convert into character the columns before recoding
storm_data_clean <- storm_data_clean %>%
  mutate(PROPDMGEXP = recode(PROPDMGEXP, 
                             "K" = 1000, "M" = 1e6, "B" = 1e9, 
                             "k" = 1000, "m" = 1e6, "b" = 1e9, 
                             .default = 1)) %>%
  mutate(CROPDMGEXP = as.character(CROPDMGEXP),  # Convert CROPDMGEXP to character
         CROPDMGEXP = recode(CROPDMGEXP, 
                             "K" = 1000, "M" = 1e6, "B" = 1e9, 
                             "k" = 1000, "m" = 1e6, "b" = 1e9, 
                             .default = 1)) %>%
  #total damages calculation
  mutate(PROPDMG_TOTAL = PROPDMG * PROPDMGEXP,
         CROPDMG_TOTAL = CROPDMG * CROPDMGEXP)


# recode the property dmage and cropdamage columns then convert to numeric
storm_data_clean <- storm_data_clean %>%
  mutate(PROPDMGEXP = recode(PROPDMGEXP, "K" = 1000, "M" = 1e6, "B" = 1e9, "k" = 1000, "m" = 1e6, "b" = 1e9, .default = 1)) %>%
  mutate(CROPDMGEXP = recode(CROPDMGEXP, "K" = 1000, "M" = 1e6, "B" = 1e9, "k" = 1000, "m" = 1e6, "b" = 1e9, .default = 1))

#total damage calculatiob
storm_data_clean <- storm_data_clean %>%
  mutate(PROPDMG_TOTAL = PROPDMG * PROPDMGEXP, CROPDMG_TOTAL = CROPDMG * CROPDMGEXP)

#summary check of clean data
summary(storm_data_clean)
##     EVTYPE            FATALITIES          INJURIES            PROPDMG       
##  Length:902297      Min.   :  0.0000   Min.   :   0.0000   Min.   :   0.00  
##  Class :character   1st Qu.:  0.0000   1st Qu.:   0.0000   1st Qu.:   0.00  
##  Mode  :character   Median :  0.0000   Median :   0.0000   Median :   0.00  
##                     Mean   :  0.0168   Mean   :   0.1557   Mean   :  12.06  
##                     3rd Qu.:  0.0000   3rd Qu.:   0.0000   3rd Qu.:   0.50  
##                     Max.   :583.0000   Max.   :1700.0000   Max.   :5000.00  
##                                                                             
##    PROPDMGEXP        CROPDMG          CROPDMGEXP     PROPDMG_TOTAL   
##  Min.   :1        Min.   :  0.000   Min.   :1        Min.   :   0.0  
##  1st Qu.:1        1st Qu.:  0.000   1st Qu.:1        1st Qu.:   0.0  
##  Median :1        Median :  0.000   Median :1        Median :   1.0  
##  Mean   :1        Mean   :  1.527   Mean   :1        Mean   :  24.9  
##  3rd Qu.:1        3rd Qu.:  0.000   3rd Qu.:1        3rd Qu.:  10.0  
##  Max.   :1        Max.   :990.000   Max.   :1        Max.   :5000.0  
##  NA's   :465934                     NA's   :902278   NA's   :465934  
##  CROPDMG_TOTAL   
##  Min.   : 0.0    
##  1st Qu.: 0.0    
##  Median : 5.0    
##  Mean   :13.7    
##  3rd Qu.:22.5    
##  Max.   :60.0    
##  NA's   :902278

Results

Two questions needed to be answered:

  1. Which types of weather events were most harmful to population health?

  2. Which types of weather events had the greatest economic consequences?

Harmful Events to Population Health

Data was aggregated by event type to determine which had the highest fatalities and injuries. The result were then visualized.

#Data aggregate by event type
health_impact <- storm_data_clean %>%
  group_by(EVTYPE) %>%
  summarize(Total_Fatalities = sum(FATALITIES), Total_Injuries = sum(INJURIES)) %>%
  arrange(desc(Total_Fatalities + Total_Injuries))

#sort aggregated data plot
top_health_impact <- health_impact %>%
  top_n(10, Total_Fatalities + Total_Injuries)

#Bar plot to visualize the aggregated data
library(ggplot2)
ggplot(top_health_impact, aes(x = reorder(EVTYPE, Total_Fatalities + Total_Injuries), y = Total_Fatalities + Total_Injuries)) +
  geom_bar(stat = "identity", fill = "blue") +
  coord_flip() +
  labs(title = "Top 10 Weather Events Most Harmful to Population Health",
       x = "Event Type",
       y = "Total Fatalities and Injuries",
       caption = "Figure 1: Top 10 harmful weather events")

Economic Impact of Events

To determine the total economic impact, the property damage and crop damage were summed across all event types. The sum is then visualized.

#Data sum by event type per economic damage category
economic_impact <- storm_data_clean %>%
  group_by(EVTYPE) %>%
  summarize(Total_Property_Damage = sum(PROPDMG_TOTAL), Total_Crop_Damage = sum(CROPDMG_TOTAL)) %>%
  arrange(desc(Total_Property_Damage + Total_Crop_Damage))

#Bar plot sort by damaage
top_economic_impact <- economic_impact %>%
  top_n(1, Total_Property_Damage + Total_Crop_Damage)

#Visualize the dmage to property and crops
ggplot(top_economic_impact, aes(x = reorder(EVTYPE, Total_Property_Damage + Total_Crop_Damage), y = Total_Property_Damage + Total_Crop_Damage)) +
  geom_bar(stat = "identity", fill = "blue") +
  coord_flip() +
  labs(title = "Top Weather Event with Greatest Economic Damage",
       x = "Event Type",
       y = "Total Property and Crop Damage (USD billions)",
       caption = "Figure 2: Top weather event with the highest property and crop damage.")

Dicussion

This analysis identified the types of severe weather events with the most harmful impacts on population health and event type with the highest economic loss. This analysis can impact emergency management in prioritizing resources and responses in the likelihood of severe weather events/patterns.