Synopsis

This report analyzes the U.S. National Oceanic and Atmospheric Administration (NOAA) Storm Database for the year 2025 to identify patterns in severe weather events and their consequences for public health and the economy. The dataset was assembled by joining three CSV files — event details, fatalities, and locations — using the shared EVENT_ID key. The analysis reveals that tornadoes, thunderstorm winds, and flash floods are the most frequent event types and among the most harmful to human health in terms of fatalities and injuries. Certain states, particularly those in the central and southeastern United States, experience disproportionately high storm activity. Monthly distribution of events shows a strong seasonal pattern, with storm activity peaking in the spring and summer months. A supplementary analysis examines the economic cost of weather events by state, revealing that property and crop damage is concentrated in a small number of high-impact event types. This report is intended to inform government and municipal managers responsible for emergency preparedness and resource allocation decisions.


Data Processing

Loading Required Libraries

library(dplyr)
library(readr)
library(ggplot2)
library(forcats)
library(lubridate)
library(tidyr)
library(scales)
library(knitr)

Downloading and Loading the Data

The data are sourced from NOAA’s Storm Events database. Three CSV files for the year 2025 are used:

  • Details: Core event-level information (event type, location, health impacts, damage estimates)
  • Fatalities: Individual fatality records linked to events
  • Locations: Geographic location data for each event
folder_path <- "/Users/tylerderkovitz/Downloads/storm_data"

details_file   <- file.path(folder_path, "StormEvents_details-ftp_v1.0_d2025_c20260323.csv.gz")
fatalities_file <- file.path(folder_path, "StormEvents_fatalities-ftp_v1.0_d2025_c20260323.csv.gz")
locations_file  <- file.path(folder_path, "StormEvents_locations-ftp_v1.0_d2025_c20260323.csv.gz")

details    <- read_csv(details_file,    show_col_types = FALSE)
fatalities <- read_csv(fatalities_file, show_col_types = FALSE)
locations  <- read_csv(locations_file,  show_col_types = FALSE)

Joining the Files

The three files are linked by EVENT_ID. A left join is used so that all events in the details file are retained, even if they have no associated fatalities or location records.

joined_data <- details %>%
  left_join(locations,   by = "EVENT_ID") %>%
  left_join(fatalities,  by = "EVENT_ID")

# Save the joined dataset for reference
output_file <- file.path(folder_path, "StormEvents_joined_data.csv")
write_csv(joined_data, output_file)
message("Joined data saved to: ", output_file)

