Synopsis

This report analyzes data collected by the U.S. National Oceanic and Atmospheric Administration (NOAA) on severe weather events from 1950 through November 2011.

The consequences of severe weather events on population health are measured in terms of number of injuries and fatalities caused by each type of weather event. The three types of severe weather events with the greatest consequences on population health are tornadoes, heat, and thunderstorms. Flash floods are also notable for causing a relatively large number of fatalities compared to the number of injuries they cause.

The economic consequences of severe weather events are measured in terms of the dollar value of property and crop damage. The three types of events with the greatest economic consequences are hurricanes, floods, and tornadoes. Droughts are also notable for causing the greatest amount of crop damage, although they cause relatively little property damage.

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
library(stringr)
library(tidyr)
library(ggplot2)

Data are loaded into R from the original data file, available at the course website.

storms_raw <- read.csv("repdata_data_StormData.csv.bz2")

Property and crop damage are coded in the dataset with a separate column (PROPDMGEXP and CROPDMGEXP) to indicate magnitude. The documentation lists:

Based on the data, I am further assuming that:

To transform the data, first I transform the PROPDMGEXP and CROPDMGEXP variables to uppercase for consistency. Then I use dplyr::case_when() to create a multiplier column (described for property damage, but the same applies to crop damage):

  1. If PROPDMGEXP is “H”, “K”, “M”, or “B”, then the multiplier is 100, 1000, 10^6, or 10^9, as described above.
  2. If both PROPDMGEXP and PROPDMG are 0 (or PROPDMG is 0 and PROPDMGEXP is blank), then the multiplier is 0.
  3. If PROPDMGEXP is a number, then the multiplier is 10^PROPDMGEXP. Note that if PROPDMGEXP is 0 and PROPDMG is nonzero, the multiplier will be 1.
  4. In all other cases, the multiplier is 1. Most commonly this is when PROPDMGEXP is blank and PROPDMG is nonzero.

Once the multiplier is created, a total damage column is added. If PROPDMG is nonzero, it is simply multiplied by the multiplier. Otherwise, the total is 5 times the multiplier, as described above.

storms <- storms_raw |> 
  mutate(PROPDMGEXP = toupper(PROPDMGEXP),
         CROPDMGEXP = toupper(CROPDMGEXP),
         prop_multiplier = case_when(PROPDMGEXP == "H" ~ 100,
                                     PROPDMGEXP == "K" ~ 1000,
                                     PROPDMGEXP == "M" ~ 10^6,
                                     PROPDMGEXP == "B" ~ 10^9,
                                     PROPDMGEXP %in% c("0", "") & PROPDMG == 0 ~ 0,
                                     !is.na(as.numeric(PROPDMGEXP)) ~ 10^as.numeric(PROPDMGEXP),
                                     TRUE ~ 1),
         crop_multiplier = case_when(CROPDMGEXP == "H" ~ 100,
                                     CROPDMGEXP == "K" ~ 1000,
                                     CROPDMGEXP == "M" ~ 10^6,
                                     CROPDMGEXP == "B" ~ 10^9,
                                     CROPDMGEXP %in% c("0", "") & CROPDMG == 0 ~ 0,
                                     !is.na(as.numeric(CROPDMGEXP)) ~ 10^as.numeric(CROPDMGEXP),
                                     TRUE ~ 1),
         prop_total = if_else(PROPDMG > 0,
                                PROPDMG * prop_multiplier,
                                5 * prop_multiplier),
         crop_total = if_else(CROPDMG > 0,
                                CROPDMG * crop_multiplier,
                                5 * crop_multiplier))
## Warning: There were 4 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `prop_multiplier = case_when(...)`.
## Caused by warning:
## ! NAs introduced by coercion
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 3 remaining warnings.

Next, the event list is cleaned up by removing summary data and collapsing similar events into single categories (e.g. “BLIZZARD”, “BLIZZARD/HEAVY SNOW” and “BLIZZARD/HIGH WIND” should all be counted as a single event type).

