In this document we will analyze data from the U.S. National Oceanic and Atmospheric Administration about different weather events and determine which kinds of weather events have the greatest impact on human health and the economy.

Data Processing

First, we read in the raw data file from NOAA.

storm <- read.csv("StormData.csv.bz2")

We consider first the types of events that are most harmful to human health.

We’re going to get a summary for fatalities and injuries for each event type. Our metric for damage to human life will be the sum of injuries and the figure of fatalities times 1000. It may not be possible to know how one can weigh a fatality versus an injury, but this allows us to account for some relative difference and allows us to combine damage to life into one number. This will be applied to each event. So first we will add a column to each row that contains this sum.

We’ll use dplyr to aid our data processing.

library(dplyr)
## 
## 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
storm <- storm %>%
  mutate(LIFEDMG = FATALITIES * 1000 + INJURIES, .after = INJURIES)

As there are multiple event types in the data that refer to similar events, we filter out event types with fewer than 100 observations to ensure that we get the aggregated event types. This should also give us a better sample size for each event type.

event_counts <- storm %>%
            group_by(EVTYPE) %>%
            count() %>%
            filter(n >= 100)

events <- event_counts$EVTYPE

summary_lifedmg <- storm %>%
  filter(EVTYPE %in% events) %>%
  group_by(EVTYPE) %>%
  summarise(MEAN_LIFEDMG = mean(LIFEDMG)) %>%
  arrange(desc(MEAN_LIFEDMG))

For this analysis, we’ll further limit our groups to the top 5 for damage to life.

top_lifedmg <- summary_lifedmg %>% 
  top_n(5, MEAN_LIFEDMG) %>%
  arrange(desc(MEAN_LIFEDMG))

print(top_lifedmg)
## # A tibble: 5 × 2
##   EVTYPE         MEAN_LIFEDMG
##   <chr>                 <dbl>
## 1 HEAT                  1224.
## 2 EXCESSIVE HEAT        1138.
## 3 RIP CURRENT            783.
## 4 RIP CURRENTS           672.
## 5 AVALANCHE              581.

We can see in the top 5 event types that there are a couple of pairs that could be combined, i.e. “HEAT” and “EXCESSIVE HEAT” and “RIP CURRENT” and “RIP CURRENTS”. We’ll go back to the original dataset and relabel all instances of “EXCESSIVE HEAT” as “HEAT” and all instances of “RIP CURRENTS” to “RIP CURRENT”.

storm <- storm %>%
  mutate(EVTYPE = if_else(EVTYPE == "EXCESSIVE HEAT", "HEAT", EVTYPE)) %>%
  mutate(EVTYPE = if_else(EVTYPE == "RIP CURRENTS", "RIP CURRENT", EVTYPE))

Now we’ll process again as we did before.

event_counts <- storm %>%
            group_by(EVTYPE) %>%
            count() %>%
            filter(n >= 100)

events <- event_counts$EVTYPE

summary_lifedmg <- storm %>%
  filter(EVTYPE %in% events) %>%
  group_by(EVTYPE) %>%
  summarise(MEAN_LIFEDMG = mean(LIFEDMG)) %>%
  arrange(desc(MEAN_LIFEDMG))

And we recalculate the top 5 for each category.

top_lifedmg <- summary_lifedmg %>% 
  top_n(5, MEAN_LIFEDMG) %>%
  arrange(desc(MEAN_LIFEDMG))

print(top_lifedmg)
## # A tibble: 5 × 2
##   EVTYPE       MEAN_LIFEDMG
##   <chr>               <dbl>
## 1 HEAT                1165.
## 2 RIP CURRENT          740.
## 3 AVALANCHE            581.
## 4 HURRICANE            351.
## 5 EXTREME COLD         245.

We’ll now consider the types of events that have the greatest economic consequences, as measured by damage to property and crops in the original data.

The data presents two columns for each category of economic damage, one for the value (PROPDMG, CROPDMG) and one for a multiplier (PROPDMGEXP, CROPDMGEXP). The multiplier indicates a factor to multiply the value by. For instance if PROPDMG is 25.0 and the PROPDMGEXP is “K” (meaning kilo or 1000), we would multiply 25.0 by 1000 to get $25,000 estimated property damage. So the first thing we’ll do is to create a new column with the expanded amount so that we can easily compare the data.

storm <- storm %>%
  mutate(PROPDMG = PROPDMG * case_when(
    PROPDMGEXP == "K" ~ 1000,
    PROPDMGEXP == "M" ~ 1000000,
    PROPDMGEXP == "B" ~ 1000000000,
    .default = 1
  )) %>%
  mutate(CROPDMG = CROPDMG * case_when(
    CROPDMGEXP == "K" ~ 1000,
    CROPDMGEXP == "M" ~ 1000000,
    CROPDMGEXP == "B" ~ 1000000000,
    .default = 1
  ))

