This report analyzes the U.S. National Oceanic and Atmospheric Administration (NOAA) Storm Database, which contains records of major weather events across the United States from 1950 to November 2011. The analysis addresses two primary questions: which event types are most harmful to population health, and which event types have the greatest economic consequences. Fatalities and injuries were used as proxy measures for public health impact, while property and crop damage estimates (converted to dollar values) were used for economic impact. The data required cleaning of event type labels and conversion of damage exponent codes (K, M, B) to numeric multipliers. Results show that tornadoes are by far the most harmful event type for population health, accounting for the most fatalities and injuries combined. For economic consequences, floods and hurricanes/typhoons cause the greatest total property and crop damage. These findings suggest that emergency preparedness resources should be prioritized toward tornado response and flood management for maximum impact on human safety and economic resilience.
The data is loaded directly from the compressed .bz2
file. R’s read.csv() can handle bz2-compressed files
natively.
## Working directory: C:/Users/Gouth/Downloads/datascience
## Files here: repdata_data_StormData.csv.bz2, StormData_Analysis--2-.Rmd, StormData_Analysis--2-_cache, StormData_Analysis (2).Rmd
## UPDATE this path if the file is not in your working directory
data_path <- "C:/Users/Gouth/Downloads/datascience/repdata_data_StormData.csv.bz2"
if (!file.exists(data_path)) stop("File not found: ", data_path, "\nSet data_path to the full path of your .bz2 file.")
storm_raw <- read.csv(data_path, header = TRUE, stringsAsFactors = FALSE)
# Basic dimensions
dim(storm_raw)## [1] 902297 37
# Preview key columns
head(storm_raw[, c("EVTYPE", "FATALITIES", "INJURIES", "PROPDMG", "PROPDMGEXP", "CROPDMG", "CROPDMGEXP")])## EVTYPE FATALITIES INJURIES PROPDMG PROPDMGEXP CROPDMG CROPDMGEXP
## 1 TORNADO 0 15 25.0 K 0
## 2 TORNADO 0 0 2.5 K 0
## 3 TORNADO 0 2 25.0 K 0
## 4 TORNADO 0 2 2.5 K 0
## 5 TORNADO 0 2 2.5 K 0
## 6 TORNADO 0 6 2.5 K 0
For this analysis, we only need the event type, health metrics, and economic damage columns.
The EVTYPE field contains many inconsistencies (mixed
case, trailing spaces, abbreviations). We standardize it by converting
to uppercase and trimming whitespace.
storm$EVTYPE <- toupper(trimws(storm$EVTYPE))
# Number of unique event types after basic cleaning
length(unique(storm$EVTYPE))## [1] 890
The PROPDMGEXP and CROPDMGEXP columns
encode magnitude: “K” = thousands, “M” = millions, “B” = billions.
Numeric digits (0–8) and symbols (+, -, ?) are handled below.
# Function to convert exponent codes to numeric multipliers
exp_to_num <- function(exp) {
exp <- toupper(trimws(as.character(exp)))
case_when(
exp == "K" ~ 1e3,
exp == "M" ~ 1e6,
exp == "B" ~ 1e9,
exp == "H" ~ 1e2, # hundreds (rare)
exp %in% as.character(0:8) ~ 10^as.numeric(exp),
exp %in% c("+", "-", "?", "") ~ 1,
TRUE ~ 1
)
}# Health impact
health_summary <- storm %>%
group_by(EVTYPE) %>%
summarise(
Total_Fatalities = sum(FATALITIES, na.rm = TRUE),
Total_Injuries = sum(INJURIES, na.rm = TRUE),
Total_Health = sum(TOTAL_HEALTH, na.rm = TRUE)
) %>%
arrange(desc(Total_Health))
# Economic impact
econ_summary <- storm %>%
group_by(EVTYPE) %>%
summarise(
Total_PropDmg = sum(PROP_DMG_USD, na.rm = TRUE),
Total_CropDmg = sum(CROP_DMG_USD, na.rm = TRUE),
Total_Damage = sum(TOTAL_DMG_USD, na.rm = TRUE)
) %>%
arrange(desc(Total_Damage))We rank events by combined fatalities and injuries, then display the top 10. We also show the fatality/injury breakdown for context.
top10_health <- health_summary %>%
slice_head(n = 10)
knitr::kable(
top10_health,
col.names = c("Event Type", "Fatalities", "Injuries", "Total (Fatalities + Injuries)"),
format.args = list(big.mark = ","),
caption = "Table 1: Top 10 Weather Events by Total Health Impact (1950–2011)"
)| Event Type | Fatalities | Injuries | Total (Fatalities + Injuries) |
|---|---|---|---|
| TORNADO | 5,633 | 91,346 | 96,979 |
| EXCESSIVE HEAT | 1,903 | 6,525 | 8,428 |
| TSTM WIND | 504 | 6,957 | 7,461 |
| FLOOD | 470 | 6,789 | 7,259 |
| LIGHTNING | 816 | 5,230 | 6,046 |
| HEAT | 937 | 2,100 | 3,037 |
| FLASH FLOOD | 978 | 1,777 | 2,755 |
| ICE STORM | 89 | 1,975 | 2,064 |
| THUNDERSTORM WIND | 133 | 1,488 | 1,621 |
| WINTER STORM | 206 | 1,321 | 1,527 |
# Reshape for stacked bar chart
top10_health_long <- top10_health %>%
select(EVTYPE, Total_Fatalities, Total_Injuries) %>%
pivot_longer(
cols = c(Total_Fatalities, Total_Injuries),
names_to = "Type",
values_to = "Count"
) %>%
mutate(
Type = recode(Type,
"Total_Fatalities" = "Fatalities",
"Total_Injuries" = "Injuries"),
EVTYPE = factor(EVTYPE, levels = rev(top10_health$EVTYPE))
)
ggplot(top10_health_long, aes(x = EVTYPE, y = Count, fill = Type)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_y_continuous(labels = comma) +
scale_fill_manual(values = c("Fatalities" = "#c0392b", "Injuries" = "#e67e22")) +
labs(
title = "Top 10 Most Harmful Weather Events to Population Health",
subtitle = "United States, 1950–2011 (NOAA Storm Database)",
x = "Event Type",
y = "Total Count",
fill = "Impact Type"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(colour = "grey40"),
legend.position = "bottom"
)Figure 1: Top 10 weather events most harmful to population health. Bar segments show the breakdown of fatalities (dark) vs. injuries (light).
Key Finding: Tornadoes dominate both fatality and injury counts, causing more combined harm than the next several event types combined. Excessive heat is the second-leading cause of fatalities, while thunderstorm winds produce many injuries. Emergency managers should prioritize tornado preparedness and early warning systems.
We rank events by total damage (property + crop) and display the top 10.
top10_econ <- econ_summary %>%
slice_head(n = 10)
knitr::kable(
top10_econ %>%
mutate(across(where(is.numeric), ~ scales::dollar(., scale = 1e-9, suffix = "B"))),
col.names = c("Event Type", "Property Damage (USD)", "Crop Damage (USD)", "Total Damage (USD)"),
caption = "Table 2: Top 10 Weather Events by Total Economic Damage (1950–2011)"
)| Event Type | Property Damage (USD) | Crop Damage (USD) | Total Damage (USD) |
|---|---|---|---|
| FLOOD | $144.66B | $5.66B | $150.32B |
| HURRICANE/TYPHOON | $69.31B | $2.61B | $71.91B |
| TORNADO | $56.95B | $0.41B | $57.36B |
| STORM SURGE | $43.32B | $0.00B | $43.32B |
| HAIL | $15.74B | $3.03B | $18.76B |
| FLASH FLOOD | $16.82B | $1.42B | $18.24B |
| DROUGHT | $1.05B | $13.97B | $15.02B |
| HURRICANE | $11.87B | $2.74B | $14.61B |
| RIVER FLOOD | $5.12B | $5.03B | $10.15B |
| ICE STORM | $3.94B | $5.02B | $8.97B |
top10_econ_long <- top10_econ %>%
select(EVTYPE, Total_PropDmg, Total_CropDmg) %>%
pivot_longer(
cols = c(Total_PropDmg, Total_CropDmg),
names_to = "Type",
values_to = "Damage"
) %>%
mutate(
Type = recode(Type,
"Total_PropDmg" = "Property Damage",
"Total_CropDmg" = "Crop Damage"),
EVTYPE = factor(EVTYPE, levels = rev(top10_econ$EVTYPE))
)
ggplot(top10_econ_long, aes(x = EVTYPE, y = Damage / 1e9, fill = Type)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_y_continuous(labels = dollar_format(suffix = "B", prefix = "$")) +
scale_fill_manual(values = c("Property Damage" = "#2980b9", "Crop Damage" = "#27ae60")) +
labs(
title = "Top 10 Weather Events by Total Economic Damage",
subtitle = "United States, 1950–2011 (NOAA Storm Database)",
x = "Event Type",
y = "Total Damage (USD Billions)",
fill = "Damage Type"
) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(colour = "grey40"),
legend.position = "bottom"
)Figure 2: Top 10 weather events by total economic damage (USD billions). Bar segments show property vs. crop damage.
top5_health <- health_summary %>% slice_head(n = 5)
top5_econ <- econ_summary %>% slice_head(n = 5)
p_health <- ggplot(top5_health,
aes(x = reorder(EVTYPE, Total_Health), y = Total_Health)) +
geom_bar(stat = "identity", fill = "#c0392b") +
coord_flip() +
scale_y_continuous(labels = comma) +
labs(title = "Health Impact",
x = NULL, y = "Fatalities + Injuries") +
theme_minimal(base_size = 11) +
theme(plot.title = element_text(face = "bold"))
p_econ <- ggplot(top5_econ,
aes(x = reorder(EVTYPE, Total_Damage), y = Total_Damage / 1e9)) +
geom_bar(stat = "identity", fill = "#2980b9") +
coord_flip() +
scale_y_continuous(labels = dollar_format(suffix = "B", prefix = "$")) +
labs(title = "Economic Damage",
x = NULL, y = "Property + Crop Damage (Billions USD)") +
theme_minimal(base_size = 11) +
theme(plot.title = element_text(face = "bold"))
# Use gridExtra for panel plot
if (!requireNamespace("gridExtra", quietly = TRUE)) install.packages("gridExtra")
library(gridExtra)
grid.arrange(p_health, p_econ, ncol = 2,
top = "Top 5 Weather Events: Health vs. Economic Impact (1950–2011)")Figure 3: Side-by-side comparison of top 5 events by health impact (left) and economic impact (right).
Key Finding: Floods cause the greatest total economic damage, predominantly through property destruction. Hurricanes and typhoons, storm surges, and tornadoes also generate enormous economic losses. Notably, drought has an outsized impact on crop damage relative to property, making it a critical agricultural concern. Municipal and state planners should incorporate flood mitigation infrastructure and crop insurance frameworks as high-priority economic resilience measures.
| Dimension | Top Event | Notable Others |
|---|---|---|
| Population Health | Tornado (fatalities + injuries) | Excessive Heat, TSTM Wind, Flood |
| Economic Damage | Flood (property + crop) | Hurricane/Typhoon, Tornado, Storm Surge |
These results highlight the dual threat posed by tornadoes (human safety) and floods (economic cost), and suggest they warrant the highest investment in preparedness, early warning infrastructure, and post-event recovery planning.