Synopsis

Severe weather events can cause substantial loss of life, injuries, property damage, and agricultural losses. This study analyzes the U.S. National Oceanic and Atmospheric Administration (NOAA) storm dataset supplied for the course, containing 902,297 records from 1950 through November 2011. The analysis has two objectives: identifying the most harmful recorded event types to public health and determining those with the greatest economic impact. Fatalities and injuries are summed separately, while property and crop damage are converted to dollars and added together. The analysis starts from the original compressed data file, with all processing shown in R. Tornadoes have the highest recorded fatalities and injuries, and floods have the highest recorded property and crop damage combined under the conversion rules used here. Earlier records are less complete, and differences in event names and uncertain damage values need to be considered when interpreting these results.

Data Processing

The analysis addresses the two questions specified for this study:

  1. Across the United States, which types of events, as indicated by EVTYPE, are most harmful with respect to population health?
  2. Across the United States, which types of events have the greatest economic consequences?

All processing and analysis code is shown below. Only knitr and rmarkdown are needed to render this report; the analysis uses base R.

Load the original data

The data are loaded directly from the original compressed CSV file, StormData.csv.bz2, using read.csv(). If the file is not available, the code downloads it from the course website. Seven variables are selected for the analysis:

  • Event type: EVTYPE gives the recorded name of the weather event.
  • Public health: FATALITIES and INJURIES give the reported numbers of deaths and injuries.
  • Economic impact: PROPDMG and CROPDMG contain damage amounts. PROPDMGEXP and CROPDMGEXP give the codes needed to convert these amounts to dollars.

All records are retained. Blank damage codes are kept for the conversion step. No previously cleaned data or saved R workspace is used.

knitr::opts_chunk$set(echo = TRUE, cache = FALSE, fig.align = "center")
options(scipen = 999)
raw_file <- "StormData.csv.bz2"
data_url <- paste0("https://d396qusza40orc.cloudfront.net/",
                   "repdata%2Fdata%2FStormData.csv.bz2")
if (!file.exists(raw_file)) download.file(data_url, raw_file, mode = "wb")
keep <- c("EVTYPE", "FATALITIES", "INJURIES", "PROPDMG",
          "PROPDMGEXP", "CROPDMG", "CROPDMGEXP")
header <- names(read.csv(bzfile(raw_file), nrows = 0))
classes <- ifelse(header %in% keep, "character", "NULL")
storm <- read.csv(bzfile(raw_file), colClasses = classes,
                  na.strings = "NA", stringsAsFactors = FALSE)
numeric_fields <- c("FATALITIES", "INJURIES", "PROPDMG", "CROPDMG")
storm[numeric_fields] <- lapply(storm[numeric_fields], as.numeric)
stopifnot(nrow(storm) == 902297L,
          !anyNA(storm[numeric_fields]),
          all(as.matrix(storm[numeric_fields]) >= 0))

The dataset contains 902,297 records. The checks above confirm that the four numeric impact fields have no missing or negative values. These checks do not verify the accuracy of the reported estimates.

Event names and damage amounts

Event type names: Capital letters and spacing are made consistent. Other differences in names are left unchanged. For example, TSTM WIND and THUNDERSTORM WIND remain separate because this analysis does not attempt to reclassify every historical event name. The results therefore compare recorded event labels, and related events may appear in separate groups. Records are not deleted just because they have the same impact values.

Converting damage values: Property and crop damage are calculated using their amount and code. K, M, and B mean thousands, millions, and billions, as described in the National Weather Service documentation. For example, 2.5 with code K means $2,500. This analysis also assumes that H means hundreds and a blank code means dollars. Lowercase letters are converted to uppercase before the calculation.

Unclear damage codes: Numeric and punctuation codes are left unresolved. A zero amount is counted as zero. A positive amount with an unclear code is set to NA and excluded from that damage total; the other damage amount and health values in the same record are retained. The table below counts the excluded property and crop amounts, not distinct events. No replacement losses are estimated. The original codes are kept, and converted values are stored in new columns.

storm$event <- toupper(trimws(gsub("[[:space:]]+", " ", storm$EVTYPE)))
stopifnot(!anyNA(storm$event), all(nzchar(storm$event)))
damage_dollars <- function(amount, exponent) {
  code <- toupper(trimws(exponent))
  multiplier <- c(1, 100, 1000, 1000000, 1000000000)[
    match(code, c("", "H", "K", "M", "B"))]
  result <- amount * multiplier
  result[amount == 0] <- 0
  result
}
storm$property <- damage_dollars(storm$PROPDMG, storm$PROPDMGEXP)
storm$crop <- damage_dollars(storm$CROPDMG, storm$CROPDMGEXP)
excluded <- c(property = sum(is.na(storm$property)),
              crop = sum(is.na(storm$crop)))
knitr::kable(data.frame(Component = names(excluded),
                        Unresolved_positive_amounts = unname(excluded)),
             caption = "Positive damage components excluded because their codes are ambiguous.")
Positive damage components excluded because their codes are ambiguous.
Component Unresolved_positive_amounts
property 244
crop 12

Data analysis: Fatalities and injuries are summed by event label to assess public health impact. They are ranked separately because deaths and injuries are different measures. Economic losses are calculated as the sum of property and crop damage with interpretable codes. All years are included, and amounts are not adjusted for inflation. The ten highest labels for each measure are shown in bar charts. The final checks confirm that the grouped totals match the included input values.

