Title

Among a Total of 984 Events:

The Most Harmful Event is TORNADO, and the Greatest Economic Consequence Event is FLOOD

Synopsis

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.

Load required libraries (Messages loading the packages are suppressed on purpose)

suppressMessages(library(dplyr))
suppressMessages(library(ggplot2))
suppressMessages(library(stringr))

Function ‘report’ is created for graphs and figures reporting wrt the scope

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)
}

Function ‘std_grammar’ is create for standarding ambiguities and typos in EVTYPE

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)
}

Data Processing

Download and Load the Source File

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))

Extracting Effective Columns and Data Cleaning

data <- data %>% 
    select(EVTYPE, FATALITIES, INJURIES, PROPDMG, PROPDMGEXP, CROPDMG, CROPDMGEXP)

data <- std_grammar(data)

Handling Exponent Values of PROPDMGEXP and CROPDMGEXP

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))
)

Aggregate health and economic impacts by event type

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")

Results

Bar Charts for Health and Economy Impact

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"