This report analyzes the U.S. National Oceanic and Atmospheric Administration (NOAA) Storm Database (raw CSV.bz2) to answer two questions: (1) which types of events are most harmful to population health (fatalities + injuries), and (2) which event types have the greatest economic consequences (property + crop damage). The analysis begins from the raw compressed CSV file, performs necessary data cleaning and unit conversion for damage exponents, and aggregates impacts by EVTYPE. Results are presented with reproducible R code (using dplyr and ggplot2) and two figures: a top-10 event types by health impact and a top-10 by economic impact. All code chunks show their source (echo = TRUE) so the work is reproducible. The document includes a Data Processing section describing transformations and a Results section with figures and interpretation.
This section loads the raw data, documents assumptions and transformations, and prepares the summary tables used in the Results.
knitr::opts_chunk$set(echo = TRUE, message = TRUE, warning = TRUE)
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(readr)
The analysis starts from the original compressed CSV file provided for the assignment. If you already have the file locally, set local_file accordingly. The default below downloads from the course URL (the standard link used in the Coursera assignment site).
# URL used in the original assignment (standard location for the Coursera assignment)
url <- "https://d396qusza40orc.cloudfront.net/repdata%2Fdata%2FStormData.csv.bz2"
local_file <- "StormData.csv.bz2"
if (!file.exists(local_file)) {
download.file(url, destfile = local_file, mode = "wb")
}
# read directly from the bzip2 compressed file
storms <- read.csv(local_file, stringsAsFactors = FALSE)
# quick peek
dim(storms)
## [1] 902297 37
str(storms[c("EVTYPE", "FATALITIES", "INJURIES", "PROPDMG", "PROPDMGEXP", "CROPDMG", "CROPDMGEXP")])
## 'data.frame': 902297 obs. of 7 variables:
## $ EVTYPE : chr "TORNADO" "TORNADO" "TORNADO" "TORNADO" ...
## $ 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 "" "" "" "" ...
EVTYPE is the event type (character). Many entries use inconsistent capitalization or spelling; for a first-pass analysis we will use simple standardization (trim, upper-case) and then aggregate by the cleaned EVTYPE values. A more thorough analysis could manually collapse similar event names into canonical categories.FATALITIES and INJURIES are numeric counts and can be summed directly.PROPDMG and CROPDMG represent numeric amounts with multipliers indicated in PROPDMGEXP / CROPDMGEXP. The exponent field contains characters like K, M, B, numeric digits, or other symbols. We convert these to multipliers and compute total dollar damages.# helper: convert exponent code to multiplier
exp_to_mult <- function(e) {
e <- toupper(trimws(e))
e[e == ""] <- ""
sapply(e, function(x) {
if (x %in% c("H")) return(100)
if (x %in% c("K")) return(1e3)
if (x %in% c("M")) return(1e6)
if (x %in% c("B")) return(1e9)
# sometimes numeric characters "0"-"9" indicate power of ten
if (grepl("^[0-9]+$", x)) return(10^as.numeric(x))
# + or - or ? or other characters: treat as multiplier 1 (conservative)
return(1)
})
}
storms <- storms %>%
mutate(
EVTYPE_CLEAN = toupper(trimws(EVTYPE)),
PROPDMGEXP_CLEAN = toupper(trimws(PROPDMGEXP)),
CROPDMGEXP_CLEAN = toupper(trimws(CROPDMGEXP))
)
# compute multiplier and dollar damage
storms <- storms %>%
mutate(
prop_mult = exp_to_mult(PROPDMGEXP_CLEAN),
crop_mult = exp_to_mult(CROPDMGEXP_CLEAN),
PROPDMG_USD = as.numeric(PROPDMG) * prop_mult,
CROPDMG_USD = as.numeric(CROPDMG) * crop_mult,
HEALTH_IMPACT = as.numeric(FATALITIES) + as.numeric(INJURIES),
ECONOMIC_IMPACT = PROPDMG_USD + CROPDMG_USD
)
# quick sanity checks
summary(storms$PROPDMG_USD)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000e+00 0.000e+00 0.000e+00 4.746e+05 5.000e+02 1.150e+11
summary(storms$CROPDMG_USD)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000e+00 0.000e+00 0.000e+00 5.442e+04 0.000e+00 5.000e+09
FATALITIES + INJURIES per EVTYPE_CLEAN.PROPDMG_USD + CROPDMG_USD per EVTYPE_CLEAN.health_by_event <- storms %>%
group_by(EVTYPE_CLEAN) %>%
summarise(
total_fatalities = sum(FATALITIES, na.rm = TRUE),
total_injuries = sum(INJURIES, na.rm = TRUE),
total_health = sum(HEALTH_IMPACT, na.rm = TRUE),
n_events = n()
) %>%
arrange(desc(total_health))
## `summarise()` ungrouping output (override with `.groups` argument)
econ_by_event <- storms %>%
group_by(EVTYPE_CLEAN) %>%
summarise(
total_prop = sum(PROPDMG_USD, na.rm = TRUE),
total_crop = sum(CROPDMG_USD, na.rm = TRUE),
total_econ = sum(ECONOMIC_IMPACT, na.rm = TRUE),
n_events = n()
) %>%
arrange(desc(total_econ))
## `summarise()` ungrouping output (override with `.groups` argument)
# top 10
top10_health <- head(health_by_event, 10)
top10_econ <- head(econ_by_event, 10)
knitr::kable(top10_health, caption = "Top 10 event types by combined injuries+fatalities")
| EVTYPE_CLEAN | total_fatalities | total_injuries | total_health | n_events |
|---|---|---|---|---|
| TORNADO | 5633 | 91346 | 96979 | 60652 |
| EXCESSIVE HEAT | 1903 | 6525 | 8428 | 1678 |
| TSTM WIND | 504 | 6957 | 7461 | 219946 |
| FLOOD | 470 | 6789 | 7259 | 25327 |
| LIGHTNING | 816 | 5230 | 6046 | 15755 |
| HEAT | 937 | 2100 | 3037 | 767 |
| FLASH FLOOD | 978 | 1777 | 2755 | 54278 |
| ICE STORM | 89 | 1975 | 2064 | 2006 |
| THUNDERSTORM WIND | 133 | 1488 | 1621 | 82564 |
| WINTER STORM | 206 | 1321 | 1527 | 11433 |
knitr::kable(top10_econ, caption = "Top 10 event types by combined property+crop damage (USD)")
| EVTYPE_CLEAN | total_prop | total_crop | total_econ | n_events |
|---|---|---|---|---|
| FLOOD | 144657709807 | 5661968450 | 150319678257 | 25327 |
| HURRICANE/TYPHOON | 69305840000 | 2607872800 | 71913712800 | 88 |
| TORNADO | 56947380676 | 414953270 | 57362333946 | 60652 |
| STORM SURGE | 43323536000 | 5000 | 43323541000 | 261 |
| HAIL | 15735267513 | 3025954473 | 18761221986 | 288661 |
| FLASH FLOOD | 16822723978 | 1421317100 | 18244041078 | 54278 |
| DROUGHT | 1046106000 | 13972566000 | 15018672000 | 2488 |
| HURRICANE | 11868319010 | 2741910000 | 14610229010 | 174 |
| RIVER FLOOD | 5118945500 | 5029459000 | 10148404500 | 173 |
| ICE STORM | 3944927860 | 5022113500 | 8967041360 | 2006 |
This section presents the plots and interprets findings. Figures are limited to two (health and economic), which keeps within the assignment limit of at most three figures.
# prepare data for plotting
plot_health <- top10_health %>%
mutate(EVTYPE_CLEAN = reorder(EVTYPE_CLEAN, total_health))
ggplot(plot_health, aes(x = EVTYPE_CLEAN, y = total_health)) +
geom_col() +
coord_flip() +
labs(x = "Event type", y = "Total fatalities + injuries",
title = "Top 10 NOAA Event Types by Health Impact") +
theme_minimal()
Top 10 event types by total fatalities+injuries (descending).
Caption: This bar chart shows the top 10 event types ranked by combined fatalities and injuries recorded in the NOAA Storm Database (1950–2011). Interpretation notes: event naming in the raw data is inconsistent; some categories (e.g., variations of thunderstorms, hail, wind) may be split across multiple EVTYPE strings and require manual cleaning for final policy use.
plot_econ <- top10_econ %>%
mutate(EVTYPE_CLEAN = reorder(EVTYPE_CLEAN, total_econ))
# plot with log scale to manage wide range of damages
ggplot(plot_econ, aes(x = EVTYPE_CLEAN, y = total_econ)) +
geom_col() +
coord_flip() +
scale_y_continuous(labels = scales::dollar_format(prefix = "$", scale = 1, big.mark = ",")) +
labs(x = "Event type", y = "Total damage (USD)",
title = "Top 10 NOAA Event Types by Economic Impact (Property + Crop)") +
theme_minimal()
Top 10 event types by economic damage (property + crop), in US dollars.
Caption: The bar chart uses absolute USD to show total property and crop damage by event type. Note that damage amounts span several orders of magnitude; for deeper analysis consider plotting on a log scale or presenting median per-event damage.
THUNDERSTORM WIND, TSTM WIND, THUNDERSTORM WINDS, etc.). A thorough policy-grade analysis must clean and map EVTYPE to canonical categories (the NOAA documentation suggests an event type standardization list). The exponent fields for damage contain many nonstandard characters and ambiguous entries; our conservative choice treats unknown symbols as multiplier 1. This may under- or over-estimate some totals.All code shown above starts from the raw StormData.csv.bz2 file and uses open R packages only. To reproduce the figures and tables, open this R Markdown document in RStudio and knit it to HTML (it will download the raw file automatically if not present).
(The full code is shown inline in the document; all chunks have echo = TRUE.)
End of report.