# Preview
glimpse(joined_data)
## Rows: 94,364
## Columns: 70
## $ BEGIN_YEARMONTH    <dbl> 202503, 202503, 202501, 202501, 202501, 202501, 202…
## $ BEGIN_DAY          <dbl> 31, 30, 5, 3, 3, 3, 3, 3, 3, 3, 19, 13, 13, 13, 13,…
## $ BEGIN_TIME         <dbl> 1104, 1552, 1800, 1300, 1300, 1300, 1547, 1527, 130…
## $ END_YEARMONTH      <dbl> 202503, 202503, 202501, 202501, 202501, 202501, 202…
## $ END_DAY            <dbl> 31, 30, 6, 3, 3, 3, 3, 3, 3, 3, 19, 13, 13, 13, 13,…
## $ END_TIME           <dbl> 1106, 1555, 2227, 1900, 1900, 1900, 1619, 1619, 190…
## $ EPISODE_ID.x       <dbl> 201366, 200337, 197733, 197761, 197761, 197761, 197…
## $ EVENT_ID           <dbl> 1252415, 1241136, 1222851, 1223112, 1223113, 122311…
## $ STATE              <chr> "GEORGIA", "MICHIGAN", "VIRGINIA", "MARYLAND", "MAR…
## $ STATE_FIPS         <dbl> 13, 26, 51, 24, 24, 24, 24, 51, 24, 24, 27, 27, 27,…
## $ YEAR               <dbl> 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2025, 202…
## $ MONTH_NAME         <chr> "March", "March", "January", "January", "January", …
## $ EVENT_TYPE         <chr> "Thunderstorm Wind", "Tornado", "Winter Storm", "Wi…
## $ CZ_TYPE            <chr> "C", "C", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "…
## $ CZ_FIPS            <dbl> 45, 27, 56, 506, 504, 503, 14, 53, 5, 505, 89, 71, …
## $ CZ_NAME            <chr> "CARROLL", "CASS", "SPOTSYLVANIA", "CENTRAL AND SOU…
## $ WFO                <chr> "FFC", "IWX", "LWX", "LWX", "LWX", "LWX", "LWX", "L…
## $ BEGIN_DATE_TIME    <chr> "31-MAR-25 11:04:00", "30-MAR-25 15:52:00", "05-JAN…
## $ CZ_TIMEZONE        <chr> "EST-5", "EST-5", "EST-5", "EST-5", "EST-5", "EST-5…
## $ END_DATE_TIME      <chr> "31-MAR-25 11:06:00", "30-MAR-25 15:55:00", "06-JAN…
## $ INJURIES_DIRECT    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ INJURIES_INDIRECT  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ DEATHS_DIRECT      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ DEATHS_INDIRECT    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ DAMAGE_PROPERTY    <chr> "1.00K", "100.00K", NA, NA, NA, NA, "0.00K", NA, NA…
## $ DAMAGE_CROPS       <chr> NA, "0.00K", NA, NA, NA, NA, "0.00K", NA, NA, NA, "…
## $ SOURCE             <chr> "Emergency Manager", "NWS Storm Survey", "Trained S…
## $ MAGNITUDE          <dbl> 52.0, NA, NA, NA, NA, NA, NA, NA, NA, NA, 38.0, NA,…
## $ MAGNITUDE_TYPE     <chr> "EG", NA, NA, NA, NA, NA, NA, NA, NA, NA, "MS", NA,…
## $ FLOOD_CAUSE        <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ CATEGORY           <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ TOR_F_SCALE        <chr> NA, "EF1", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ TOR_LENGTH         <dbl> NA, 2.59, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ TOR_WIDTH          <dbl> NA, 100, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ TOR_OTHER_WFO      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ TOR_OTHER_CZ_STATE <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ TOR_OTHER_CZ_FIPS  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ TOR_OTHER_CZ_NAME  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ BEGIN_RANGE        <dbl> 2.22, 1.24, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ BEGIN_AZIMUTH      <chr> "W", "SW", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ BEGIN_LOCATION     <chr> "TYUS", "EDWARDSBURG", NA, NA, NA, NA, NA, NA, NA, …
## $ END_RANGE          <dbl> 2.22, 1.47, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ END_AZIMUTH        <chr> "W", "NNE", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ END_LOCATION       <chr> "TYUS", "EDWARDSBURG", NA, NA, NA, NA, NA, NA, NA, …
## $ BEGIN_LAT          <dbl> 33.4757, 41.7900, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ BEGIN_LON          <dbl> -85.238, -86.100, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ END_LAT            <dbl> 33.4757, 41.8200, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ END_LON            <dbl> -85.238, -86.070, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ EPISODE_NARRATIVE  <chr> "A cold-front initiated a line of thunderstorms acr…
## $ EVENT_NARRATIVE    <chr> "Tree down at the intersection of highway 5 and old…
## $ DATA_SOURCE        <chr> "CSV", "CSV", "CSV", "CSV", "CSV", "CSV", "CSV", "C…
## $ YEARMONTH          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ EPISODE_ID.y       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ LOCATION_INDEX     <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ RANGE              <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ AZIMUTH            <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ LOCATION           <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ LATITUDE           <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ LONGITUDE          <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ LAT2               <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ LON2               <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FAT_YEARMONTH      <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FAT_DAY            <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FAT_TIME           <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FATALITY_ID        <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FATALITY_TYPE      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FATALITY_DATE      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FATALITY_AGE       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FATALITY_SEX       <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ FATALITY_LOCATION  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…

