This research identifies the weather events that caused the most harm to human health and the most economic damages in the US since the beginning of the year 2000 through November of 2011.
I found that tornadoes, excessive heat, lightning, and thunderstorms were the events causing the most injuries and fatalities. I also found that floods, hurricanes/typhoons, storm surges, and tornadoes caused the most economic damage as measured by damages to crops and property.
To complete this analysis, I used the U.S. National Oceanic and Atmospheric Administration’s (NOAA) storm database, covering events since 1950. In order to perform my analysis, I extracted the data for the years under analysis, chose the variables measuring harm and economic damage, and recoded the databases categorization of the weather events to make that categorization more consistent.
I donwloaded the data from the course website and read it into a data frame:
fileUrl <- "https://d396qusza40orc.cloudfront.net/repdata%2Fdata%2FStormData.csv.bz2"
download.file(fileUrl, destfile = "database.csv.bz2")
dat <- read.csv("database.csv.bz2", na.strings = c("", "NA"))
str(dat)
## '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 NA NA NA NA ...
## $ BGN_LOCATI: chr NA NA NA NA ...
## $ END_DATE : chr NA NA NA NA ...
## $ END_TIME : chr NA NA NA NA ...
## $ 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 NA NA NA NA ...
## $ END_LOCATI: chr NA NA NA NA ...
## $ 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 NA NA NA NA ...
## $ WFO : chr NA NA NA NA ...
## $ STATEOFFIC: chr NA NA NA NA ...
## $ ZONENAMES : chr NA NA NA NA ...
## $ 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 NA NA NA NA ...
## $ REFNUM : num 1 2 3 4 5 6 7 8 9 10 ...
I then cleaned up the variable names by making them lower case and removing "_" signs.
names(dat) <- tolower(names(dat))
names(dat) <- gsub("_", "", names(dat))
The variables indicating the beginning (bgndate) and end (enddate) dates of each event are formatted as characters, and contain uninformative time data - a string “0:00:00” is placed at the end of every entry. I thus modified these two data variables by removing the uninformative string and formatting the result as a date.
#remove uninformative 0:00:00 string from bgndate and enddate
dat$bgndate <- gsub(" 0:00:00", "", dat$bgndate)
dat$enddate <- gsub(" 0:00:00", "", dat$enddate)
#convert to date format
dat$bgndate <- as.Date(dat$bgndate, "%m/%d/%Y")
dat$enddate <- as.Date(dat$enddate, "%m/%d/%Y")
In keeping with the principles of tidy data, I deleted the first column, containing a variable named “state” which took on numerical values, and the fifth column, containing a variable named “county” which also took on numerical values. The reason why I deleted these columns is that the database contains other columns, respectively titled “state” and “countyname” that presented the same information in a more descriptive way (with full county names and abbreviated state names rather than numerical codes).
dat <- dat[, -c(1, 5)]
To further clean the database, I ran the code below to find which variables contained actual information:
apply(dat, 2, function(x) length(unique(x)))
This allowed me to idenfity the variables that had one unique value (countyend and countyendn). Since these variables always display the same value, they are uniformative, so I deleted them:
#loads tidyverse package
library(tidyverse)
dat <- dat %>% select(!c(countyend, countyendn))
I then created a new dataframe with the variables that might be relevant to this project:
subdat <- dat %>% select(bgndate, countyname, state, evtype, fatalities:cropdmgexp)
The resulting dataframe is tidy-ish. There are inconsistencies in how several variables are coded, but fixing this would take an amount of time that I think is unreasonable for the assignment at hand. I thus treated the resulting dataframe as the basis from which I will subset the analytic data.
The goal of the project is to find the events that cause the greatest harm to human health and those with the greatest economic consequences. Since data far into the past are more incomplete,as stated in the assignment prompt, and they are also more unevenly coded (typos or inconsistent notation are frequent), it is reasonable to conjecture that old data might introduce bias in our analysis, in particular if some events were sistematically less likely to be coded correctly.
I thus decided to restrict attention in my analysis to events occuring since 01/01/2000. This is an arbitrary threshold, but without an amount of work and knowledge beyond the scope of this assignment it is impossible to arrive at an appropriate threshold. The code below create the subseted data:
andat <- subset(subdat, bgndate > as.Date("1999-12-31"))
I measure the harm caused by an event to a population’s health as the sum of the variables “fatalities” and “injuries:”
andat$harm <- andat$fatalities + andat$injuries
Two variables are relevant to the calculation of the economic impact of a weather event: “propdmg” and “cropdmg.” The values that these variables take are expressed in different units depending on the weather event. These units are expressed in the variables “propdmgexp” and “cropdmgexp.” I ran the function unique to determine the units in which the variables are expressed:
unique(andat$propdmgexp)
## [1] "K" NA "M" "B" "0"
unique(andat$cropdmgexp)
## [1] "K" NA "M" "B"
After reading the documentation of the database, I determined that K corresponds to thousands, M to millions, and B to Billions. 0 and NA mean that there is no record of damage. The different scales in which damages are expressed makes it necessary to calculate new variables that use uniform scales. I will do this using a for loop with a if test. Since a value of NA does not return TRUE or FALSE in an if test, I must first convert the NAS in columns “propdmgexp” and “cropdmgexp:”
#replace NAs using tools from the tidyr package
andat$propdmgexp <- andat$propdmgexp %>% replace_na(0)
andat$cropdmgexp <- andat$cropdmgexp %>% replace_na(0)
I can now run a for loop with if conditions to create a new variable called “property” that calculates the property damages in thousands of dollars. When the data are not available, I input the damage as 0.
for (i in 1:nrow(andat)) {
if (andat$propdmgexp[i] == "K") {
andat$property[i] <- andat$propdmg[i]
} else if (andat$propdmgexp[i] =="M") {
andat$property[i] <- andat$propdmg[i]*1000
} else if (andat$propdmgexp[i] =="B") {
andat$property[i] <- andat$propdmg[i]*1000000
} else(andat$property[i] <- 0)
}
According to the same principle, I also calculated a variable called “crop” to measure the damage to crops in thousands of dollars:
for (i in 1:nrow(andat)) {
if (andat$cropdmgexp[i] == "K") {
andat$crop[i] <- andat$cropdmg[i]
} else if (andat$cropdmgexp[i] =="M") {
andat$crop[i] <- andat$cropdmg[i]*1000
} else if (andat$cropdmgexp[i] =="B") {
andat$crop[i] <- andat$cropdmg[i]*1000000
} else(andat$crop[i] <- 0)
}
I measure the economic impact of an event as the sum of the monetary value of property and crop damage:
andat$econ <- andat$property + andat$crop
The data frame that results from these computations contains the analytic data of this assignment. The data contain 196 different types of weather events:
length(unique(andat$evtype))
## [1] 196
After inspection of the variable’s values, I found that some events of the same nature were coded differently. I thus recoded them below:
#remove triple blank space at start of value
andat$evtype <- gsub("^ ", "", andat$evtype)
#remove single blank space at start of value
andat$evtype <- gsub("^ ", "", andat$evtype)
#uniformize coastal flooding
andat$evtype <- gsub("COASTAL FLOODING", "COASTAL FLOOD", andat$evtype)
#uniformize lake effect
andat$evtype <- gsub("LAKE-", "LAKE ", andat$evtype)
#uniformize mudslide
andat$evtype <- gsub("MUD SLIDE", "MUDSLIDE", andat$evtype)
#uniformize NON-TSTM WIND
andat$evtype <- gsub("NON TSTM WIND", "NON-TSTM WIND", andat$evtype)
#uniformize rip current
andat$evtype <- gsub("RIP CURRENTS", "RIP CURRENT", andat$evtype)
#uniformize strong wind
andat$evtype <- gsub("STRONG WINDS", "STRONG WIND", andat$evtype)
#uniformize winter weather mix
andat$evtype <- gsub("WINTER WEATHER/MIX", "WINTER WEATHER MIX", andat$evtype)
#uniformize thunderstorm wind
andat$evtype <- gsub("TSTM WIND", "THUNDERSTORM WIND", andat$evtype)
This reduces the number of unique events to 182:
length(unique(andat$evtype))
## [1] 182
To measure harm to health (hth) of each type of event, I calculated the sum of the “harm” variable, which is itself the sum of injuries and fatalities, across the various events. To measure damage to the economy (dte), did the same for the econ variable. I stored the results in the data frame “con,” for consequences.
con <- andat %>% group_by(evtype) %>% summarize(hth = sum(harm), dte = sum(econ))
## `summarise()` ungrouping output (override with `.groups` argument)
I want to find the events that account for 90% of the harm to health and of the economic damage. To that end, and for harm to health, I ran the following code:
# creates a a frame with events and harm to health ordered by amount of harm (fatalities + injuries)
hthorder <- con[order(con$hth, decreasing = TRUE),1:2]
# adds a column with cumulative share
hthorder$cum <- cumsum(hthorder$hth)/sum(hthorder$hth)
#display the events that account for up to 90% of the harm
hthorder[hthorder$cum < 0.9, ]
## # A tibble: 14 x 3
## evtype hth cum
## <chr> <dbl> <dbl>
## 1 TORNADO 16406 0.399
## 2 EXCESSIVE HEAT 4721 0.514
## 3 LIGHTNING 3459 0.598
## 4 THUNDERSTORM WIND 3399 0.680
## 5 HEAT 1453 0.716
## 6 FLASH FLOOD 1412 0.750
## 7 HURRICANE/TYPHOON 1339 0.783
## 8 WILDFIRE 986 0.807
## 9 RIP CURRENT 845 0.827
## 10 HIGH WIND 808 0.847
## 11 FLOOD 581 0.861
## 12 HAIL 545 0.874
## 13 WINTER STORM 540 0.887
## 14 WINTER WEATHER 376 0.896
The graph below depicts the total impact of these events:
ghth <- ggplot(hthorder[hthorder$cum < 0.9, ], aes(x = reorder(evtype, - hth), y = hth))
ghth + theme(axis.text.x = element_text(angle = 90)) + geom_col(fill = "steelblue") + labs(title = "Harm to human health from extreme weather events in the US (2000-2011)", subtitle = "Fatalities and injuries from event types accounting for 90% of all fatalities and injuries", x = "weather event", y = "fatalies + injuries")
As the graph shows, in the period of analysis, tornadoes were the most dangerous event to human health, followed by excessive heat, lightning, and thunderstorms.
I performed a similar analysis to find the events that create the most economic damage:
# creates a a frame with events and economic damage ordered by damage (crop + property)
dteorder <- con[order(con$dte, decreasing = TRUE),c(1,3)]
# adds a column with cumulative share
dteorder$cum <- cumsum(dteorder$dte)/sum(dteorder$dte)
#display the events that account for up to 90% of the harm
dteorder[dteorder$cum < 0.9, ]
## # A tibble: 8 x 3
## evtype dte cum
## <chr> <dbl> <dbl>
## 1 FLOOD 138913008. 0.392
## 2 HURRICANE/TYPHOON 71913713. 0.595
## 3 STORM SURGE 43170935 0.717
## 4 TORNADO 19695553. 0.772
## 5 HAIL 13773372. 0.811
## 6 FLASH FLOOD 12781544. 0.847
## 7 DROUGHT 9982231 0.875
## 8 TROPICAL STORM 7607242. 0.897
This information is showecased in the graphed below:
gdte <- ggplot(dteorder[dteorder$cum < 0.9, ], aes(x = reorder(evtype, - dte), y = dte))
gdte + theme(axis.text.x = element_text(angle = 90)) + geom_col(fill = "indianred") + labs(title = "Damage to the economy from extreme weather events in the US (2000-2011)", subtitle = "Damage to crops and property from event types accounting for 90% of all damage", x = "weather event", y = "Damage in thousands of $US")
As the graph shows, floods, hurricanes/typhoons, storm surges, and tornadoes created the most economic damage in the period under analysis.