The goal of this report is to explore the NOAA Storm Database and answer the following questions:
-Across the United States, which types of events are most harmful with respect to population health?
-Across the United States, which types of events have the greatest economic consequences?
The original dataset can be found here It was obtained and downloaded in bz format on 8/04/2024. All data processing and analysis were conducted in R Studio.
Upon importing the file, the data was grouped by event type and the sum of injuries and fatalities were calculated. Subsequently, a graph was generated with two plots illustrating the event types with the highest number of injuries and fatalities along with their corresponding figures.
To address the second question, two new columns were created to incorporate financial damage, encompassing both crop and property damage. The dataset was then grouped by event type and the sum of total damage caused by each event was calculated. Finally, a barplot was generated to visualize which event types incurred the most damage.
The details of the software used are below:
sessionInfo()
## R version 4.2.3 (2023-03-15 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19045)
##
## Matrix products: default
##
## locale:
## [1] LC_COLLATE=English_United Kingdom.utf8
## [2] LC_CTYPE=English_United Kingdom.utf8
## [3] LC_MONETARY=English_United Kingdom.utf8
## [4] LC_NUMERIC=C
## [5] LC_TIME=English_United Kingdom.utf8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## loaded via a namespace (and not attached):
## [1] digest_0.6.31 R6_2.5.1 jsonlite_1.8.4 evaluate_0.20
## [5] cachem_1.0.7 rlang_1.1.0 cli_3.6.1 rstudioapi_0.14
## [9] jquerylib_0.1.4 bslib_0.4.2 rmarkdown_2.21 tools_4.2.3
## [13] xfun_0.38 yaml_2.3.7 fastmap_1.1.1 compiler_4.2.3
## [17] htmltools_0.5.5 knitr_1.42 sass_0.4.5
The following libraries were loaded
# Load the packages
library(base)
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(ggplot2)
library(tidyr)
library(patchwork)
library(gridExtra)
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
A path was specified to the file
After opening the connection bz filed was read and the connection closed.
# Open a connection to the compressed file using bzfile
bzfile_conn <- bzfile(file_path, "r")
# Use read.csv to read the data from the compressed file
data <- read.csv(bzfile_conn)
# Close the connection
close(bzfile_conn)
After reading in the data we check summary of the dataset and the first few rows.
str(data)
## 'data.frame': 902297 obs. of 37 variables:
## $ STATE__ : num 1 1 1 1 1 1 1 1 1 1 ...
## $ BGN_DATE : chr "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 "0130" "0145" "1600" "0900" ...
## $ TIME_ZONE : chr "CST" "CST" "CST" "CST" ...
## $ COUNTY : num 97 3 57 89 43 77 9 123 125 57 ...
## $ COUNTYNAME: chr "MOBILE" "BALDWIN" "FAYETTE" "MADISON" ...
## $ STATE : chr "AL" "AL" "AL" "AL" ...
## $ EVTYPE : chr "TORNADO" "TORNADO" "TORNADO" "TORNADO" ...
## $ BGN_RANGE : num 0 0 0 0 0 0 0 0 0 0 ...
## $ BGN_AZI : chr "" "" "" "" ...
## $ BGN_LOCATI: chr "" "" "" "" ...
## $ END_DATE : chr "" "" "" "" ...
## $ END_TIME : chr "" "" "" "" ...
## $ COUNTY_END: num 0 0 0 0 0 0 0 0 0 0 ...
## $ COUNTYENDN: logi NA NA NA NA NA NA ...
## $ END_RANGE : num 0 0 0 0 0 0 0 0 0 0 ...
## $ END_AZI : chr "" "" "" "" ...
## $ END_LOCATI: chr "" "" "" "" ...
## $ LENGTH : num 14 2 0.1 0 0 1.5 1.5 0 3.3 2.3 ...
## $ WIDTH : num 100 150 123 100 150 177 33 33 100 100 ...
## $ F : int 3 2 2 2 2 2 2 1 3 3 ...
## $ MAG : num 0 0 0 0 0 0 0 0 0 0 ...
## $ FATALITIES: num 0 0 0 0 0 0 0 0 1 0 ...
## $ INJURIES : num 15 0 2 2 2 6 1 0 14 0 ...
## $ PROPDMG : num 25 2.5 25 2.5 2.5 2.5 2.5 2.5 25 25 ...
## $ PROPDMGEXP: chr "K" "K" "K" "K" ...
## $ CROPDMG : num 0 0 0 0 0 0 0 0 0 0 ...
## $ CROPDMGEXP: chr "" "" "" "" ...
## $ WFO : chr "" "" "" "" ...
## $ STATEOFFIC: chr "" "" "" "" ...
## $ ZONENAMES : chr "" "" "" "" ...
## $ LATITUDE : num 3040 3042 3340 3458 3412 ...
## $ LONGITUDE : num 8812 8755 8742 8626 8642 ...
## $ LATITUDE_E: num 3051 0 0 0 0 ...
## $ LONGITUDE_: num 8806 0 0 0 0 ...
## $ REMARKS : chr "" "" "" "" ...
## $ REFNUM : num 1 2 3 4 5 6 7 8 9 10 ...
head(data)
## STATE__ BGN_DATE BGN_TIME TIME_ZONE COUNTY COUNTYNAME STATE EVTYPE
## 1 1 4/18/1950 0:00:00 0130 CST 97 MOBILE AL TORNADO
## 2 1 4/18/1950 0:00:00 0145 CST 3 BALDWIN AL TORNADO
## 3 1 2/20/1951 0:00:00 1600 CST 57 FAYETTE AL TORNADO
## 4 1 6/8/1951 0:00:00 0900 CST 89 MADISON AL TORNADO
## 5 1 11/15/1951 0:00:00 1500 CST 43 CULLMAN AL TORNADO
## 6 1 11/15/1951 0:00:00 2000 CST 77 LAUDERDALE AL TORNADO
## BGN_RANGE BGN_AZI BGN_LOCATI END_DATE END_TIME COUNTY_END COUNTYENDN
## 1 0 0 NA
## 2 0 0 NA
## 3 0 0 NA
## 4 0 0 NA
## 5 0 0 NA
## 6 0 0 NA
## END_RANGE END_AZI END_LOCATI LENGTH WIDTH F MAG FATALITIES INJURIES PROPDMG
## 1 0 14.0 100 3 0 0 15 25.0
## 2 0 2.0 150 2 0 0 0 2.5
## 3 0 0.1 123 2 0 0 2 25.0
## 4 0 0.0 100 2 0 0 2 2.5
## 5 0 0.0 150 2 0 0 2 2.5
## 6 0 1.5 177 2 0 0 6 2.5
## PROPDMGEXP CROPDMG CROPDMGEXP WFO STATEOFFIC ZONENAMES LATITUDE LONGITUDE
## 1 K 0 3040 8812
## 2 K 0 3042 8755
## 3 K 0 3340 8742
## 4 K 0 3458 8626
## 5 K 0 3412 8642
## 6 K 0 3450 8748
## LATITUDE_E LONGITUDE_ REMARKS REFNUM
## 1 3051 8806 1
## 2 0 0 2
## 3 0 0 3
## 4 0 0 4
## 5 0 0 5
## 6 0 0 6
The columns we are interested in for the first question are EVTYPE, FATALITIES and INJURIES and for the second one EVTYPE, PROPDMG, PROPDMGEXP, CROPDMG and CROPDMGEXP.
columns_of_interest <- c("EVTYPE","FATALITIES","INJURIES","PROPDMG","CROPDMG","PROPDMGEXP","CROPDMGEXP")
missing_values <- colSums(is.na(data[, columns_of_interest]))
According to the NATIONAL WEATHER SERVICE INSTRUCTION 10-1605 the following Alphabetical characters are used to signify magnitude are “K” for thousands, “M” for millions, and “B” for billion for damage.
unique(data$PROPDMGEXP)
## [1] "K" "M" "" "B" "m" "+" "0" "5" "6" "?" "4" "2" "3" "h" "7" "H" "-" "1" "8"
unique(data$CROPDMGEXP)
## [1] "" "M" "K" "m" "B" "?" "0" "k" "2"
not_stndsrd1 <- sum(data$PROPDMGEXP != "K" & data$PROPDMGEXP != "M" & data$PROPDMGEXP != "B" & data$PROPDMGEXP != "" )
not_stndsrd2 <- sum(data$CROPDMGEXP != "K" & data$CROPDMGEXP != "M" & data$CROPDMGEXP != "B" & data$CROPDMGEXP != "" )
not_stndsrd1/902297
## [1] 0.0003635167
not_stndsrd2/902297
## [1] 5.430584e-05
Looking at the unique values we can see that the proportion of invalid characters (“K”,“M”,“B”, ““) is low so we choose to ignore these.
In order to show the weather events with the greatest population health consequences, we can group the data by event type and calculate the total number of injuries and fatalities for each type.
data_gb <- data %>% group_by(EVTYPE) %>% summarise(sum_fatalities =sum(FATALITIES),sum_injuries =sum(INJURIES))
summary(data_gb)
## EVTYPE sum_fatalities sum_injuries
## Length:985 Min. : 0.00 Min. : 0.0
## Class :character 1st Qu.: 0.00 1st Qu.: 0.0
## Mode :character Median : 0.00 Median : 0.0
## Mean : 15.38 Mean : 142.7
## 3rd Qu.: 0.00 3rd Qu.: 0.0
## Max. :5633.00 Max. :91346.0
Here (above) we can see that there are 985 types of event categories listed and the mean and maximum number of fatalities are 15.38 and 5633 respectively and the mean and maximum number of injuries are 142.7 and 91346 respectively.
Subsequently, we generate a graph with two plots illustrating the top 15 event types with the highest number of injuries and fatalities.
plot_fatalities <- ggplot(data_gb %>% top_n(15, sum_fatalities), aes(x = sum_fatalities, y = reorder(EVTYPE, sum_fatalities))) +
geom_bar(stat = "identity", color = "black", fill='pink', width = 0.7) +
labs(x = "Number of fatalities", y = NULL ) +
theme(plot.title = element_text(hjust = 0.5)) +
theme_minimal()
plot_injuries <- ggplot(data_gb %>% top_n(15, sum_injuries), aes(x = sum_injuries, y = reorder(EVTYPE, sum_injuries))) +
geom_bar(stat = "identity", color = "black", fill='#D02090', width = 0.7) +
labs(x = "Number of injuries", y = NULL) +
ggtitle("The most harmful types of events with respect to population health") +
theme(plot.title = element_text(hjust = 0.5)) +
theme_minimal()
plot_injuries + plot_fatalities + plot_layout(ncol = 2, widths = c(5,2))
From the plot above we can see that there are substantially more injuries than fatalities which occurred due to weather events. Tornado causes both the highest number of fatalities and injuries and they are significantly higher than any of the other weather events. Most event categories are present on both graphs. Interestingly there are a few categories that cause a high number of deaths but not many injuries for example avalanche, heat wave and rip current. On the other hand wildfire and heavy snow are categories that were listed among the weather events with the 15 highest number of injuries but not listed with the highest number of fatalities.
So far, we have looked at the health damage caused. The second question is related to the economic consequences of weather events. We have added 2 new columns to have the actual value of damage recorded. The original data set records both property and crop damage as numeric values rounded to three significant digits. Both of these columns are followed by an alphabetical character signifying the magnitude of the number including “K” for thousands, “M” for millions, and “B” for billions. We have added 2 new columns to have the actual value of damage recorded. These two column values were copied from the property and crop value columns and were multiplied by the correct number based on the alphabetical character recorded. We created a third column that adds the property and crop damage to have a total economic damage recorded.
data$p_dam <- data$PROPDMG
data$c_dam <- data$CROPDMG
result_data <- data %>% mutate(p_dam = case_when(PROPDMGEXP == "K" ~ PROPDMG * 1000,
PROPDMGEXP == "M" ~ PROPDMG * 1000000,
PROPDMGEXP == "B" ~ PROPDMG * 1000000000))
result_data <- data %>% mutate(c_dam = case_when(CROPDMGEXP == "K" ~ CROPDMG * 1000,
CROPDMGEXP == "M" ~ CROPDMG * 1000000,
CROPDMGEXP == "B" ~ CROPDMG * 1000000000))
result_data$c_p_dam <- result_data$p_dam+ result_data$c_dam
To show the weather events with the greatest economic consequences, we can group the data by event type and calculate the total economic damage caused.
fin_gb <- result_data %>% group_by(EVTYPE) %>% summarise(sum_dam =sum(c_p_dam))
Subsequently, we create a graph to show the combined crop and property damage by event type sorted in descending order displaying the top 15.
plot_c_p_dam <- ggplot(fin_gb %>% top_n(15, sum_dam), aes(x = sum_dam / 1e6, y = reorder(EVTYPE, sum_dam))) +
geom_bar(stat = "identity", color = "black", fill = '#008B45' ,width = 0.7) +
labs(x = "Crop and Property Damage (in million US Dollar)", y = NULL) +
ggtitle("Events with the greatest economic consequences") +
theme(plot.title = element_text(hjust = 0.5)) +
theme_minimal()
plot_c_p_dam
Looking at the graph we can see that categories with related to “wet” and “cold” conditions are responsible for most of the financial damage caused followed by “freeze” and “frost” followed by other “wet” and “wind” categories. The categories that caused the most financial damage do not coincide with the categories causing the most public health harm.