Data Cleaning and Transformation

# Standardize column names to uppercase for consistency
names(joined_data) <- toupper(names(joined_data))

# Parse the begin date and extract month
# NOAA dates can appear as "01-JAN-25 00:00:00" or "1/1/2025 0:00:00"
# We try multiple formats and fall back to BEGIN_YEARMONTH if needed
joined_data <- joined_data %>%
  mutate(
    BEGIN_DATE_TIME_PARSED = parse_date_time(
      BEGIN_DATE_TIME,
      orders = c("dmy HMS", "mdy HMS", "dmy HM", "mdy HM", "dmy", "mdy"),
      quiet = TRUE
    ),
    # If parse_date_time failed, extract month directly from BEGIN_YEARMONTH (format: YYYYMM)
    MONTH_NUM = case_when(
      !is.na(BEGIN_DATE_TIME_PARSED) ~ month(BEGIN_DATE_TIME_PARSED),
      !is.na(BEGIN_YEARMONTH)        ~ as.integer(BEGIN_YEARMONTH) %% 100L,
      TRUE                           ~ NA_integer_
    ),
    MONTH = month(MONTH_NUM, label = TRUE, abbr = TRUE)
  )

# Convert damage columns: handle suffix K (thousands), M (millions), B (billions)
parse_damage <- function(x) {
  x <- toupper(trimws(as.character(x)))
  multiplier <- case_when(
    grepl("K$", x) ~ 1e3,
    grepl("M$", x) ~ 1e6,
    grepl("B$", x) ~ 1e9,
    TRUE            ~ 1
  )
  numeric_part <- as.numeric(gsub("[^0-9.]", "", x))
  ifelse(is.na(numeric_part), 0, numeric_part * multiplier)
}

joined_data <- joined_data %>%
  mutate(
    DAMAGE_PROPERTY_NUM = parse_damage(DAMAGE_PROPERTY),
    DAMAGE_CROPS_NUM    = parse_damage(DAMAGE_CROPS),
    TOTAL_DAMAGE        = DAMAGE_PROPERTY_NUM + DAMAGE_CROPS_NUM,
    INJURIES_DIRECT     = replace_na(INJURIES_DIRECT, 0),
    INJURIES_INDIRECT   = replace_na(INJURIES_INDIRECT, 0),
    DEATHS_DIRECT       = replace_na(DEATHS_DIRECT, 0),
    DEATHS_INDIRECT     = replace_na(DEATHS_INDIRECT, 0),
    TOTAL_INJURIES      = INJURIES_DIRECT + INJURIES_INDIRECT,
    TOTAL_DEATHS        = DEATHS_DIRECT + DEATHS_INDIRECT
  )

cat("Rows in joined dataset:", nrow(joined_data), "\n")
## Rows in joined dataset: 94364
cat("Unique event types:", n_distinct(joined_data$EVENT_TYPE), "\n")
## Unique event types: 48
cat("States covered:", n_distinct(joined_data$STATE), "\n")
## States covered: 68
cat("Rows with valid MONTH:", sum(!is.na(joined_data$MONTH)), "\n")
## Rows with valid MONTH: 94364
print(table(joined_data$MONTH, useNA = "ifany"))
## 
##   Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov   Dec 
##  6217  7953  7934  9447 11793 13859 15590  7196  3949  2468  2855  5103

Results

Question 1: Which Event Types Are Most Harmful to Population Health?

Population health impact is measured by combining total fatalities and total injuries across all recorded events for each event type.

health_summary <- joined_data %>%
  group_by(EVENT_TYPE) %>%
  summarise(
    Total_Deaths   = sum(TOTAL_DEATHS,   na.rm = TRUE),
    Total_Injuries = sum(TOTAL_INJURIES, na.rm = TRUE),
    Total_Impact   = Total_Deaths + Total_Injuries,
    .groups = "drop"
  ) %>%
  arrange(desc(Total_Impact)) %>%
  slice_head(n = 15) %>%
  pivot_longer(cols = c(Total_Deaths, Total_Injuries),
               names_to = "Impact_Type", values_to = "Count") %>%
  mutate(EVENT_TYPE = fct_reorder(EVENT_TYPE, Count, .fun = sum))