storms_collapsed <-  storms |> 
  mutate(EVTYPE = tolower(EVTYPE),
         EVTYPE = str_trim(EVTYPE)) |> 
  filter(!str_detect(EVTYPE, "summary|monthly")) |> 
  mutate(event_type = case_when(EVTYPE == "avalance" ~ "avalanche",
                                str_detect(EVTYPE, "blizzard") ~ "blizzard",
                                str_detect(EVTYPE, "coastal flood") ~ "coastal flood",
                                str_detect(EVTYPE, "drought") ~ "drought",
                                str_detect(EVTYPE, "dry") & !str_detect(EVTYPE, "microburst") ~ "dry conditions",
                                str_detect(EVTYPE, "dust") ~ "dust storm",
                                str_detect(EVTYPE, "cold|hypothermia") ~ "cold",
                                str_detect(EVTYPE, "flash flood|flashflood|flash/flood") ~ "flash flood",
                                str_detect(EVTYPE, "flood|fld") ~ "flood",
                                str_detect(EVTYPE, "fog") ~ "fog",
                                str_detect(EVTYPE, "freeze|frost") ~ "freeze",
                                str_detect(EVTYPE, "freezing rain|freezing drizzle") ~ "freezing rain",
                                str_detect(EVTYPE, "funnel") ~ "funnel cloud",
                                str_detect(EVTYPE, "hail") ~ "hail",
                                str_detect(EVTYPE, "heat|hot|high temperature|hyperthermia") ~ "heat",
                                str_detect(EVTYPE, "heavy rain|hvy rain") ~ "heavy rain",
                                str_detect(EVTYPE, "heavy snow") ~ "heavy snow",
                                str_detect(EVTYPE, "heavy surf|high surf") ~ "heavy surf",
                                str_detect(EVTYPE, "high wind") ~ "high wind",
                                str_detect(EVTYPE, "hurricane") ~ "hurricane",
                                str_detect(EVTYPE, "ice") ~ "ice storm",
                                str_detect(EVTYPE, "landslide|landslump") ~ "landslide",
                                str_detect(EVTYPE, "lightning|lighting|ligntning") ~ "lightning",
                                str_detect(EVTYPE, "microburst") ~ "microburst",
                                str_detect(EVTYPE, "mud slide|mudslide") ~ "mud slide",
                                str_detect(EVTYPE, "rain") ~ "rain",
                                str_detect(EVTYPE, "rip current") ~ "rip current",
                                str_detect(EVTYPE, "snow") ~ "snow",
                                str_detect(EVTYPE, "thunderstorm|tstm") ~ "thunderstorm",
                                str_detect(EVTYPE, "tornado") ~ "tornado",
                                str_detect(EVTYPE, "tropical storm") ~ "tropical storm",
                                str_detect(EVTYPE, "waterspout") ~ "waterspout",
                                str_detect(EVTYPE, "wild.*fire|forest fire") ~ "wildfire",
                                str_detect(EVTYPE, "wind chill|windchill") ~ "wind chill",
                                str_detect(EVTYPE, "wind") & !str_detect(EVTYPE, "chill") ~ "wind",
                                str_detect(EVTYPE, "winter mix|wintry mix") ~ "winter mix",
                                str_detect(EVTYPE, "winter weather") ~ "winter weather",
                                str_detect(EVTYPE, "winter storm") ~ "winter storm",
                                TRUE ~ EVTYPE))

This is imperfect, but it should clean up the data enough to make analysis meaningful.

Now a summary dataset will be created. To analyze the types of events that are most harmful to population health, we will look at injuries and fatalities. To analyze the types of events with the greatest economic consequences, we will look at property damage and crop damage.

storm_summary <- storms_collapsed |> 
  group_by(event_type) |> 
  summarize(total_events = n(),
            total_injuries = sum(INJURIES),
            median_injuries = median(INJURIES),
            mean_injuries = mean(INJURIES),
            total_fatalities = sum(FATALITIES),
            median_fatalities = median(FATALITIES),
            mean_fatalities = mean(FATALITIES),
            total_prop = sum(prop_total),
            median_prop = median(prop_total),
            total_crop = sum(crop_total),
            median_crop = median(crop_total)) |> 
  mutate(total_health = total_injuries + total_fatalities,
         total_econ = total_prop + total_crop)

Results

Across the United States, which types of events are most harmful with respect to population health?

There are two measures of population health in the dataset: injuries and fatalities.

The top ten event types that caused the most total fatalities are:

