In this report we explore the U.S. National Oceanic and Atmospheric Administration (NOAA) storm database. National Oceanic and Atmospheric Administration (NOAA). This database tracks characteristics of major storms and weather events in the United States, including when and where they occur, as well as estimates of any fatalities, injuries, and property damage. We will analyze the data to answer the following questions :
Our analysis concludes that:
Translated with DeepL.com (free version)
Library loading
if(!require(dplyr)) install.packages("ggplot2", dependencies=TRUE)
## Loading required package: 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
if(!require(ggplot2)) install.packages("ggplot2", dependencies=TRUE)
## Loading required package: ggplot2
if(!require(scales)) install.packages("ggplot2", dependencies=TRUE)
## Loading required package: scales
if(!require(gridExtra)) install.packages("ggplot2", dependencies=TRUE)
## Loading required package: gridExtra
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
library(dplyr)
library(ggplot2)
library(scales)
library(gridExtra)
Downloading and reading the file
file_storm <- "./repdata_data_StormData.csv.bz2"
if(!file.exists(file_storm)) {
url_storm <- "https://d396qusza40orc.cloudfront.net/repdata%2Fdata%2FStormData.csv.bz2"
download.file(url = url_storm, destfile = file_storm)
}
df_storm <- read.csv(bzfile(file_storm))
After loading the data, we will check the first rows and the data structure.
head(df_storm)
## 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
For the purpose of our analysis, we will select only the columns we are interested in. 1. FATALITIES AND INJURIES columns inform us about the effect of storms and meteorological phenomena on the health of the population 2. 2. The columns PROPDMG, PROPDMGEXP and CROPDMG, CROPDMGEXP tell us about the economic damage caused by storms and weather events by estimating the approximate losses (in dollars) of goods and crops.
colsToSelect <- c("BGN_DATE","EVTYPE","FATALITIES","INJURIES","PROPDMG","PROPDMGEXP","CROPDMG","CROPDMGEXP")
df_storm_short <- df_storm[, colsToSelect]
head(df_storm_short)
## BGN_DATE EVTYPE FATALITIES INJURIES PROPDMG PROPDMGEXP CROPDMG
## 1 4/18/1950 0:00:00 TORNADO 0 15 25.0 K 0
## 2 4/18/1950 0:00:00 TORNADO 0 0 2.5 K 0
## 3 2/20/1951 0:00:00 TORNADO 0 2 25.0 K 0
## 4 6/8/1951 0:00:00 TORNADO 0 2 2.5 K 0
## 5 11/15/1951 0:00:00 TORNADO 0 2 2.5 K 0
## 6 11/15/1951 0:00:00 TORNADO 0 6 2.5 K 0
## CROPDMGEXP
## 1
## 2
## 3
## 4
## 5
## 6
Checking unique values in PROPDMGEXP and CROPDMGEXP to understand the different types of characters used to indicate the multiplication factor to be applied to PROPDMG and CROPDMG respectively.
unique(df_storm_short$PROPDMGEXP)
## [1] "K" "M" "" "B" "m" "+" "0" "5" "6" "?" "4" "2" "3" "h" "7" "H" "-" "1" "8"
unique(df_storm_short$CROPDMGEXP)
## [1] "" "M" "K" "m" "B" "?" "0" "k" "2"
From the above we can understand the following correspondences:
Add a column for transforming character symbols into their corresponding multiplication factor
df_storm_short <- df_storm_short %>%
mutate(PROPDMGEXP2 = case_when(
(PROPDMGEXP == "h" | PROPDMGEXP == "H") ~ 100,
(PROPDMGEXP == "k" | PROPDMGEXP == "K") ~ 1000,
(PROPDMGEXP == "m" | PROPDMGEXP == "M") ~ 1000000,
(PROPDMGEXP == "b" | PROPDMGEXP == "B") ~ 1000000000,
PROPDMGEXP == "" ~ 1
),
CROPDMGEXP2 = case_when(
(CROPDMGEXP == "h" | CROPDMGEXP == "H") ~ 100,
(CROPDMGEXP == "k" | CROPDMGEXP == "K") ~ 1000,
(CROPDMGEXP == "m" | CROPDMGEXP == "M") ~ 1000000,
(CROPDMGEXP == "b" | CROPDMGEXP == "B") ~ 1000000000,
CROPDMGEXP == "" ~ 1
))
For the rest of the characters, we are NOT able to interpret the meaning. meaning. We will check how much data there is, apart from the characters we have identified, to understand the impact these data will have on our analysis
table(df_storm_short$PROPDMGEXP2, useNA = "ifany")
##
## 1 100 1000 1e+06 1e+09 <NA>
## 465934 7 424665 11337 40 314
table(df_storm_short$CROPDMGEXP2, useNA = "ifany")
##
## 1 1000 1e+06 1e+09 <NA>
## 618413 281853 1995 9 27
We can see here that the NA values, or the # of observations for which we were unable to interpret the characters, represent a very small percentage percent of the total number of observations. We will ignore the transformation of these observations.
calculation of the economic damage value with the derived multiplication factor derived factor
df_storm_short <- df_storm_short %>%
mutate(PROPDMGVAL = PROPDMG*PROPDMGEXP2,
CROPDMGVAL = CROPDMG*CROPDMGEXP2)
#fatalities2 <- tapply(df_storm_short$FATALITIES, df_storm_short$EVTYPE, sum)
#fatalities2 <- sort(fatalities2, decreasing = TRUE)
#fatalities2 <- fatalities2[1:10]
fatalities <- aggregate(FATALITIES ~ EVTYPE, df_storm_short, sum)
fatalities <- fatalities[order(-fatalities$FATALITIES), ]
fatalities <- fatalities[1:10,]
fatalities$EVTYPE <- factor(fatalities$EVTYPE, levels = fatalities$EVTYPE)
p1 <- ggplot(fatalities, aes(x = EVTYPE, y = FATALITIES)) + geom_bar(stat = "identity") + xlab("Event Type") + ylab("No of Fatalities") + ggtitle("Most Fatalities per Weather Event") + theme(axis.text.x = element_text(angle = 45, hjust = 1))
#injuries2 <- tapply(df_storm_short$INJURIES, df_storm_short$EVTYPE, sum)
#injuries2 <- sort(injuries2, decreasing = TRUE)
#injuries2 <- injuries2[1:10]
injuries <- aggregate(INJURIES ~ EVTYPE, df_storm_short, sum)
injuries <- injuries[order(-injuries$INJURIES),]
injuries <- injuries[1:10,]
injuries$EVTYPE <- factor(injuries$EVTYPE, levels = injuries$EVTYPE)
p2 <- ggplot(injuries, aes(x = EVTYPE, y = INJURIES)) + geom_bar(stat = "identity") + xlab("Event Type")+ ylab("No of Injuries") + ggtitle("Most Injuries per Weather Event") + theme(axis.text.x = element_text(angle = 45, hjust = 1))
grid.arrange(p1,p2, ncol = 2)
#### Answer 1: Tornado is the most damaging weather event to the health
of the population.
damages <- aggregate(PROPDMGVAL + CROPDMGVAL ~ EVTYPE, df_storm_short, sum)
names(damages) <- c("EVTYPE", "TOTDMG")
damages <- damages[order(-damages$TOTDMG), ]
damages <- damages[1:10, ]
damages$EVTYPE <- factor(damages$EVTYPE, levels = damages$EVTYPE)
p3 <- ggplot(damages, aes(x = EVTYPE, y = TOTDMG)) + geom_bar(stat = "identity") + xlab("Event Type") + ylab("Damages $") + ggtitle("Most Damgages (in USD) per Weather Event") + theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 7)) + scale_y_continuous(labels = label_number(suffix = " Bn", scale = 1e-09))
damages_nObs <- df_storm_short %>%
count(EVTYPE)
damages_nObs <- damages_nObs[damages_nObs$EVTYPE %in% damages[,1],]
damages_nObs$EVTYPE <- factor(damages_nObs$EVTYPE, levels = damages$EVTYPE)
p4<- ggplot(damages_nObs, aes(x = EVTYPE, y = n)) + geom_bar(stat = "identity") + geom_text(aes(label = n), vjust = -0.3, size = 3) + xlab("Event Type") + ylab("No of Events") + ggtitle("No of Events per Event Type") + theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 7)) + scale_y_continuous(labels = label_number(suffix = "K", scale = 1e-03))
grid.arrange(p3,p4)
#### Answer 2: Floods have had the greatest economic consequences.
However, if you look at the corresponding number of events, hurricanes
and typhoons are the deadliest weather events with the greatest economic
damage per event.