ggplot(health_summary, aes(x = Count, y = EVENT_TYPE, fill = Impact_Type)) +
  geom_col(position = "stack") +
  scale_fill_manual(values = c("Total_Deaths" = "#c0392b", "Total_Injuries" = "#e67e22"),
                    labels = c("Fatalities", "Injuries")) +
  scale_x_continuous(labels = comma) +
  labs(
    title    = "Top 15 Most Harmful Storm Event Types: Population Health Impact (2025)",
    subtitle = "Stacked bars show fatalities (red) and injuries (orange)",
    x        = "Total Count (Fatalities + Injuries)",
    y        = "Event Type",
    fill     = "Impact Type",
    caption  = "Source: NOAA Storm Events Database, 2025"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "bottom",
        plot.title = element_text(face = "bold"))
Figure 1: Top 15 storm event types ranked by total population health impact (fatalities + injuries) in 2025. Tornadoes and thunderstorm winds consistently dominate health-related storm impacts.

Figure 1: Top 15 storm event types ranked by total population health impact (fatalities + injuries) in 2025. Tornadoes and thunderstorm winds consistently dominate health-related storm impacts.

Interpretation: The event types with the greatest population health impact are those that are both common and difficult to avoid, such as tornadoes, thunderstorm winds, flash floods, and heat events. Fatalities, though fewer in count than injuries, represent irreversible harm and deserve particular attention in emergency planning.


Question 2: Which Event Types Occur Most Frequently in Which States?

This analysis examines the geographic distribution of storm events. We identify the top event type per state by frequency.

# Total events per state (top 15)
state_totals <- joined_data %>%
  filter(!is.na(STATE)) %>%
  count(STATE, name = "Event_Count") %>%
  arrange(desc(Event_Count)) %>%
  slice_head(n = 15) %>%
  mutate(STATE = fct_reorder(STATE, Event_Count))