storm_summary |> 
  arrange(desc(total_fatalities)) |> 
  select(event_type, total_events, total_fatalities, median_fatalities, mean_fatalities) |> 
  head(10)
## # A tibble: 10 × 5
##    event_type   total_events total_fatalities median_fatalities mean_fatalities
##    <chr>               <int>            <dbl>             <dbl>           <dbl>
##  1 tornado             60698             5636                 0         0.0929 
##  2 heat                 2653             3133                 0         1.18   
##  3 flash flood         55670             1035                 0         0.0186 
##  4 lightning           15777              817                 0         0.0518 
##  5 thunderstorm       335664              724                 0         0.00216
##  6 rip current           774              572                 1         0.739  
##  7 flood               29609              512                 0         0.0173 
##  8 cold                 2470              459                 0         0.186  
##  9 high wind           21921              297                 0         0.0135 
## 10 avalanche             387              225                 0         0.581

As shown in the table above, tornadoes have caused the most total fatalities, followed by heat (including events with codes such as “excessive heat” and “heat wave”) and flash floods. However, as shown in the median_fatalities column, most of these events still cause no fatalities.

To find the events that cause the most fatalities on average, first I will filter the data to show only events with at least 10 instances recorded in the database (to avoid biasing the data with uncommon or strangely coded events), and then sort by mean fatalities.

storm_summary |> 
  filter(total_events >= 10) |> 
  arrange(desc(mean_fatalities)) |> 
  select(event_type, total_events, total_fatalities, mean_fatalities) |> 
  head(10)
## # A tibble: 10 × 4
##    event_type     total_events total_fatalities mean_fatalities
##    <chr>                 <int>            <dbl>           <dbl>
##  1 tsunami                  20               33           1.65 
##  2 heat                   2653             3133           1.18 
##  3 rip current             774              572           0.739
##  4 avalanche               387              225           0.581
##  5 hurricane               287              133           0.463
##  6 coastal storm            10                3           0.3  
##  7 dry conditions          110               29           0.264
##  8 mixed precip             10                2           0.2  
##  9 cold                   2470              459           0.186
## 10 glaze                    43                7           0.163

Tsunamis, heat, and rip currents cause the most fatalities per event on average.

The top ten event types that caused the most total injuries are:

storm_summary |> 
  arrange(desc(total_injuries)) |> 
  select(event_type, total_events, total_injuries, median_injuries, mean_injuries) |> 
  head(10)
## # A tibble: 10 × 5
##    event_type   total_events total_injuries median_injuries mean_injuries
##    <chr>               <int>          <dbl>           <dbl>         <dbl>
##  1 tornado             60698          91407               0       1.51   
##  2 thunderstorm       335664           9447               0       0.0281 
##  3 heat                 2653           9209               0       3.47   
##  4 flood               29609           6874               0       0.232  
##  5 lightning           15777           5232               0       0.332  
##  6 ice storm            2168           2154               0       0.994  
##  7 flash flood         55670           1802               0       0.0324 
##  8 wildfire             4232           1606               0       0.379  
##  9 high wind           21921           1518               0       0.0692 
## 10 hail               290399           1467               0       0.00505

Tornadoes, thunderstorms, and heat have caused the most total injuries. As with fatalities, most of these events cause no injuries.

The top ten event types that caused the most injuries on average are:

storm_summary |> 
  filter(total_events >= 10) |> 
  arrange(desc(mean_injuries)) |> 
  select(event_type, total_events, total_injuries, mean_injuries) |> 
  head(10)
## # A tibble: 10 × 4
##    event_type   total_events total_injuries mean_injuries
##    <chr>               <int>          <dbl>         <dbl>
##  1 tsunami                20            129         6.45 
##  2 glaze                  43            216         5.02 
##  3 hurricane             287           1328         4.63 
##  4 heat                 2653           9209         3.47 
##  5 mixed precip           10             26         2.6  
##  6 tornado             60698          91407         1.51 
##  7 ice storm            2168           2154         0.994
##  8 icy roads              32             31         0.969
##  9 dust storm            589            483         0.820
## 10 winter mix             97             77         0.794

The events causing the most injuries per event on average are tsunamis, glaze (meaning icy roads), and hurricanes.

