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