The analysis done by The Post for the story The Ring in Ashes can be reproduced using FEMA’s Hazard Mitigation Assistance Projects open data and joined with with FEMA’s Disaster Declarations Summaries data to determine which designated disasters occurred between three time periods
library(tidyverse)
library(tidycensus)
library(lubridate)
library(DT)
library(knitr)
library(viridis)
library(scales)
knitr::opts_chunk$set(warning = FALSE)
knitr::opts_chunk$set(message = FALSE)
knitr::opts_chunk$set(fig.width = 8)
knitr::opts_chunk$set(fig.height = 3)
# load up cleaned up data
mega_df <- readRDS("../../data/clean/mega_df_pt2.RDS") %>%
mutate(declaration_year=year(declarationDate)) %>%
filter(programArea=="HMGP")
Of the $11 billion FEMA has allocated for this program over the past decade, only $1.6 billion has been spent.
# 1. What percent of money is unspent
share1 <- mega_df %>%
#filter(programFy>2010) %>%
mutate(year_declared=year(declarationDate)) %>%
filter(year_declared>2010) %>%
filter(programArea=="HMGP") %>%
group_by(status) %>%
summarize(amount=sum(projectAmount, na.rm=T)) %>%
mutate(percent_money=round(amount/sum(amount, na.rm=T)*100,1))
kable(share1, format.args = list(big.mark = ","))
status | amount | percent_money |
---|---|---|
Approved | 9,393,000,822 | 85.5 |
Closed | 1,597,847,125 | 14.5 |
How long counties wait on average to complete their FEMA-funded resilience projects.
Projects that closed in 2020 took an average of 7 years to get funded and completed, one year longer than it took a decade ago.
This is counting from a declared disaster dates to dates projects closed by year of closure.
mega_df %>%
mutate(year_closed=year(dateClosed)) %>%
mutate(disaster_closed_interval=interval(declarationDate, dateClosed)) %>%
mutate(months_disaster_closed=disaster_closed_interval %/% months(1)) %>%
mutate(months_disaster_closed=case_when(
months_disaster_closed < 0 ~ 0,
TRUE ~ months_disaster_closed
)) %>%
filter(year_closed>2010 & year_closed < 2021) %>%
group_by(year_closed) %>%
#filter(initially_approved_year>2010) %>%
summarize(total=n(),
months_disaster_closed=round(mean(months_disaster_closed, na.rm=T),1)) %>%
mutate(years=months_disaster_closed/12) %>%
filter(year_closed>2010) %>%
ggplot(aes(x=year_closed, y=years)) +
geom_bar(position="stack", stat="identity") +
#facet_wrap(~still_open) +
scale_y_continuous(labels = scales::comma) +
labs(title="Years it took for projects to close",
subtitle="By project close year",
caption="Data: FEMA",
y="Years",
x="") +
theme_minimal()
It takes nearly two years for projects in rural counties to get approved.
# import county census data (poverty, urban, race)
county_data <- read_csv("../../data/clean/county_combined.csv") %>%
mutate(pov_quantile= ntile(pctpov, 4)) %>%
mutate(pop_quantile=ntile(poverty_population, 4))
# import county names
county_names <- read_csv("../../data/clean/county_names.csv")
county_data <- county_data %>% left_join(county_names)
mega_df %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
left_join(county_data, by="GEOID") %>%
mutate(ur=case_when(
(urban_rural > 0 & urban_rural <= 2) ~ "1. Urban",
(urban_rural > 2 & urban_rural <= 4) ~ "2. Suburban",
(urban_rural > 4 & urban_rural <= 6) ~ "3. Rural",
TRUE ~ "4. Unclassified"
)) %>%
mutate(initially_approved_year=year(approval_date)) %>%
mutate(initially_declared_approved_interval=interval(declarationDate, approval_date)) %>%
mutate(months_declared_approved=initially_declared_approved_interval %/% months(1)) %>%
filter(initially_approved_year>2010) %>%
group_by(ur) %>%
summarize(total=n(),
costs=sum(projectAmount, na.rm=T),
months_declared_approved=round(mean(months_declared_approved, na.rm=T),1)) %>%
filter(ur=="3. Rural") %>%
kable()
ur | total | costs | months_declared_approved |
---|---|---|---|
3. Rural | 3766 | 2116359580 | 22.4 |
How long it takes counties to close out projects by poverty percentile.
# poor communities
mega_df %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
mutate(year_closed=year(dateClosed)) %>%
#mutate(disaster_closed_interval=interval(declarationDate, approval_date)) %>%
mutate(disaster_closed_interval=interval(declarationDate, dateClosed)) %>%
mutate(months_disaster_closed=disaster_closed_interval %/% months(1)) %>%
left_join(county_data, by="GEOID") %>%
#filter(year(approval_date)>2010) %>%
filter(year_closed>2010) %>%
group_by(pov_quantile) %>%
summarize(total=n(),
costs=sum(projectAmount, na.rm=T),
months_declared_closed=round(mean(months_disaster_closed, na.rm=T),1)) %>%
filter(!is.na(pov_quantile)) %>%
kable()
pov_quantile | total | costs | months_declared_closed |
---|---|---|---|
1 | 2294 | 1200396874 | 65.2 |
2 | 1999 | 1354363394 | 70.9 |
3 | 2476 | 1953018115 | 79.5 |
4 | 1715 | 737964092 | 73.0 |
How long it takes to close out projects in counties where majority of the population is either white or non-white.
# white or non-white
mega_df %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
mutate(year_closed=year(dateClosed)) %>%
mutate(disaster_closed_interval=interval(declarationDate, approval_date)) %>%
#mutate(disaster_closed_interval=interval(declarationDate, dateClosed)) %>%
mutate(months_disaster_closed=disaster_closed_interval %/% months(1)) %>%
select(-majority) %>%
left_join(county_data, by="GEOID") %>%
filter(year(approval_date)>2010) %>%
# filter(year_closed>2010) %>%
group_by(majority) %>%
summarize(total=n(),
costs=sum(projectAmount, na.rm=T),
months_declared_closed=round(mean(months_disaster_closed, na.rm=T),1)) %>%
filter(!is.na(majority)) %>%
kable()
majority | total | costs | months_declared_closed |
---|---|---|---|
Non-White | 1580 | 4504105055 | 27.5 |
White | 7835 | 6834382034 | 24.2 |
Counties with at least one project that took longer than 10 years to close out where majority of the population is either white or non-white.
tenplus <- mega_df %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
mutate(year_closed=year(dateClosed)) %>%
#mutate(disaster_closed_interval=interval(declarationDate, dateClosed)) %>%
mutate(disaster_closed_interval=interval(declarationDate, approval_date)) %>%
mutate(months_disaster_closed=disaster_closed_interval %/% months(1)) %>%
select(-majority) %>%
left_join(county_data, by="GEOID") %>%
filter(months_disaster_closed>120) %>%
mutate(year_approved=year(approval_date)) %>%
filter(year_approved>2010)
#filter(year_closed>2010)
# Counties with at least one project that took longer than 10 years to close out
tenplus %>%
count(GEOID) %>%
mutate(project=1) %>%
right_join(county_data, by="GEOID") %>%
group_by(majority) %>%
summarize(total=n(),
counties=sum(project, na.rm=T)) %>%
ungroup() %>%
mutate(percent_of_counties=round(counties/total*100,1)) %>%
kable()
majority | total | counties | percent_of_counties |
---|---|---|---|
Non-White | 462 | 5 | 1.1 |
White | 2758 | 11 | 0.4 |
Counties with projects that took longer than 10 years to close out in counties by poverty quantiles.
tenplus <- mega_df %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
mutate(year_closed=year(dateClosed)) %>%
mutate(disaster_closed_interval=interval(declarationDate, dateClosed)) %>%
mutate(months_disaster_closed=disaster_closed_interval %/% months(1)) %>%
select(-majority) %>%
left_join(county_data, by="GEOID") %>%
filter(months_disaster_closed>120) %>%
filter(year_closed>2010)
tenplus %>%
mutate(project=1) %>%
group_by(GEOID) %>%
summarize(projects=sum(project, na.rm=T)) %>%
right_join(county_data, by="GEOID") %>%
group_by(pov_quantile) %>%
summarize(total=n(),
counties=sum(projects, na.rm=T)) %>%
filter(!is.na(pov_quantile)) %>%
kable()
pov_quantile | total | counties |
---|---|---|
1 | 805 | 73 |
2 | 805 | 136 |
3 | 805 | 349 |
4 | 805 | 158 |
Average number of disasters affecting counties while waiting for relevant hazard mitigation projects.
project_types <- read_csv("../../data/raw/project_types.csv")
mega_df <- mega_df %>%
left_join(project_types)
mega_df <- mega_df %>%
mutate(incident_count=str_count(disaster_wide_type, incidentType))
mega_df %>%
filter(subappType!="Management Costs") %>%
filter(subappType!="Planning") %>%
filter(programFy>2010) %>%
group_by(incidentType) %>%
summarize(average_disaster_count=round(mean(incident_count, na.rm=T),1)) %>%
arrange(-average_disaster_count) %>%
head(3) %>%
kable()
incidentType | average_disaster_count |
---|---|
Typhoon | 3.2 |
Fire | 2.9 |
Hurricane | 2.2 |
#Hurricane
hurricanes <-
mega_df %>%
filter(subappType!="Management Costs") %>%
filter(subappType!="Planning") %>%
filter(programFy>2010) %>% filter(incidentType=="Hurricane")
stc <- mega_df %>%
filter(year(approval_date)>2010) %>%
filter(county=="St. Charles")
#Fire
#Severe Ice Storm
ice <-
mega_df %>%
filter(subappType!="Management Costs") %>%
filter(subappType!="Planning") %>%
filter(programFy>2010) %>% filter(incidentType=="Severe Ice Storm")
# too many are still open
#Flood
Flood <-
mega_df %>%
filter(subappType!="Management Costs") %>%
filter(subappType!="Planning") %>%
filter(programFy>2010) %>% filter(incidentType=="Flood")
#Tornado
tornados <-
mega_df %>%
filter(subappType!="Management Costs") %>%
filter(subappType!="Planning") %>%
filter(programFy>2010) %>% filter(incidentType=="Tornado")
typh<-
mega_df %>%
filter(subappType!="Management Costs") %>%
filter(subappType!="Planning") %>%
filter(programFy>2010) %>% filter(incidentType=="Typhoon")
Disasters compared to projects by county type.
disasters <- read_csv("../../data/raw/DisasterDeclarationsSummaries090321.csv") %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode))
# import county census data (poverty, urban, race)
county_data <- read_csv("../../data/clean/county_combined.csv") %>%
mutate(pov_quantile= ntile(pctpov, 4)) %>%
mutate(pop_quantile= ntile(poverty_population,4))
# import county names (whoops)
county_names <- read_csv("../../data/clean/county_names.csv")
county_data <- county_data %>% left_join(county_names)
county_disaster_list <- disasters %>%
ungroup() %>%
select(-placeCode, -designatedArea, -hash, -id) %>%
unique() %>%
mutate(declaration_year=year(declarationDate)) %>%
filter(declaration_year>2010)
write_csv(county_disaster_list, "../../data/clean/county_disaster_list_dupe.csv", na="")
county_disaster_list <- read_csv("../../data/clean/county_disaster_list_dupe.csv") %>%
unique()
county_disaster_count <- county_disaster_list %>%
count(GEOID, name="disasters") %>%
full_join(county_data) %>%
mutate(ur=case_when(
(urban_rural > 0 & urban_rural <= 2) ~ "1. Urban",
(urban_rural > 2 & urban_rural <= 4) ~ "2. Suburban",
(urban_rural > 4 & urban_rural <= 6) ~ "3. Rural",
TRUE ~ "4. Unclassified"
)) %>%
filter(!is.na(NAME))
county_projects_count <- mega_df %>%
filter(programArea=="HMGP") %>%
filter(year(declarationDate)>2010) %>%
# filter(is.na(dateClosed) | year(dateClosed)>2010) %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
count(GEOID, name="projects")
county_projects_disasters <- full_join(county_disaster_count, county_projects_count) %>%
filter(!is.na(NAME))
ggplot(county_projects_disasters, aes(x=disasters, y=projects, color=ur)) +
geom_point()+
#geom_smooth(method='lm', formula= y~x, se=FALSE) +
geom_abline(intercept=0, slope=1) +
geom_smooth(method=lm) +
labs(title="Number of projects versus disasters by county type") +
theme_minimal()
Urban counties are twice as likely on average to receive funding after a disaster than rural areas.
county_projects_disasters %>%
mutate(projects2=case_when(
is.na(projects) ~ 0,
TRUE ~ as.numeric(projects)
),
disasters2=case_when(
is.na(disasters) ~ 0,
TRUE ~ as.numeric(disasters)
)) %>%
mutate(ratio=projects2/disasters2) %>%
group_by(ur) %>%
summarize(average_ratio = mean(ratio, na.rm=T)) %>%
kable()
ur | average_ratio |
---|---|
1. Urban | 0.5252977 |
2. Suburban | 0.4593427 |
3. Rural | 0.2310508 |
4. Unclassified | 0.0703265 |
Half of all rural counties in the U.S. experienced a disaster over the past 10 years, yet didn’t have a single mitigation project.
disasters_counties <- read_csv("../../data/raw/DisasterDeclarationsSummaries090321.csv") %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
filter(incidentType=="Biological") %>%
filter(year(declarationDate)>2010) %>%
select(GEOID) %>%
unique()
counties_only <- mega_df %>%
filter(year(declarationDate)>2010) %>%
select(GEOID) %>%
unique() %>%
left_join(county_data, by="GEOID") %>%
mutate(ur=case_when(
(urban_rural > 0 & urban_rural <= 2) ~ "1. Urban",
(urban_rural > 2 & urban_rural <= 4) ~ "2. Suburban",
(urban_rural > 4 & urban_rural <= 6) ~ "3. Rural",
TRUE ~ "4. Unclassified"
)) %>%
count(ur, name="counties_with_projects")
no_mitigation <- readRDS("../../data/clean/no_mitigation.RDS")
county_data_none <- county_data %>%
mutate(pov_quantile= ntile(pctpov, 4)) %>%
filter(GEOID %in% no_mitigation)
total_ur <- county_data %>%
count(urban_rural, name="total_counties")
#
# county_data_none %>%
# count(urban_rural) %>%
# left_join(total_ur) %>%
# mutate(percent=round(n/total_counties*100,1)) %>%
# rename(counties_with_no_projects=n,
# counties=total_counties) %>%
# filter(!is.na(urban_rural)) %>%
# kable()
county_data_none <- county_data %>%
mutate(pov_quantile= ntile(pctpov, 4)) %>%
filter(GEOID %in% no_mitigation)
total_ur <- county_data %>%
count(urban_rural, name="total_counties")
county_data_none %>%
count(urban_rural) %>%
left_join(total_ur) %>%
mutate(ur=case_when(
(urban_rural > 0 & urban_rural <= 2) ~ "1. Urban",
(urban_rural > 2 & urban_rural <= 4) ~ "2. Suburban",
(urban_rural > 4 & urban_rural <= 6) ~ "3. Rural",
TRUE ~ "4. Unclassified"
)) %>%
group_by(ur) %>%
summarize(total_counties=sum(total_counties),
n=sum(n)) %>%
left_join(counties_only) %>%
filter(ur!="4. Unclassified") %>%
mutate(percent=round(n/total_counties*100,1)) %>%
rename(type=ur,
`total counties`=total_counties,
`qualified counties with no projects`=n,
`counties with projects`=counties_with_projects,
`percent counties with no projects`=percent) %>%
kable()
type | total counties | qualified counties with no projects | counties with projects | percent counties with no projects |
---|---|---|---|---|
1. Urban | 436 | 155 | 281 | 35.6 |
2. Suburban | 730 | 228 | 502 | 31.2 |
3. Rural | 1976 | 908 | 1067 | 46.0 |
Southern states wait longer.
states <- read_csv("../../data/raw/states.csv")
mega_df %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
mutate(year_closed=year(dateClosed)) %>%
mutate(disaster_closed_interval=interval(declarationDate, dateClosed)) %>%
mutate(months_disaster_closed=disaster_closed_interval %/% months(1)) %>%
filter(year(dateClosed)>2010) %>%
left_join(states, by=c("fipsStateCode"="st_fips")) %>%
group_by(region.y) %>%
summarize(total=n(),
costs=sum(projectAmount, na.rm=T),
months_declared_closed=round(mean(months_disaster_closed, na.rm=T),1)) %>%
arrange(-months_declared_closed) %>%
filter(!is.na(region.y)) %>%
kable()
region.y | total | costs | months_declared_closed |
---|---|---|---|
South | 4529 | 2986186893 | 80.9 |
Northeast | 1431 | 902396328 | 74.4 |
West | 888 | 520122488 | 73.3 |
Midwest | 2415 | 1438674982 | 58.1 |
Specifically West South Central, which consists of Arkansas, Louisiana, Oklahoma, and Texas.
mega_df %>%
mutate(fipsStateCode=case_when(
nchar(stateNumberCode)==1 ~ paste0("0", stateNumberCode),
TRUE ~ as.character(stateNumberCode)
)) %>%
mutate(fipsCountyCode=case_when(
nchar(countyCode)==1 ~ paste0("00", countyCode),
nchar(countyCode)==2 ~ paste0("0", countyCode),
is.na(countyCode) ~ "000",
TRUE ~ as.character(countyCode)
)) %>%
mutate(GEOID=paste0(fipsStateCode, fipsCountyCode)) %>%
mutate(year_closed=year(dateClosed)) %>%
mutate(disaster_closed_interval=interval(declarationDate, dateClosed)) %>%
mutate(months_disaster_closed=disaster_closed_interval %/% months(1)) %>%
filter(year(dateClosed)>2010) %>%
left_join(states, by=c("fipsStateCode"="st_fips")) %>%
group_by(division) %>%
summarize(total=n(),
costs=sum(projectAmount, na.rm=T),
months_declared_closed=round(mean(months_disaster_closed, na.rm=T),1)) %>%
arrange(-months_declared_closed) %>%
filter(!is.na(division)) %>%
kable()
division | total | costs | months_declared_closed |
---|---|---|---|
West South Central | 1643 | 1370051448 | 97.8 |
Middle Atlantic | 865 | 783599758 | 77.6 |
Pacific | 546 | 375097146 | 76.0 |
East North Central | 470 | 249205028 | 75.8 |
East South Central | 1506 | 629269697 | 74.4 |
New England | 566 | 118796570 | 69.6 |
Mountain | 342 | 145025342 | 69.1 |
South Atlantic | 1380 | 986865747 | 68.0 |
West North Central | 1945 | 1189469954 | 53.8 |