title: “Storm Data Analysis: Population Health and Economic Impact Assessment” author: “Storm Data Analysis Team” date: “2025-06-21” output: html_document —
knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
# Load required libraries
library(knitr)
## Warning: package 'knitr' was built under R version 4.4.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
##
## 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)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(gridExtra)
## Warning: package 'gridExtra' was built under R version 4.4.3
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
library(scales)
## Warning: package 'scales' was built under R version 4.4.3
This analysis examines severe weather events across the United States to identify which event types pose the greatest threats to population health and economic stability. Using the Storm Events Database, we analyzed 61,595 weather events to answer two critical questions for emergency management: (1) which events are most harmful to population health, and (2) which events have the greatest economic consequences. The data reveals that tornadoes are by far the most dangerous weather phenomenon, responsible for 94.5% of all weather-related fatalities and injuries despite representing only 21% of events. Tornadoes also cause the most significant economic damage, with over $13.5 billion in documented losses. The analysis shows extreme concentration of both casualties and economic damage in tornado events, providing clear justification for prioritizing tornado-specific preparedness and response capabilities. Government and municipal managers should allocate emergency management resources with tornado preparedness as the top priority for both public safety and economic protection measures.
# Read the raw CSV file
# Note: Adjust the file path as needed for your local environment
storm_data <- read.csv("C:/Users/gayatrig/Desktop/datasciencecourse/reproducible research 2/repdata_data_StormData.csv/repdata_data_StormData/repdata_data_StormData.csv", stringsAsFactors = FALSE)
# Examine the structure of the data
str(storm_data)
## '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 basic information about the dataset
cat("Dataset dimensions:", nrow(storm_data), "rows,", ncol(storm_data), "columns")
## Dataset dimensions: 902297 rows, 37 columns
cat("Date range:", min(storm_data$BGN_DATE, na.rm = TRUE), "to", max(storm_data$BGN_DATE, na.rm = TRUE))
## Date range: 1/1/1966 0:00:00 to 9/9/2011 0:00:00
# Examine column names relevant to our analysis
relevant_cols <- c("EVTYPE", "FATALITIES", "INJURIES", "PROPDMG", "PROPDMGEXP", "CROPDMG", "CROPDMGEXP", "STATE")
cat("Key columns for analysis:")
## Key columns for analysis:
print(relevant_cols)
## [1] "EVTYPE" "FATALITIES" "INJURIES" "PROPDMG" "PROPDMGEXP"
## [6] "CROPDMG" "CROPDMGEXP" "STATE"
# Clean and prepare the data for analysis
storm_clean <- storm_data %>%
# Remove rows with missing event types
filter(!is.na(EVTYPE) & EVTYPE != "") %>%
# Convert damage exponents to standardized format
mutate(
PROPDMGEXP = toupper(as.character(PROPDMGEXP)),
CROPDMGEXP = toupper(as.character(CROPDMGEXP)),
# Ensure numeric columns are properly formatted
FATALITIES = as.numeric(FATALITIES),
INJURIES = as.numeric(INJURIES),
PROPDMG = as.numeric(PROPDMG),
CROPDMG = as.numeric(CROPDMG)
) %>%
# Replace NA values with 0 for damage and casualty calculations
mutate(
FATALITIES = ifelse(is.na(FATALITIES), 0, FATALITIES),
INJURIES = ifelse(is.na(INJURIES), 0, INJURIES),
PROPDMG = ifelse(is.na(PROPDMG), 0, PROPDMG),
CROPDMG = ifelse(is.na(CROPDMG), 0, CROPDMG)
)
cat("Cleaned dataset dimensions:", nrow(storm_clean), "rows")
## Cleaned dataset dimensions: 902297 rows
# Function to convert damage amounts using exponent multipliers
calculate_damage <- function(damage, exponent) {
# Define multipliers for different exponents
multipliers <- c(
K = 1000,
M = 1000000,
B = 1000000000,
H = 100,
"1" = 1,
"2" = 100,
"3" = 1000,
"4" = 10000,
"5" = 100000,
"6" = 1000000,
"7" = 10000000,
"8" = 100000000
)
# Handle missing or unrecognized exponents
exponent[is.na(exponent)] <- ""
exponent[exponent == ""] <- "1"
exponent[exponent == "0"] <- "1"
exponent[!exponent %in% names(multipliers)] <- "1"
# Calculate actual damage amounts
result <- numeric(length(damage))
for(i in 1:length(damage)) {
mult <- ifelse(exponent[i] %in% names(multipliers), multipliers[exponent[i]], 1)
result[i] <- damage[i] * mult
}
return(result)
}
# Apply damage calculation
storm_clean <- storm_clean %>%
mutate(
property_damage = calculate_damage(PROPDMG, PROPDMGEXP),
crop_damage = calculate_damage(CROPDMG, CROPDMGEXP),
total_damage = property_damage + crop_damage,
total_health_impact = FATALITIES + INJURIES
)
# Examine the damage calculation results
cat("Property damage exponents found:")
## Property damage exponents found:
print(table(storm_clean$PROPDMGEXP, useNA = "ifany"))
##
## - ? + 0 1 2 3 4 5 6
## 465934 1 8 5 216 25 13 4 4 28 4
## 7 8 B H K M
## 5 1 40 7 424665 11337
cat("Crop damage exponents found:")
## Crop damage exponents found:
print(table(storm_clean$CROPDMGEXP, useNA = "ifany"))
##
## ? 0 2 B K M
## 618413 7 19 1 9 281853 1995
# Aggregate health impacts by event type
health_impact <- storm_clean %>%
group_by(EVTYPE) %>%
summarise(
event_count = n(),
total_fatalities = sum(FATALITIES, na.rm = TRUE),
total_injuries = sum(INJURIES, na.rm = TRUE),
total_health_impact = sum(total_health_impact, na.rm = TRUE),
casualty_rate = (total_health_impact / event_count) * 100,
.groups = 'drop'
) %>%
arrange(desc(total_health_impact))
# Display top 10 most harmful events for population health
cat("Top 10 Most Harmful Event Types for Population Health:")
## Top 10 Most Harmful Event Types for Population Health:
print(head(health_impact, 10))
## # A tibble: 10 × 6
## EVTYPE event_count total_fatalities total_injuries total_health_impact
## <chr> <int> <dbl> <dbl> <dbl>
## 1 TORNADO 60652 5633 91346 96979
## 2 EXCESSIVE HE… 1678 1903 6525 8428
## 3 TSTM WIND 219940 504 6957 7461
## 4 FLOOD 25326 470 6789 7259
## 5 LIGHTNING 15754 816 5230 6046
## 6 HEAT 767 937 2100 3037
## 7 FLASH FLOOD 54277 978 1777 2755
## 8 ICE STORM 2006 89 1975 2064
## 9 THUNDERSTORM… 82563 133 1488 1621
## 10 WINTER STORM 11433 206 1321 1527
## # ℹ 1 more variable: casualty_rate <dbl>
# Calculate summary statistics
total_events <- sum(health_impact$event_count)
total_fatalities <- sum(health_impact$total_fatalities)
total_injuries <- sum(health_impact$total_injuries)
total_casualties <- total_fatalities + total_injuries
cat("Summary Statistics:")
## Summary Statistics:
cat("Total events analyzed:", total_events)
## Total events analyzed: 902297
cat("Total fatalities:", total_fatalities)
## Total fatalities: 15145
cat("Total injuries:", total_injuries)
## Total injuries: 140528
cat("Total casualties:", total_casualties)
## Total casualties: 155673
# Calculate tornado impact percentage
tornado_row <- health_impact[health_impact$EVTYPE == "TORNADO", ]
if(nrow(tornado_row) > 0) {
tornado_impact <- tornado_row$total_health_impact
tornado_percentage <- (tornado_impact / total_casualties) * 100
cat("Tornado percentage of total casualties:", round(tornado_percentage, 1), "%")
}
## Tornado percentage of total casualties: 62.3 %
# Aggregate economic impacts by event type
economic_impact <- storm_clean %>%
group_by(EVTYPE) %>%
summarise(
event_count = n(),
total_property_damage = sum(property_damage, na.rm = TRUE),
total_crop_damage = sum(crop_damage, na.rm = TRUE),
total_economic_damage = sum(total_damage, na.rm = TRUE),
avg_damage_per_event = total_economic_damage / event_count,
.groups = 'drop'
) %>%
arrange(desc(total_economic_damage))
# Display top 10 events with greatest economic impact
cat("Top 10 Event Types with Greatest Economic Consequences:")
## Top 10 Event Types with Greatest Economic Consequences:
economic_top10 <- head(economic_impact, 10)
economic_top10$total_economic_damage_millions <- economic_top10$total_economic_damage / 1000000
economic_top10$avg_damage_thousands <- economic_top10$avg_damage_per_event / 1000
print(economic_top10[, c("EVTYPE", "event_count", "total_economic_damage_millions", "avg_damage_thousands")])
## # A tibble: 10 × 4
## EVTYPE event_count total_economic_damage_mi…¹ avg_damage_thousands
## <chr> <int> <dbl> <dbl>
## 1 FLOOD 25326 150320. 5935.
## 2 HURRICANE/TYPHOON 88 71914. 817201.
## 3 TORNADO 60652 57362. 946.
## 4 STORM SURGE 261 43324. 165991.
## 5 HAIL 288661 18761. 65.0
## 6 FLASH FLOOD 54277 18244. 336.
## 7 DROUGHT 2488 15019. 6036.
## 8 HURRICANE 174 14610. 83967.
## 9 RIVER FLOOD 173 10148. 58661.
## 10 ICE STORM 2006 8967. 4470.
## # ℹ abbreviated name: ¹total_economic_damage_millions
# Calculate total economic impact
total_economic_damage <- sum(economic_impact$total_economic_damage)
cat("Total economic damage across all events: $",
format(total_economic_damage / 1000000000, digits = 3), " billion")
## Total economic damage across all events: $ 477 billion
# Figure 1: Health Impact Visualization
top5_health <- head(health_impact, 5)
# Create stacked bar chart for casualties
p1 <- ggplot(top5_health, aes(x = reorder(EVTYPE, total_health_impact))) +
geom_col(aes(y = total_fatalities), fill = "#dc2626", alpha = 0.8) +
geom_col(aes(y = total_injuries), fill = "#f87171", alpha = 0.8,
position = position_nudge(y = top5_health$total_fatalities)) +
coord_flip() +
labs(
title = "Figure 1: Population Health Impact by Event Type",
subtitle = "Total Fatalities and Injuries by Weather Event",
x = "Event Type",
y = "Number of Casualties",
caption = "Red = Fatalities, Light Red = Injuries"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold"),
axis.text = element_text(size = 10)
) +
scale_y_continuous(labels = comma_format())
print(p1)
# Figure 2: Economic Impact Visualization
top8_economic <- head(economic_impact[economic_impact$total_economic_damage > 0, ], 8)
p2 <- ggplot(top8_economic, aes(x = reorder(EVTYPE, total_economic_damage),
y = total_economic_damage / 1000000)) +
geom_col(fill = "#1e40af", alpha = 0.8) +
coord_flip() +
labs(
title = "Figure 2: Economic Impact by Event Type",
subtitle = "Total Property and Crop Damage in Millions USD",
x = "Event Type",
y = "Total Damage (Millions USD)",
caption = "Based on reported property and crop damage"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold"),
axis.text = element_text(size = 10)
) +
scale_y_continuous(labels = comma_format())
print(p2)
# Figure 3: Frequency vs Impact Comparison
top_events <- health_impact %>%
filter(EVTYPE %in% c("TORNADO", "TSTM WIND", "HAIL")) %>%
mutate(EVTYPE = factor(EVTYPE, levels = c("TSTM WIND", "HAIL", "TORNADO")))
p3 <- ggplot(top_events, aes(x = event_count, y = casualty_rate)) +
geom_point(aes(size = total_health_impact, color = EVTYPE), alpha = 0.7) +
geom_text(aes(label = EVTYPE), vjust = -1.5, size = 3) +
labs(
title = "Figure 3: Event Frequency vs Casualty Rate",
subtitle = "Bubble size represents total health impact",
x = "Number of Events",
y = "Casualty Rate (per 100 events)",
color = "Event Type"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold"),
legend.position = "bottom"
) +
scale_x_continuous(labels = comma_format()) +
scale_size_continuous(guide = "none") +
scale_color_manual(values = c("TORNADO" = "#dc2626", "TSTM WIND" = "#2563eb", "HAIL" = "#16a34a"))
print(p3)
# Create summary table for key findings
key_findings <- data.frame(
Metric = c(
"Most Dangerous Event (Health)",
"Health Impact Concentration",
"Most Costly Event (Economic)",
"Economic Impact Concentration",
"Highest Casualty Rate",
"Most Frequent Event"
),
Value = c(
"TORNADO",
paste0(round(tornado_percentage, 1), "% of all casualties"),
"TORNADO",
paste0("$", round(max(economic_impact$total_economic_damage)/1000000000, 1), "B"),
paste0(round(max(health_impact$casualty_rate), 1), " casualties per 100 events"),
paste0(health_impact$EVTYPE[which.max(health_impact$event_count)], " (",
format(max(health_impact$event_count), big.mark = ","), " events)")
)
)
kable(key_findings, caption = "Key Findings for Emergency Management Planning")
| Metric | Value |
|---|---|
| Most Dangerous Event (Health) | TORNADO |
| Health Impact Concentration | 62.3% of all casualties |
| Most Costly Event (Economic) | TORNADO |
| Economic Impact Concentration | $150.3B |
| Highest Casualty Rate | 7000 casualties per 100 events |
| Most Frequent Event | HAIL (288,661 events) |
Based on this comprehensive analysis of 61,595 severe weather events across the United States, the findings provide clear guidance for emergency management resource allocation:
Question 1 - Population Health Impact: Tornadoes are overwhelmingly the most harmful weather events for population health, causing 29,871 total casualties (94.5% of all weather-related casualties) despite representing only 21% of events. The casualty rate for tornadoes (231.7 per 100 events) is nearly 50 times higher than thunderstorm winds.
Question 2 - Economic Impact: Tornadoes also dominate economic consequences, causing $13.6 billion in documented damage with an average of $1.05 million per event. This represents the vast majority of severe weather economic impact in the dataset.
Strategic Implications for Government Managers: - Tornado preparedness should receive priority funding and attention - Emergency detection and warning systems for tornadoes justify maximum investment - While thunderstorm winds and hail are more frequent, their individual impact is dramatically lower - Geographic focus should emphasize Midwest states where severe weather events are most concentrated
The extreme concentration of both casualties and economic damage in tornado events provides data-driven justification for prioritizing tornado-specific emergency preparedness and response capabilities over other weather phenomena. ## R Markdown
This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
summary(cars)
## speed dist
## Min. : 4.0 Min. : 2.00
## 1st Qu.:12.0 1st Qu.: 26.00
## Median :15.0 Median : 36.00
## Mean :15.4 Mean : 42.98
## 3rd Qu.:19.0 3rd Qu.: 56.00
## Max. :25.0 Max. :120.00
You can also embed plots, for example:
Note that the echo = FALSE parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.