This report analyzes storm event data from the NOAA Storm Database. Web interface is available here.
We focus on:
- Health impact: Fatalities and Injuries.
- Economic impact: Property and Crop damages.
Key steps:
- Download and load the dataset. - Subset the dataset to relevant
columns for efficiency.
- Aggregate health and economic impacts by event type.
- Visualize top contributors with bar charts and percentages.
The following sections present detailed results with plots and commentary.
suppressMessages(library(dplyr))
suppressMessages(library(ggplot2))
suppressMessages(library(stringr))
Refer to the Exponent Interpretation for justifications
report <- function(agg_tbl, scope){
top_items <- agg_tbl %>%
slice_max(order_by = figure, n = 9)
others <- agg_tbl %>%
slice(-(1:9)) %>%
summarise(EVTYPE = "OTHERS", figure = sum(figure))
tbl <- bind_rows(top_items, others) %>%
mutate(percentage = 100 * figure / sum(figure))
print(paste0('Total number of events: ', length(agg_tbl$EVTYPE)))
print(paste0('Events with Zero impact: ', sum(agg_tbl$figure == 0)))
print(paste0('Events with impact: ', sum(agg_tbl$figure != 0)))
print(paste0('The Event Impacting ',scope, ' the Most is ', top_items$EVTYPE[which.max(top_items$figure)]))
ggplot(tbl, aes(x = reorder(EVTYPE, percentage), y = percentage)) +
geom_bar(stat = "identity", fill = "cyan") +
geom_text(aes(label = paste0(round(percentage, 1), "%")), hjust = 0.5, size = 3) +
coord_flip() +
labs(title = paste0("Top 10 Events Impacting ", scope), x = "Event Type", y = "Percentage") +
theme_minimal(base_size = 10)
}
web_keyword is extracted from NOAA website for the 48 events in
search list.
custom_keyword is based on manual findings of
ambiguities
Irrelevant EVTYPE are dropped from the dataset
std_grammar <- function(data){
data$EVTYPE <- toupper(data$EVTYPE)
data$EVTYPE <- str_replace_all(data$EVTYPE, " {2,}", " ")
#Correcting various typos for Thunderstorm Wind
thunderstorm_typo <- 'T.*U.*E.*M WIN.*'
data$EVTYPE[str_detect(toupper(data$EVTYPE), thunderstorm_typo)] <- 'THUNDERSTORM WIND'
web_keyword <- c('ASTRONOMICAL LOW TIDE', 'AVALANCHE', 'BLIZZARD', 'COASTAL FLOOD', 'COLD/WINDHILL',
'DEBRIS FLOW', 'DENSE FOG', 'DENSE SMOKE', 'DROUGHT', 'DUST DEVIL', 'DUST STORM',
'EXCESSIVE HEAT', 'EXTREMEOLD/WINDHILL', 'FLASH FLOOD', 'FLOOD', 'FREEZING FOG',
'FROST/FREEZE', 'FUNNEL CLOUD', 'HAIL', 'HEAT', 'HEAVY RAIN', 'HEAVY SNOW',
'HIGH SURF', 'HIGH WIND', 'HURRICANE (TYPHOON)', 'ICE STORM', 'LAKE-EFFECT SNOW',
'LAKESHORE FLOOD', 'LIGHTNING', 'MARINE HAIL', 'MARINE HIGH WIND', 'MARINE STRONG WIND',
'MARINE THUNDERSTORM WIND', 'RIP CURRENT', 'SEICHE', 'SLEET', 'STORM SURGE/TIDE',
'STRONG WIND', 'THUNDERSTORM WIND', 'TORNADO', 'TROPICAL DEPRESSION', 'TROPICAL STORM',
'TSUNAMI', 'VOLCANIC ASH', 'WATERSPOUT', 'WILDFIRE', 'WINTER STORM', 'WINTER WEATHER')
matches <- str_extract(toupper(data$EVTYPE), paste(web_keyword, collapse = "|"))
data$EVTYPE <- ifelse(!is.na(matches), matches, data$EVTYPE)
top_set <- data[data$EVTYPE %in% web_keyword,] #This is the set cleaned by web_keyword
bottom_set <- data[!data$EVTYPE %in% web_keyword,] #This is the set to be cleaned by custom_keyword
custom_keyword <- c('MICROBURST' = 'MICROBURST', 'AVALAN' = 'AVALANCHE',
'TSTM' = 'THUNDERSTORM WIND', 'THUNDERSTORM' = 'THUNDERSTORM WIND',
'TYPHOON' = 'HURRICANE (TYPHOON)', 'HURRICANE' = 'HURRICANE (TYPHOON)',
'WET' = 'WET', 'RAIN' = 'RAIN', 'SNOW' = 'SNOW', 'SHOWER' = 'SHOWER',
'MUD' = 'MUDSLIDE', 'LANDSLIDE' = 'LANDSLIDE', 'URBAN' = 'URBAN/SMALL STREAM',
'WND' = 'WIND', 'COLD' = 'COLD','LOW TEMP' = 'COLD', 'HYPOTHERMIA' = 'COLD',
'FREEZING' = 'FREEZING', 'HYPERTHERMIA' = 'HEAT', 'HIGH TEMP' = 'HEAT',
'WARM' = 'HEAT', 'HOT' = 'HEAT')
matches <- str_extract((bottom_set$EVTYPE), paste(names(custom_keyword), collapse = "|"))
bottom_set$EVTYPE <- ifelse(!is.na(matches), custom_keyword[matches], bottom_set$EVTYPE)
#Dropping Irrelevant Event types
bottom_set <- bottom_set[!grepl(".*county.*", bottom_set$EVTYPE, ignore.case = TRUE), ]
bottom_set <- bottom_set[!grepl("^summary", bottom_set$EVTYPE, ignore.case = TRUE), ]
bottom_set <- bottom_set[!grepl("^record", bottom_set$EVTYPE, ignore.case = TRUE), ]
bottom_set <- bottom_set[!grepl("^monthly", bottom_set$EVTYPE, ignore.case = TRUE), ]
bottom_set <- bottom_set[!bottom_set$EVTYPE %in% c('?','NONE'), ]
# Combining the separate sets again
data <- top_set
data <- bind_rows(data, bottom_set)
}
url <- "https://d396qusza40orc.cloudfront.net/repdata%2Fdata%2FStormData.csv.bz2"
zip_file <- "stormdata.bz2"
if (!file.exists(zip_file)){
download.file(url, zip_file, mode="wb")
}
data <- read.csv(bzfile(zip_file))
data <- data %>%
select(EVTYPE, FATALITIES, INJURIES, PROPDMG, PROPDMGEXP, CROPDMG, CROPDMGEXP)
data <- std_grammar(data)
suppressWarnings(
data <- data %>%
filter(!PROPDMGEXP %in% c('?','-')) %>%
mutate(PROPDMG = case_when(
PROPDMGEXP %in% c('0','1','2','3','4','5','6','7','8') ~ PROPDMG * 10 + as.numeric(PROPDMGEXP),
PROPDMGEXP %in% c('H','h') ~ PROPDMG * 100,
PROPDMGEXP %in% c('K','k') ~ PROPDMG * 1e+03,
PROPDMGEXP %in% c('M','m') ~ PROPDMG * 1e+06,
PROPDMGEXP %in% c('B','b') ~ PROPDMG * 1e+09,
TRUE ~ PROPDMG))
)
suppressWarnings(
data <- data %>%
filter(!CROPDMGEXP %in% c('?','-')) %>%
mutate(CROPDMG = case_when(
CROPDMGEXP %in% c('0','1','2','3','4','5','6','7','8') ~ CROPDMG * 10 + as.numeric(CROPDMGEXP),
CROPDMGEXP %in% c('H','h') ~ CROPDMG * 100,
CROPDMGEXP %in% c('K','k') ~ CROPDMG * 1e+03,
CROPDMGEXP %in% c('M','m') ~ CROPDMG * 1e+06,
CROPDMGEXP %in% c('B','b') ~ CROPDMG * 1e+09,
TRUE ~ CROPDMG))
)
evt_health <- data %>% group_by(EVTYPE) %>%
summarise(figure = sum(FATALITIES + INJURIES, na.rm = TRUE), .groups = "drop")
evt_econ <- data %>% group_by(EVTYPE) %>%
summarise(figure = sum(PROPDMG + CROPDMG, na.rm = TRUE), .groups = "drop")
report(evt_health, 'Health (FATALITIES + INJURIES)')
## [1] "Total number of events: 207"
## [1] "Events with Zero impact: 122"
## [1] "Events with impact: 85"
## [1] "The Event Impacting Health (FATALITIES + INJURIES) the Most is TORNADO"
report(evt_econ, 'Economy (PROPDMG + CROPDMG)')
## [1] "Total number of events: 207"
## [1] "Events with Zero impact: 89"
## [1] "Events with impact: 118"
## [1] "The Event Impacting Economy (PROPDMG + CROPDMG) the Most is FLOOD"