This analysis explores the U.S. NOAA storm dataset on Storm Data from 1950 ~ 2011 to answer questions about:
the impacts of severe weather events on both population health and
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.
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 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()
## .. )
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
Two questions needed to be answered:
Which types of weather events were most harmful to population health?
Which types of weather events had the greatest economic consequences?
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")
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.")
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.