ggplot(state_totals, aes(x = Event_Count, y = STATE, fill = Event_Count)) +
  geom_col() +
  scale_fill_gradient(low = "#aed6f1", high = "#1a5276") +
  scale_x_continuous(labels = comma) +
  labs(
    title   = "Top 15 States by Total Recorded Storm Events (2025)",
    x       = "Number of Events",
    y       = "State",
    fill    = "Event Count",
    caption = "Source: NOAA Storm Events Database, 2025"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold"))
Figure 2: Top 10 states by total number of storm events recorded in 2025. States in the central and southeastern U.S. tend to experience the highest event counts.

Figure 2: Top 10 states by total number of storm events recorded in 2025. States in the central and southeastern U.S. tend to experience the highest event counts.

# Most common event type within top 15 states
top_states <- state_totals$STATE

state_event_type <- joined_data %>%
  filter(STATE %in% levels(top_states)) %>%
  count(STATE, EVENT_TYPE) %>%
  group_by(STATE) %>%
  slice_max(n, n = 1, with_ties = FALSE) %>%
  ungroup() %>%
  mutate(STATE = factor(STATE, levels = levels(top_states)))

ggplot(state_event_type, aes(x = n, y = STATE, fill = EVENT_TYPE)) +
  geom_col() +
  labs(
    title   = "Most Frequent Storm Event Type per State (Top 15 States, 2025)",
    x       = "Number of Occurrences",
    y       = "State",
    fill    = "Dominant Event Type",
    caption = "Source: NOAA Storm Events Database, 2025"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "bottom",
        legend.text = element_text(size = 9),
        plot.title = element_text(face = "bold")) +
  guides(fill = guide_legend(nrow = 3))
Figure 3: Most common storm event type in each of the top 15 states. This highlights how storm risk profiles differ by region and can guide state-level emergency preparedness priorities.

Figure 3: Most common storm event type in each of the top 15 states. This highlights how storm risk profiles differ by region and can guide state-level emergency preparedness priorities.

Interpretation: Storm frequency varies substantially by state. States with large geographic areas or those situated in climatologically active zones (such as tornado alley or the Gulf Coast) tend to record higher event counts. The dominant event type in each state reflects its regional climate profile and should shape local emergency preparedness investments.


Question 3: Which Event Types Are Characterized by Which Months?

This analysis explores the seasonal timing of different storm event types.

# Top 10 event types overall
top_events <- joined_data %>%
  count(EVENT_TYPE, sort = TRUE) %>%
  slice_head(n = 10) %>%
  pull(EVENT_TYPE)

monthly_dist <- joined_data %>%
  filter(EVENT_TYPE %in% top_events, !is.na(MONTH)) %>%
  count(EVENT_TYPE, MONTH, MONTH_NUM) %>%
  mutate(EVENT_TYPE = factor(EVENT_TYPE, levels = top_events))

ggplot(monthly_dist, aes(x = MONTH, y = n, fill = EVENT_TYPE)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ EVENT_TYPE, scales = "free_y", ncol = 2) +
  labs(
    title   = "Monthly Distribution of Top 10 Storm Event Types (2025)",
    x       = "Month",
    y       = "Number of Events",
    caption = "Source: NOAA Storm Events Database, 2025"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    strip.text = element_text(face = "bold", size = 9),
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(face = "bold")
  )
Figure 4: Monthly distribution of the top 10 most frequent storm event types. Clear seasonal patterns emerge, with most event types peaking in spring and summer months.

Figure 4: Monthly distribution of the top 10 most frequent storm event types. Clear seasonal patterns emerge, with most event types peaking in spring and summer months.

Interpretation: Seasonal patterns are strongly evident in the data. Thunderstorm winds and tornadoes peak in spring and early summer, consistent with atmospheric instability during those months. Winter storms naturally concentrate in December through February. Understanding these seasonal windows is essential for pre-positioning emergency resources and staffing.


Question 4: Which States Incur the Greatest Economic Damage from Storm Events?

Beyond human health, severe weather causes substantial economic damage through property destruction and crop losses. This question examines total economic losses by state.

damage_by_state <- joined_data %>%
  filter(!is.na(STATE)) %>%
  group_by(STATE) %>%
  summarise(
    Total_Property_Damage = sum(DAMAGE_PROPERTY_NUM, na.rm = TRUE),
    Total_Crop_Damage     = sum(DAMAGE_CROPS_NUM,    na.rm = TRUE),
    Total_Damage          = Total_Property_Damage + Total_Crop_Damage,
    .groups = "drop"
  ) %>%
  arrange(desc(Total_Damage)) %>%
  slice_head(n = 15) %>%
  pivot_longer(cols = c(Total_Property_Damage, Total_Crop_Damage),
               names_to = "Damage_Type", values_to = "Amount") %>%
  mutate(STATE = fct_reorder(STATE, Amount, .fun = sum))

ggplot(damage_by_state, aes(x = Amount, y = STATE, fill = Damage_Type)) +
  geom_col(position = "stack") +
  scale_x_continuous(labels = label_dollar(scale = 1e-6, suffix = "M")) +
  scale_fill_manual(values = c("Total_Property_Damage" = "#2980b9",
                                "Total_Crop_Damage"     = "#27ae60"),
                    labels = c("Property Damage", "Crop Damage")) +
  labs(
    title   = "Top 15 States by Total Storm-Related Economic Damage (2025)",
    subtitle = "Stacked bars show property (blue) and crop (green) damage",
    x       = "Total Estimated Damage (Millions USD)",
    y       = "State",
    fill    = "Damage Type",
    caption = "Source: NOAA Storm Events Database, 2025"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "bottom",
        plot.title = element_text(face = "bold"))
Figure 5: Total estimated economic damage (property + crop) by state for the top 15 highest-impact states in 2025. A small number of states account for the majority of storm-related economic losses.

Figure 5: Total estimated economic damage (property + crop) by state for the top 15 highest-impact states in 2025. A small number of states account for the majority of storm-related economic losses.

Interpretation: Economic damage from severe weather is highly concentrated in a few states, often driven by a handful of large-scale events such as major floods or tornadoes. Property damage consistently outweighs crop damage in dollar terms, though agricultural communities may experience crop losses as a more directly life-altering impact. This information can guide federal and state-level infrastructure investment and disaster relief pre-funding.


Summary Table

summary_tbl <- joined_data %>%
  group_by(EVENT_TYPE) %>%
  summarise(
    Events      = n(),
    Deaths      = sum(TOTAL_DEATHS,   na.rm = TRUE),
    Injuries    = sum(TOTAL_INJURIES, na.rm = TRUE),
    Damage_USD  = sum(TOTAL_DAMAGE,   na.rm = TRUE),
    .groups = "drop"
  ) %>%
  arrange(desc(Events)) %>%
  slice_head(n = 10) %>%
  mutate(Damage_USD = dollar(Damage_USD))

kable(summary_tbl,
      col.names = c("Event Type", "# Events", "Deaths", "Injuries", "Total Damage"),
      caption   = "Table 1: Top 10 most frequent storm event types and their health/economic impacts (2025)",
      align     = c("l", "r", "r", "r", "r"))
Table 1: Top 10 most frequent storm event types and their health/economic impacts (2025)
Event Type # Events Deaths Injuries Total Damage
Thunderstorm Wind 22256 105 158 $318,779,700
Flash Flood 20167 37430 81 $78,288,453,100
Hail 9319 0 8 $74,087,500
Flood 7497 55 20 $314,134,150
High Wind 4604 9 9 $12,261,600
Winter Weather 4443 47 131 $2,293,500
Drought 3283 0 0 $39,503,250
Winter Storm 2962 65 33 $4,107,750
Heat 2926 429 51 $0
Tornado 2471 441 688 $13,269,143,500

Session Info

sessionInfo()
## R version 4.5.2 (2025-10-31)
## Platform: aarch64-apple-darwin20
## Running under: macOS Tahoe 26.3.1
## 
## Matrix products: default
## BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: America/New_York
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] knitr_1.51      scales_1.4.0    tidyr_1.3.2     lubridate_1.9.5
## [5] forcats_1.0.1   ggplot2_4.0.3   readr_2.2.0     dplyr_1.2.1    
## 
## loaded via a namespace (and not attached):
##  [1] bit_4.6.0          gtable_0.3.6       jsonlite_2.0.0     crayon_1.5.3      
##  [5] compiler_4.5.2     tidyselect_1.2.1   parallel_4.5.2     jquerylib_0.1.4   
##  [9] yaml_2.3.12        fastmap_1.2.0      R6_2.6.1           labeling_0.4.3    
## [13] generics_0.1.4     tibble_3.3.1       bslib_0.9.0        pillar_1.11.1     
## [17] RColorBrewer_1.1-3 tzdb_0.5.0         rlang_1.1.7        cachem_1.1.0      
## [21] xfun_0.56          sass_0.4.10        S7_0.2.1           bit64_4.6.0-1     
## [25] otel_0.2.0         timechange_0.4.0   cli_3.6.5          withr_3.0.2       
## [29] magrittr_2.0.4     digest_0.6.39      grid_4.5.2         vroom_1.7.1       
## [33] rstudioapi_0.18.0  hms_1.1.4          lifecycle_1.0.5    vctrs_0.7.3       
## [37] evaluate_1.0.5     glue_1.8.0         farver_2.1.2       purrr_1.2.1       
## [41] rmarkdown_2.30     tools_4.5.2        pkgconfig_2.0.3    htmltools_0.5.9