We’ll also create a new column that is the sum of PROPDMG and CROPDMG called ECONDMG.

storm <- storm %>%
  mutate(ECONDMG = PROPDMG + CROPDMG, .after = CROPDMGEXP)

Now we’ll group by event type and get the top 5 for ECONDMG, much as we did for human health.

event_counts <- storm %>%
            group_by(EVTYPE) %>%
            count() %>%
            filter(n >= 100)

events <- event_counts$EVTYPE

summary <- storm %>%
  filter(EVTYPE %in% events) %>%
  group_by(EVTYPE) %>%
  summarise(MEAN_ECONDMG = mean(ECONDMG)) %>%
  arrange(desc(MEAN_ECONDMG))

top_econdmg <- summary %>% 
  top_n(5, MEAN_ECONDMG) %>%
  arrange(desc(MEAN_ECONDMG))

print(top_econdmg)
## # A tibble: 5 × 2
##   EVTYPE           MEAN_ECONDMG
##   <chr>                   <dbl>
## 1 STORM SURGE        165990579.
## 2 HURRICANE           83966833.
## 3 RIVER FLOOD         58661298.
## 4 STORM SURGE/TIDE    31365122.
## 5 TROPICAL STORM      12148169.

The top 5 contains both “STORM SURGE” and STORM SURGE/TIDE”, so let’s group these two together under STORM STURGE by relabeling the corresponding rows in the original data frame.

storm <- storm  %>%
  mutate(EVTYPE = if_else(EVTYPE == "STORM SURGE/TIDE", "STORM SURGE", EVTYPE))

Now we’ll recalculate the summaries and top 5.

event_counts <- storm %>%
            group_by(EVTYPE) %>%
            count() %>%
            filter(n >= 100)

events <- event_counts$EVTYPE

summary_econ <- storm %>%
  filter(EVTYPE %in% events) %>%
  group_by(EVTYPE) %>%
  summarise(MEAN_ECONDMG = mean(ECONDMG)) %>%
  arrange(desc(MEAN_ECONDMG))

top_econdmg <- summary_econ %>% 
  top_n(5, MEAN_ECONDMG) %>%
  arrange(desc(MEAN_ECONDMG))

print(top_econdmg)
## # A tibble: 5 × 2
##   EVTYPE         MEAN_ECONDMG
##   <chr>                 <dbl>
## 1 STORM SURGE      117275254.
## 2 HURRICANE         83966833.
## 3 RIVER FLOOD       58661298.
## 4 TROPICAL STORM    12148169.
## 5 DROUGHT            6036444.

Results

Most harmful events with respect to human health

For the purposes of this study, we define “harmful with respect to human health” as the sum of the fatalities * 1000 and injuries for a given event. Therefore we aggregated these over each event type and found that the following 5 events had the greatest recorded toll on human health:

print(top_lifedmg)
## # A tibble: 5 × 2
##   EVTYPE       MEAN_LIFEDMG
##   <chr>               <dbl>
## 1 HEAT                1165.
## 2 RIP CURRENT          740.
## 3 AVALANCHE            581.
## 4 HURRICANE            351.
## 5 EXTREME COLD         245.
  1. Heat
  2. Rip current
  3. Avalanche
  4. Hurricane
  5. Extreme cold
par(mar = c(9, 5, 5, 2))
y <- top_lifedmg$MEAN_LIFEDMG
plt <- barplot(
  main = "Mean damage to human life by event type",
  y,
  names.arg = top_lifedmg$EVTYPE,
  las = 2,
  ylab = "(fatalities x 1000) + injuries",
  ylim = c(0, max(y) + 150)
)
text(x = plt, y = y + 70, labels = round(y, 1))

Most damaging events in terms of economic damage

For the purposes of this study, we define “economic damage” as the sum of the property damage and crop damage for a given event. Therefore we aggregated these over each event type and found that the following 5 events had the greatest recorded economic damage:

print(top_econdmg)
## # A tibble: 5 × 2
##   EVTYPE         MEAN_ECONDMG
##   <chr>                 <dbl>
## 1 STORM SURGE      117275254.
## 2 HURRICANE         83966833.
## 3 RIVER FLOOD       58661298.
## 4 TROPICAL STORM    12148169.
## 5 DROUGHT            6036444.
  1. Storm surge
  2. Hurricane
  3. River flood
  4. Tropical storm
  5. Drought
par(mar = c(9, 5, 5, 2))
y <- top_econdmg$MEAN_ECONDMG / 1000000
plt <- barplot(
  main = "Mean economic damage by event type",
  y,
  names.arg = top_econdmg$EVTYPE,
  las = 2,
  ylab = "Millions of US dollars",
  ylim = c(0, max(y) + 15)
)
text(x = plt, y = y + 10, labels = round(y, 1))