Next, injuries and fatalities are combined to find the top ten event types with the greatest overall effect on population health.

health_longer <- storm_summary |> 
  arrange(total_health) |> 
  mutate(event_type = factor(event_type, levels = event_type)) |> 
  tail(10) |> 
  rename(injuries = total_injuries,
         fatalities = total_fatalities) |> 
  select(event_type, total_events, injuries, fatalities, total_health) |> 
  pivot_longer(cols = c(injuries, fatalities), names_to = "type", values_to = "count")

health_longer |> 
  ggplot(aes(x = event_type, y = count, fill = type)) +
  geom_col() +
  facet_wrap(~ type, scales = "free") +
  coord_flip() +
  labs(x = "Event type",
       y = "Number of injuries or fatalities",
       title = "Severe weather events with the greatest effects on population health") +
  guides(fill = "none") +
  theme_bw()

This figure shows the ten event types with the greatest effects on population health (total injuries and fatalities). Note the different x-axes in the two graphs; injuries are much more common than fatalities. Tornadoes cause the most injuries and fatalities. Hot weather is the second most hazardous, and causes relatively more fatalities. Flash floods are also notable for causing a relatively large number of fatalities compared to the number of injuries.

Across the United States, which types of events have the greatest economic consequences?

Because most of the economic damage estimates are highly inexact, means or medians have minimal value for this analysis. Only totals are shown.

The top ten event types that caused the most property damage are:

storm_summary |> 
  arrange(desc(total_prop)) |> 
  select(event_type, total_events, total_prop, median_prop) |> 
  head(10)
## # A tibble: 10 × 4
##    event_type     total_events    total_prop median_prop
##    <chr>                 <int>         <dbl>       <dbl>
##  1 flood                 29609 150333362329         5000
##  2 hurricane               287  84656210010      1000000
##  3 tornado               60698  57127328126.        5000
##  4 storm surge             261  43323546000        37500
##  5 hail                 290399  18522258702.           0
##  6 flash flood           55670  17650842206.        5000
##  7 thunderstorm         335664  11378644441.           0
##  8 wildfire               4232   8502793500         5000
##  9 tropical storm          697   7715235550         5000
## 10 winter storm          11436   6724622251         5000

Floods, hurricanes, and tornadoes caused the most property damage.

The top ten event types that caused the most crop damage are:

storm_summary |> 
  arrange(desc(total_crop)) |> 
  select(event_type, total_events, total_crop, median_crop)
## # A tibble: 171 × 4
##    event_type   total_events  total_crop median_crop
##    <chr>               <int>       <dbl>       <dbl>
##  1 drought              2512 23978951780        5000
##  2 flood               29609 10941019050           0
##  3 hurricane             287  5505402800           0
##  4 ice storm            2168  5026799300           0
##  5 hail               290399  3485047873           0
##  6 freeze               1503  2021696000        5000
##  7 thunderstorm       335664  1793929258           0
##  8 flash flood         55670  1699962165           0
##  9 cold                 2470  1423375550        5000
## 10 heat                 2653   911073500        5000
## # ℹ 161 more rows
  head(10)
## [1] 10

Droughts, floods, and hurricanes caused the most crop damage.

Next, propery and crop damage are combined to find the top ten event types with the greatest overall economic effect.

econ_longer <- storm_summary |> 
  arrange(total_econ) |> 
  mutate(event_type = factor(event_type, levels = event_type)) |> 
  tail(10) |> 
  rename(property = total_prop,
         crop = total_crop) |> 
  select(event_type, total_events, property, crop, total_econ) |> 
  pivot_longer(cols = c(property, crop), names_to = "type", values_to = "value")

econ_longer |> 
  ggplot(aes(x = event_type, y = value/10^9, fill = type)) +
  geom_col() +
  facet_wrap(~ type) +
  coord_flip() +
  labs(x = "Event type",
       y = "Cost (billions of dollars)",
       title = "Severe weather events with the greatest economic effects") +
  guides(fill = "none") +
  theme_bw()

This figure shows the ten event types with the greatest economic consequences (total crop and property damage). Floods and hurricanes cause the most overall damage, primarily property damage. Droughts cause comparatively little property damage, but are the greatest source of crop damage.