This analysis examines severe weather events recorded in the U.S. National Oceanic and Atmospheric Administration Storm Database. The main objectives are to identify which event types are most harmful to population health and which have the greatest economic consequences. Population health impact is evaluated using reported fatalities and injuries. Economic impact is assessed using reported property and crop damage. The analysis begins with the original compressed NOAA storm data file and performs all processing within this reproducible R Markdown document. Event types are summarized across the United States to identify those associated with the greatest health and economic impacts.
The NOAA Storm Database was loaded directly from the original
compressed .csv.bz2 file. All data cleaning and
transformations used in this analysis are performed within this document
so that the results can be reproduced from the raw data.
# Set global chunk options
knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE
)
# Load the raw NOAA storm data
storm <- read.csv(
"repdata_data_StormData .csv.bz2",
stringsAsFactors = FALSE
)
# Check the dimensions of the dataset
dim(storm)
## [1] 902297 37
# Display the first few observations
head(storm)
## STATE__ BGN_DATE BGN_TIME TIME_ZONE COUNTY COUNTYNAME STATE EVTYPE
## 1 1 4/18/1950 0:00:00 0130 CST 97 MOBILE AL TORNADO
## 2 1 4/18/1950 0:00:00 0145 CST 3 BALDWIN AL TORNADO
## 3 1 2/20/1951 0:00:00 1600 CST 57 FAYETTE AL TORNADO
## 4 1 6/8/1951 0:00:00 0900 CST 89 MADISON AL TORNADO
## 5 1 11/15/1951 0:00:00 1500 CST 43 CULLMAN AL TORNADO
## 6 1 11/15/1951 0:00:00 2000 CST 77 LAUDERDALE AL TORNADO
## BGN_RANGE BGN_AZI BGN_LOCATI END_DATE END_TIME COUNTY_END COUNTYENDN
## 1 0 0 NA
## 2 0 0 NA
## 3 0 0 NA
## 4 0 0 NA
## 5 0 0 NA
## 6 0 0 NA
## END_RANGE END_AZI END_LOCATI LENGTH WIDTH F MAG FATALITIES INJURIES PROPDMG
## 1 0 14.0 100 3 0 0 15 25.0
## 2 0 2.0 150 2 0 0 0 2.5
## 3 0 0.1 123 2 0 0 2 25.0
## 4 0 0.0 100 2 0 0 2 2.5
## 5 0 0.0 150 2 0 0 2 2.5
## 6 0 1.5 177 2 0 0 6 2.5
## PROPDMGEXP CROPDMG CROPDMGEXP WFO STATEOFFIC ZONENAMES LATITUDE LONGITUDE
## 1 K 0 3040 8812
## 2 K 0 3042 8755
## 3 K 0 3340 8742
## 4 K 0 3458 8626
## 5 K 0 3412 8642
## 6 K 0 3450 8748
## LATITUDE_E LONGITUDE_ REMARKS REFNUM
## 1 3051 8806 1
## 2 0 0 2
## 3 0 0 3
## 4 0 0 4
## 5 0 0 5
## 6 0 0 6
# Examine the structure of the dataset
str(storm)
## '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 "" "" "" "" ...
## $ BGN_LOCATI: chr "" "" "" "" ...
## $ END_DATE : chr "" "" "" "" ...
## $ END_TIME : chr "" "" "" "" ...
## $ 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 "" "" "" "" ...
## $ END_LOCATI: chr "" "" "" "" ...
## $ 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 "" "" "" "" ...
## $ WFO : chr "" "" "" "" ...
## $ STATEOFFIC: chr "" "" "" "" ...
## $ ZONENAMES : chr "" "" "" "" ...
## $ 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 "" "" "" "" ...
## $ REFNUM : num 1 2 3 4 5 6 7 8 9 10 ...
# Display the variable names
names(storm)
## [1] "STATE__" "BGN_DATE" "BGN_TIME" "TIME_ZONE" "COUNTY"
## [6] "COUNTYNAME" "STATE" "EVTYPE" "BGN_RANGE" "BGN_AZI"
## [11] "BGN_LOCATI" "END_DATE" "END_TIME" "COUNTY_END" "COUNTYENDN"
## [16] "END_RANGE" "END_AZI" "END_LOCATI" "LENGTH" "WIDTH"
## [21] "F" "MAG" "FATALITIES" "INJURIES" "PROPDMG"
## [26] "PROPDMGEXP" "CROPDMG" "CROPDMGEXP" "WFO" "STATEOFFIC"
## [31] "ZONENAMES" "LATITUDE" "LONGITUDE" "LATITUDE_E" "LONGITUDE_"
## [36] "REMARKS" "REFNUM"
Only the variables required for the population health and economic
impact analyses were retained. EVTYPE identifies the type
of weather event. FATALITIES and INJURIES
measure population health impacts. PROPDMG and
PROPDMGEXP describe property damage, while
CROPDMG and CROPDMGEXP describe crop
damage.
# Retain only variables needed for the analysis
storm_analysis <- storm[, c(
"EVTYPE",
"FATALITIES",
"INJURIES",
"PROPDMG",
"PROPDMGEXP",
"CROPDMG",
"CROPDMGEXP"
)]
# Display the first few observations
head(storm_analysis)
## 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
The event type labels were standardized by converting them to uppercase and removing leading or trailing spaces. This reduces simple formatting differences while preserving the original event classifications.
# Standardize event type labels
storm_analysis$EVTYPE <- toupper(
trimws(storm_analysis$EVTYPE)
)
# Count the number of unique event labels
length(unique(storm_analysis$EVTYPE))
## [1] 890
After basic standardization, 890 unique event labels remain. This reflects historical inconsistencies and variations in NOAA event naming. Extensive manual recoding is avoided so that the transformations remain transparent and reproducible.
Economic damage in the NOAA Storm Database is recorded using a
numeric damage amount together with an exponent code. For example,
K represents thousands, M represents millions,
and B represents billions. These exponent codes must be
converted to numeric multipliers before property and crop damage can be
compared across events.
# Examine the exponent codes used for property damage
unique(storm_analysis$PROPDMGEXP)
## [1] "K" "M" "" "B" "m" "+" "0" "5" "6" "?" "4" "2" "3" "h" "7" "H" "-" "1" "8"
# Examine the exponent codes used for crop damage
unique(storm_analysis$CROPDMGEXP)
## [1] "" "M" "K" "m" "B" "?" "0" "k" "2"
The exponent variables contain standard codes as well as some
historical or nonstandard values. In this analysis, H,
K, M, and B are interpreted as
hundreds, thousands, millions, and billions. Single numeric codes are
treated as powers of 10. Blank or unrecognized symbols are assigned a
multiplier of 1 so that the recorded damage value is retained without
additional scaling.
# Convert exponent codes to uppercase character values
prop_exp <- toupper(trimws(as.character(storm_analysis$PROPDMGEXP)))
crop_exp <- toupper(trimws(as.character(storm_analysis$CROPDMGEXP)))
# Begin with a multiplier of 1 for every observation
storm_analysis$PROP_MULT <- rep(1, nrow(storm_analysis))
storm_analysis$CROP_MULT <- rep(1, nrow(storm_analysis))
# Assign standard property damage multipliers
storm_analysis$PROP_MULT[prop_exp == "H"] <- 1e2
storm_analysis$PROP_MULT[prop_exp == "K"] <- 1e3
storm_analysis$PROP_MULT[prop_exp == "M"] <- 1e6
storm_analysis$PROP_MULT[prop_exp == "B"] <- 1e9
# Assign standard crop damage multipliers
storm_analysis$CROP_MULT[crop_exp == "H"] <- 1e2
storm_analysis$CROP_MULT[crop_exp == "K"] <- 1e3
storm_analysis$CROP_MULT[crop_exp == "M"] <- 1e6
storm_analysis$CROP_MULT[crop_exp == "B"] <- 1e9
# Handle numeric exponent codes from 0 through 8
for (i in 0:8) {
storm_analysis$PROP_MULT[prop_exp == as.character(i)] <- 10^i
storm_analysis$CROP_MULT[crop_exp == as.character(i)] <- 10^i
}
# Confirm that the multiplier variables have the correct length
length(storm_analysis$PROP_MULT)
## [1] 902297
length(storm_analysis$CROP_MULT)
## [1] 902297
nrow(storm_analysis)
## [1] 902297
The three values above should be identical. This confirms that every row in the dataset has a property and crop damage multiplier.
# Confirm the multiplier vectors match the number of rows
stopifnot(
length(storm_analysis$PROP_MULT) == nrow(storm_analysis),
length(storm_analysis$CROP_MULT) == nrow(storm_analysis)
)
# Calculate property damage in dollars
storm_analysis$PROPERTY_DAMAGE <-
storm_analysis$PROPDMG * storm_analysis$PROP_MULT
# Calculate crop damage in dollars
storm_analysis$CROP_DAMAGE <-
storm_analysis$CROPDMG * storm_analysis$CROP_MULT
# Calculate total economic damage
storm_analysis$TOTAL_DAMAGE <-
storm_analysis$PROPERTY_DAMAGE +
storm_analysis$CROP_DAMAGE
# Inspect the newly created damage variables
head(
storm_analysis[, c(
"PROPDMG",
"PROPDMGEXP",
"PROPERTY_DAMAGE",
"CROPDMG",
"CROPDMGEXP",
"CROP_DAMAGE",
"TOTAL_DAMAGE"
)]
)
## PROPDMG PROPDMGEXP PROPERTY_DAMAGE CROPDMG CROPDMGEXP CROP_DAMAGE
## 1 25.0 K 25000 0 0
## 2 2.5 K 2500 0 0
## 3 25.0 K 25000 0 0
## 4 2.5 K 2500 0 0
## 5 2.5 K 2500 0 0
## 6 2.5 K 2500 0 0
## TOTAL_DAMAGE
## 1 25000
## 2 2500
## 3 25000
## 4 2500
## 5 2500
## 6 2500
Property and crop damage were converted to dollar values using the corresponding multipliers. Total economic damage was then calculated as the sum of property and crop damage for each observation.
Population health impact was evaluated using the total number of reported fatalities and injuries associated with each event type. A combined health impact measure was calculated by adding fatalities and injuries for each event category.
# Calculate total fatalities and injuries by event type
health_summary <- aggregate(
cbind(FATALITIES, INJURIES) ~ EVTYPE,
data = storm_analysis,
FUN = sum,
na.rm = TRUE
)
# Calculate combined health impact
health_summary$TOTAL_HEALTH_IMPACT <-
health_summary$FATALITIES +
health_summary$INJURIES
# Sort event types from greatest to smallest health impact
health_summary <- health_summary[
order(-health_summary$TOTAL_HEALTH_IMPACT),
]
# Display the ten event types with the greatest health impact
head(health_summary, 10)
## EVTYPE FATALITIES INJURIES TOTAL_HEALTH_IMPACT
## 750 TORNADO 5633 91346 96979
## 108 EXCESSIVE HEAT 1903 6525 8428
## 771 TSTM WIND 504 6957 7461
## 146 FLOOD 470 6789 7259
## 410 LIGHTNING 816 5230 6046
## 235 HEAT 937 2100 3037
## 130 FLASH FLOOD 978 1777 2755
## 379 ICE STORM 89 1975 2064
## 677 THUNDERSTORM WIND 133 1488 1621
## 880 WINTER STORM 206 1321 1527
# Select the top ten event types
top_health <- head(health_summary, 10)
# Create a matrix for fatalities and injuries
health_matrix <- rbind(
Fatalities = top_health$FATALITIES,
Injuries = top_health$INJURIES
)
# Create stacked bar plot
barplot(
health_matrix,
names.arg = top_health$EVTYPE,
las = 2,
cex.names = 0.7,
ylab = "Number of People Affected",
main = "Severe Weather Events with the Greatest Health Impact",
legend.text = TRUE
)
Figure 1. Top 10 severe weather event types by reported fatalities and injuries in the United States.
Tornadoes produced the greatest overall population health impact, with 5,633 fatalities and 91,346 injuries, for a combined total of 96,979 reported deaths and injuries. Excessive heat ranked second, followed by TSTM wind, flood, and lightning. These results show that tornadoes were associated with substantially greater reported human harm than the other individual event categories in the database.
The event labels should be interpreted with some caution because
historical variations in NOAA event classifications remain in the
dataset. For example, TSTM WIND and
THUNDERSTORM WIND appear as separate event categories.
Economic consequences were evaluated using the estimated dollar value of property and crop damage associated with each event type. Property and crop damage were combined to obtain the total economic impact for each event category.
# Calculate total economic damage by event type
economic_summary <- aggregate(
TOTAL_DAMAGE ~ EVTYPE,
data = storm_analysis,
FUN = sum,
na.rm = TRUE
)
# Sort event types from greatest to smallest economic damage
economic_summary <- economic_summary[
order(-economic_summary$TOTAL_DAMAGE),
]
# Display the ten event types with the greatest economic damage
head(economic_summary, 10)
## EVTYPE TOTAL_DAMAGE
## 146 FLOOD 150319678257
## 364 HURRICANE/TYPHOON 71913712800
## 750 TORNADO 57362333946
## 591 STORM SURGE 43323541000
## 204 HAIL 18761221986
## 130 FLASH FLOOD 18244041078
## 76 DROUGHT 15018672000
## 355 HURRICANE 14610229010
## 521 RIVER FLOOD 10148404500
## 379 ICE STORM 8967041360
# Summarize property and crop damage separately by event type
economic_components <- aggregate(
cbind(PROPERTY_DAMAGE, CROP_DAMAGE) ~ EVTYPE,
data = storm_analysis,
FUN = sum,
na.rm = TRUE
)
# Calculate total economic damage
economic_components$TOTAL_DAMAGE <-
economic_components$PROPERTY_DAMAGE +
economic_components$CROP_DAMAGE
# Sort from greatest to smallest total economic damage
economic_components <- economic_components[
order(-economic_components$TOTAL_DAMAGE),
]
# Display the top ten event types
head(economic_components, 10)
## EVTYPE PROPERTY_DAMAGE CROP_DAMAGE TOTAL_DAMAGE
## 146 FLOOD 144657709807 5661968450 150319678257
## 364 HURRICANE/TYPHOON 69305840000 2607872800 71913712800
## 750 TORNADO 56947380676 414953270 57362333946
## 591 STORM SURGE 43323536000 5000 43323541000
## 204 HAIL 15735267513 3025954473 18761221986
## 130 FLASH FLOOD 16822723978 1421317100 18244041078
## 76 DROUGHT 1046106000 13972566000 15018672000
## 355 HURRICANE 11868319010 2741910000 14610229010
## 521 RIVER FLOOD 5118945500 5029459000 10148404500
## 379 ICE STORM 3944927860 5022113500 8967041360
# Select the ten event types with the greatest economic damage
top_economic <- head(economic_summary, 10)
# Convert total damage to billions of dollars
top_economic$DAMAGE_BILLIONS <-
top_economic$TOTAL_DAMAGE / 1e9
# Create bar plot
barplot(
top_economic$DAMAGE_BILLIONS,
names.arg = top_economic$EVTYPE,
las = 2,
cex.names = 0.7,
ylab = "Total Damage (Billions of Dollars)",
main = "Severe Weather Events with the Greatest Economic Impact"
)
Figure 2. Top 10 severe weather event types by total estimated property and crop damage in the United States.
# Summarize property and crop damage separately by event type
economic_components <- aggregate(
cbind(PROPERTY_DAMAGE, CROP_DAMAGE) ~ EVTYPE,
data = storm_analysis,
FUN = sum,
na.rm = TRUE
)
# Calculate total economic damage
economic_components$TOTAL_DAMAGE <-
economic_components$PROPERTY_DAMAGE +
economic_components$CROP_DAMAGE
# Sort by total economic damage
economic_components <- economic_components[
order(economic_components$TOTAL_DAMAGE, decreasing = TRUE),
]
# Display top ten
head(economic_components, 10)
## EVTYPE PROPERTY_DAMAGE CROP_DAMAGE TOTAL_DAMAGE
## 146 FLOOD 144657709807 5661968450 150319678257
## 364 HURRICANE/TYPHOON 69305840000 2607872800 71913712800
## 750 TORNADO 56947380676 414953270 57362333946
## 591 STORM SURGE 43323536000 5000 43323541000
## 204 HAIL 15735267513 3025954473 18761221986
## 130 FLASH FLOOD 16822723978 1421317100 18244041078
## 76 DROUGHT 1046106000 13972566000 15018672000
## 355 HURRICANE 11868319010 2741910000 14610229010
## 521 RIVER FLOOD 5118945500 5029459000 10148404500
## 379 ICE STORM 3944927860 5022113500 8967041360
Floods produced the greatest overall economic impact, with approximately $149.83 billion in combined property and crop damage. Most of this loss came from property damage, which accounted for about $144.66 billion, while crop damage contributed approximately $5.17 billion.
Hurricane/Typhoon events ranked second with about $71.91 billion in total damage, followed by tornadoes with approximately $57.35 billion and storm surge events with about $43.32 billion. Flash floods and hail were also among the event types associated with major economic losses.
For most of the highest-ranking event types, property damage was the dominant source of economic loss. However, some categories such as river flood and ice storm showed a larger contribution from crop damage relative to other events.
These findings show that the weather events associated with the greatest economic consequences are not identical to those associated with the greatest population health impacts. Tornadoes produced the largest combined health impact, while floods produced the greatest total economic damage.
The NOAA Storm Database shows that severe weather events differ substantially in their effects on population health and the economy. Tornadoes produced the greatest combined number of reported fatalities and injuries, making them the most harmful event type with respect to population health in this analysis. Excessive heat, thunderstorm wind, floods, and lightning were also important contributors to human health impacts.
In terms of economic consequences, floods produced the largest total estimated damage, with approximately $149.83 billion in combined property and crop losses. Hurricane/Typhoon events, tornadoes, and storm surge events were also associated with substantial economic damage.
Overall, the results show that the event types responsible for the greatest human health impacts are not necessarily the same as those responsible for the greatest economic losses. The analysis also highlights that most of the economic impact among the highest-ranking events was driven by property damage, although crop losses were important for some event categories.