health <- aggregate(storm[c("FATALITIES", "INJURIES")],
                    list(Event = storm$event), sum)
economic <- aggregate(storm[c("property", "crop")],
                      list(Event = storm$event), sum, na.rm = TRUE)
economic$total <- economic$property + economic$crop
fatal_top <- head(health[order(-health$FATALITIES), ], 10)
injury_top <- head(health[order(-health$INJURIES), ], 10)
economic_top <- head(economic[order(-economic$total), ], 10)
stopifnot(sum(health$FATALITIES) == sum(storm$FATALITIES),
          sum(health$INJURIES) == sum(storm$INJURIES),
          isTRUE(all.equal(sum(economic$total),
            sum(storm$property, na.rm = TRUE) + sum(storm$crop, na.rm = TRUE))))

Results

Population health

  • TORNADO has the highest recorded fatalities (5,633), and TORNADO has the highest injuries (91,346).
  • EXCESSIVE HEAT is second for fatalities, while TSTM WIND is second for injuries.

Tornadoes therefore have the greatest recorded population-health impact on both measures used in this analysis. Figure 1 shows the ten highest event labels. The panels use different scales, so bar lengths should only be compared within the same panel.

old_par <- par(mfrow = c(2, 1), mar = c(4, 12, 3, 1), las = 1)
barplot(rev(fatal_top$FATALITIES), names.arg = rev(fatal_top$Event),
        horiz = TRUE, col = "#B45309", border = NA, cex.names = 0.8,
        main = "Recorded fatalities", xlab = "Number of deaths")
barplot(rev(injury_top$INJURIES), names.arg = rev(injury_top$Event),
        horiz = TRUE, col = "#2563A6", border = NA, cex.names = 0.8,
        main = "Recorded injuries", xlab = "Number of injuries")
Figure 1. Ten event labels with the largest recorded fatality totals (top) and injury totals (bottom), 1950–November 2011. Each panel is ranked independently.

Figure 1. Ten event labels with the largest recorded fatality totals (top) and injury totals (bottom), 1950–November 2011. Each panel is ranked independently.

par(old_par)

Economic consequences

  • FLOOD has the highest recorded economic damage, totaling $150.32 billion.
  • This consists of $144.66 billion in property damage and $5.66 billion in crop damage.
  • HURRICANE/TYPHOON and TORNADO have the next-highest totals.

Floods therefore have the greatest recorded economic consequences under the conversion rules used here. Figure 2 compares the ten highest event labels. These totals include direct property and crop losses; they do not include indirect costs such as business interruption.

old_par <- par(mar = c(4, 12, 3, 1), las = 1)
barplot(rev(economic_top$total) / 1e9,
        names.arg = rev(economic_top$Event), horiz = TRUE,
        col = "#247568", border = NA, cex.names = 0.8,
        main = "Recorded economic damage",
        xlab = "Property + crop damage (US$ billions)")
Figure 2. Ten event labels with the largest recorded property-plus-crop losses, in billions of nominal US dollars. Ambiguous positive damage components are excluded.

Figure 2. Ten event labels with the largest recorded property-plus-crop losses, in billions of nominal US dollars. Ambiguous positive damage components are excluded.

par(old_par)

Interpretation and limitations

Earlier records are less complete, so care is needed when comparing event types across the full period. Differences in event naming may split related events into separate groups. Damage estimates may contain errors, unclear damage amounts are excluded, and values are not adjusted for inflation. Large reported losses have not been removed or changed. These results describe total recorded impacts over the study period, not the risk or average severity of a single event. Within these limits, tornadoes lead the health measures and floods lead the economic totals.

Conclusion

This analysis answers the two project questions. Tornadoes have the highest recorded totals for both deaths and injuries, making them the most harmful event type to population health in this dataset. Floods have the highest combined property and crop damage under the conversion rules used here. These findings describe recorded losses over the study period; they do not measure the risk from an individual event. Reporting differences and uncertain damage estimates should be considered when interpreting the results.

Reproducibility

The complete analysis above runs from the compressed raw file in a fresh R session. The following records the R and package environment used to build this document.

sessionInfo()
## R version 4.6.1 (2026-06-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Dutch_Netherlands.utf8  LC_CTYPE=Dutch_Netherlands.utf8   
## [3] LC_MONETARY=Dutch_Netherlands.utf8 LC_NUMERIC=C                      
## [5] LC_TIME=Dutch_Netherlands.utf8    
## 
## time zone: Europe/Amsterdam
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## loaded via a namespace (and not attached):
##  [1] digest_0.6.39     R6_2.6.1          fastmap_1.2.0     xfun_0.60        
##  [5] cachem_1.1.0      knitr_1.51        htmltools_0.5.9   rmarkdown_2.31   
##  [9] lifecycle_1.0.5   cli_3.6.6         sass_0.4.10       jquerylib_0.1.4  
## [13] compiler_4.6.1    rstudioapi_0.19.0 tools_4.6.1       evaluate_1.0.5   
## [17] bslib_0.12.0      yaml_2.3.12       otel_0.2.0        jsonlite_2.0.0   
## [21] rlang_1.3.0