This report examines the human and economic consequences of severe weather events recorded in the U.S. National Oceanic and Atmospheric Administration (NOAA) Storm Database between 1950 and November 2011. Population-health impacts are assessed separately using the numbers of fatalities and injuries associated with each reported event type. Economic consequences are assessed using estimated property and crop damage, converted into U.S. dollars with the magnitude codes supplied in the original data. Event labels are standardized conservatively to avoid combining substantively different categories. The analysis identifies the event types associated with the largest recorded totals, rather than estimating individual risk or causal effects. Interpretation is limited by evolving reporting practices, inconsistent event labels, approximate damage estimates, and the absence of inflation adjustment.
The analysis begins with the original compressed CSV
file, downloaded directly from the assignment’s source when it
is not already present locally. R reads the .csv.bz2 file
directly; no externally preprocessed dataset is used. To make the
analysis reproducible, all subsequent cleaning, conversion, aggregation,
and visualization are performed in this document.
library(ggplot2)
library(knitr)
knitr::opts_chunk$set(echo=TRUE, message=FALSE, warning=FALSE,
fig.align="center")
source_url <- paste0(
"https://d396qusza40orc.cloudfront.net/",
"repdata%2Fdata%2FStormData.csv.bz2"
)
data_file <- "StormData.csv.bz2"
if (!file.exists(data_file)) {
download.file(source_url, destfile=data_file, mode="wb")
}
stopifnot(file.exists(data_file), file.info(data_file)$size > 1000000)
storm_raw <- read.csv(bzfile(data_file), stringsAsFactors=FALSE)
required <- c("EVTYPE", "FATALITIES", "INJURIES", "PROPDMG",
"PROPDMGEXP", "CROPDMG", "CROPDMGEXP")
stopifnot(all(required %in% names(storm_raw)))
cat("Recorded events:", format(nrow(storm_raw), big.mark=","), "\n")
## Recorded events: 902,297
cat("Variables in source:", ncol(storm_raw), "\n")
## Variables in source: 37
For public health, fatalities and injuries are reported separately: they are distinct outcomes and should not be confused with one another. Their sum is also used as a descriptive indicator of the total number of recorded casualties, not as a measure of severity-weighted burden.
Only formatting inconsistencies in EVTYPE are corrected:
surrounding spaces are removed, internal whitespace is reduced, and
letters are converted to uppercase. Potentially synonymous but different
event categories are not automatically merged, avoiding
undocumented reclassification. Consequently, rankings describe event
types as reported (after this conservative cleaning).
For economics, the data store a numerical damage amount alongside a
magnitude code. K, M, and B mean
thousands, millions, and billions of dollars, respectively;
H means hundreds. Blank and 0 codes are
interpreted as unscaled amounts. Unknown or ambiguous nonzero damage
codes are treated as missing instead of assigning them an invented
multiplier. The number of such records is reported below, and these
uncertain amounts are omitted from monetary totals. Fatalities and
injuries from those records remain in the health analysis. These
estimates are nominal dollars, not inflation
adjusted.
storm <- storm_raw[, required]
rm(storm_raw)
storm$event <- toupper(gsub("[[:space:]]+", " ", trimws(storm$EVTYPE)))
storm$event[is.na(storm$event) | storm$event == ""] <- "UNSPECIFIED"
# NOAA damage multiplier codes. Unrecognized codes are not guessed.
damage_multiplier <- function(code) {
code <- toupper(trimws(as.character(code)))
multiplier <- rep(NA_real_, length(code))
multiplier[!is.na(code) & code %in% c("", "0")] <- 1
multiplier[!is.na(code) & code == "H"] <- 1e2
multiplier[!is.na(code) & code == "K"] <- 1e3
multiplier[!is.na(code) & code == "M"] <- 1e6
multiplier[!is.na(code) & code == "B"] <- 1e9
multiplier
}
storm$property_usd <- storm$PROPDMG * damage_multiplier(storm$PROPDMGEXP)
storm$crop_usd <- storm$CROPDMG * damage_multiplier(storm$CROPDMGEXP)
# Only missing or ambiguous positive damage estimates affect reported sums.
unknown_property <- sum(is.na(storm$property_usd) &
!is.na(storm$PROPDMG) & storm$PROPDMG > 0)
unknown_crop <- sum(is.na(storm$crop_usd) &
!is.na(storm$CROPDMG) & storm$CROPDMG > 0)
quality <- data.frame(
Indicator=c("Records", "Distinct event labels after formatting",
"Positive property estimates with ambiguous units",
"Positive crop estimates with ambiguous units"),
Value=c(nrow(storm), length(unique(storm$event)),
unknown_property, unknown_crop)
)
kable(quality, caption="Dataset size and damage-conversion checks")
| Indicator | Value |
|---|---|
| Records | 902297 |
| Distinct event labels after formatting | 883 |
| Positive property estimates with ambiguous units | 35 |
| Positive crop estimates with ambiguous units | 0 |
Totals are calculated over the available records for each event type. Missing values are excluded from sums rather than replaced with assumed damages. The analysis uses aggregate counts and monetary amounts, which are relevant for historical resource planning but should not be interpreted as per-event probabilities or as adjusted measures of future risk.
health <- aggregate(cbind(FATALITIES, INJURIES) ~ event,
data=storm,
FUN=function(x) sum(x, na.rm=TRUE))
health$casualties <- health$FATALITIES + health$INJURIES
# Convert missing monetary values to zero for the purpose of summing
# the remaining known dollar amounts in each event category.
storm$property_known <- ifelse(is.na(storm$property_usd), 0, storm$property_usd)
storm$crop_known <- ifelse(is.na(storm$crop_usd), 0, storm$crop_usd)
economic <- aggregate(cbind(property_known, crop_known) ~ event,
data=storm, FUN=sum)
names(economic)[2:3] <- c("property_usd", "crop_usd")
economic$total_usd <- economic$property_usd + economic$crop_usd
# Reproducibility and quality checks
stopifnot(nrow(storm) > 900000,
all(health$FATALITIES >= 0), all(health$INJURIES >= 0),
all(economic$total_usd >= 0),
!anyNA(economic$total_usd))
Both fatality and injury totals are analyzed, because the categories with the greatest number of deaths need not be the same as those with the greatest number of injuries. The following table lists the five largest event categories for each outcome.
top_fatal <- head(health[order(-health$FATALITIES),
c("event", "FATALITIES")], 5)
top_injury <- head(health[order(-health$INJURIES),
c("event", "INJURIES")], 5)
names(top_fatal) <- c("Event type", "Fatalities")
names(top_injury) <- c("Event type", "Injuries")
kable(top_fatal, caption="Five event types with the most reported deaths")
| Event type | Fatalities | |
|---|---|---|
| 745 | TORNADO | 5633 |
| 107 | EXCESSIVE HEAT | 1903 |
| 129 | FLASH FLOOD | 978 |
| 234 | HEAT | 937 |
| 407 | LIGHTNING | 816 |
kable(top_injury, caption="Five event types with the most reported injuries")
| Event type | Injuries | |
|---|---|---|
| 745 | TORNADO | 91346 |
| 766 | TSTM WIND | 6957 |
| 145 | FLOOD | 6789 |
| 107 | EXCESSIVE HEAT | 6525 |
| 407 | LIGHTNING | 5230 |
The leading category for recorded fatalities is TORNADO (5,633 deaths). The leading category for recorded injuries is TORNADO (91,346 injuries). These are historical reported totals, not rates adjusted for population exposure.
make_top <- function(column, label, n=10) {
d <- health[order(-health[[column]]), c("event", column)]
d <- head(d, n)
data.frame(event=d$event, count=d[[column]], outcome=label,
stringsAsFactors=FALSE)
}
health_plot <- rbind(make_top("FATALITIES", "Fatalities"),
make_top("INJURIES", "Injuries"))
# Each panel uses its own labels and ranking.
health_plot$category <- paste(health_plot$event, health_plot$outcome, sep="___")
health_plot$category <- reorder(health_plot$category, health_plot$count)
ggplot(health_plot, aes(x=count, y=category, fill=outcome)) +
geom_col(width=0.72, show.legend=FALSE) +
facet_wrap(~outcome, scales="free", nrow=1) +
scale_y_discrete(labels=function(x) sub("___.*$", "", x)) +
scale_x_continuous(labels=function(x) format(x, big.mark=",", scientific=FALSE)) +
labs(title="Health impact of severe weather in the United States",
subtitle="Top 10 recorded event types for each outcome, 1950–2011",
x="Recorded people affected", y=NULL) +
theme_minimal(base_size=11) +
theme(strip.text=element_text(face="bold"),
panel.grid.major.y=element_blank(),
plot.title=element_text(face="bold"))
Figure 1. Ten event types with the largest reported fatalities and injuries, displayed as two panels. Bars represent cumulative event counts recorded in the NOAA database during 1950–2011; the x-axis scale is allowed to differ between panels.
Property and crop losses were converted to dollars before aggregation, then added to estimate combined reported economic damage. The table below lists the ten event types associated with the greatest nominal combined losses, expressed in billions of U.S. dollars. As a further check, the largest property-loss and crop-loss categories are displayed separately.
econ_top <- head(economic[order(-economic$total_usd), ], 10)
econ_table <- data.frame(
`Event type`=econ_top$event,
`Property (USD bn)`=round(econ_top$property_usd / 1e9, 2),
`Crops (USD bn)`=round(econ_top$crop_usd / 1e9, 2),
`Total (USD bn)`=round(econ_top$total_usd / 1e9, 2),
check.names=FALSE
)
kable(econ_table,
caption="Ten event types with the greatest combined reported damage")
| Event type | Property (USD bn) | Crops (USD bn) | Total (USD bn) |
|---|---|---|---|
| FLOOD | 144.66 | 5.66 | 150.32 |
| HURRICANE/TYPHOON | 69.31 | 2.61 | 71.91 |
| TORNADO | 56.94 | 0.41 | 57.35 |
| STORM SURGE | 43.32 | 0.00 | 43.32 |
| HAIL | 15.73 | 3.03 | 18.76 |
| FLASH FLOOD | 16.14 | 1.42 | 17.56 |
| DROUGHT | 1.05 | 13.97 | 15.02 |
| HURRICANE | 11.87 | 2.74 | 14.61 |
| RIVER FLOOD | 5.12 | 5.03 | 10.15 |
| ICE STORM | 3.94 | 5.02 | 8.97 |
highest_property <- economic$event[which.max(economic$property_usd)]
highest_crop <- economic$event[which.max(economic$crop_usd)]
cat("Largest property-damage category:", highest_property, "\n")
## Largest property-damage category: FLOOD
cat("Largest crop-damage category:", highest_crop, "\n")
## Largest crop-damage category: DROUGHT
The largest combined nominal economic loss is associated with FLOOD, representing approximately USD 150.32 billion. Property losses are highest for FLOOD, whereas crop losses are highest for DROUGHT. These rankings reflect the reported monetary totals in the historical data and do not adjust for inflation, variations in reporting, or changes in exposed assets.
econ_plot <- econ_top
econ_plot$event <- reorder(econ_plot$event, econ_plot$total_usd)
ggplot(econ_plot, aes(x=total_usd/1e9, y=event)) +
geom_col(fill="#327F82", width=0.73) +
scale_x_continuous(labels=function(x) format(x, big.mark=",", trim=TRUE)) +
labs(title="Economic losses from severe weather in the United States",
subtitle="Property and crop damage combined, 1950–2011",
x="Reported damage (billion USD, nominal)", y=NULL) +
theme_minimal(base_size=12) +
theme(panel.grid.major.y=element_blank(),
plot.title=element_text(face="bold"))
Figure 2. The ten NOAA event types with the greatest cumulative reported economic losses (property plus crop damage), in nominal billions of U.S. dollars. Unrecognized damage-magnitude codes are excluded rather than assigned a guessed value.
The two questions reveal different dimensions of weather-event burden: the highest numbers of deaths and injuries are not necessarily associated with the largest monetary losses. The rankings should be interpreted as descriptive comparisons of cumulative reported impacts, not as predictions of expected losses or as measures of risk per event. The NOAA database is less complete in its earlier years, its event classifications have changed over time, and some historical labels are not standardized. Reported damage values are estimates in nominal dollars, and some ambiguous magnitude codes cannot be converted reliably. These limitations should be considered when using the historical findings to understand preparedness priorities.
National Oceanic and Atmospheric Administration (NOAA), historical Storm Data provided for the Coursera Reproducible Research assignment, 1950–November 2011. NOAA describes its storm records and damage estimates as subject to reporting limitations; the monetary amounts in the database are not adjusted for inflation.