The firearm suicide epidemic has been growing, with the firearm suicide rate increasing 12.5% over the last decade (2010-2019). While females are more likely than males to attempt suicide, males are four times more likely to die by suicide. Across all demographics, males have higher rates of firearm suicide and suicide overall. This is primarily due to the fact that males are more likely to use a more lethal suicide attempt method, such as firearms. Suicide attempts among males are eight times more likely to involve firearms than attempts among females. Firearm suicide rates vary substantially across the country. Suicide rates (both overall and by firearm) are generally higher in places where household firearm ownership is more common. In 2019, New Jersey had the lowest firearm suicide rate, while Wyoming had the highest. I am very interested in answering the following questions:
To answer these question, I combined two separate data sources. To obtain the median household income and poverty rates, I used a US Census API for all years for which firearms-related suicide data are available. For firearm-related suicide and ownership data, I used the database compiled by the Rand Corp. that includes those data by state for the years 1981 – 2002.
The motivation behind this project is one of a personal nature for me, as a good friend in our circle was having mental health issues and ended up taking his own life with a firearm. In order to extend what was learned in class, I used ggmap as my new tool to show suicide rates across the entirety of the United States. I then combined this with other visualizations to address the questions I set forth to answer.
Load the requisite libraries:
library(jsonlite)
library(readxl)
library(ggplot2)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.1 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ lubridate 1.9.2 ✔ tibble 3.2.1
## ✔ purrr 1.0.1 ✔ tidyr 1.3.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ purrr::flatten() masks jsonlite::flatten()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(ggmap)
## ℹ Google's Terms of Service: <https://mapsplatform.google.com>
## ℹ Please cite ggmap if you use it! Use `citation("ggmap")` for details.
library(viridis)
## Loading required package: viridisLite
library(forcats)
Import the Rand Corp. gun-related suicide rate data from an excel file:
suicide = read_excel("TL-354-State-Level Estimates of Household Firearm Ownership.xlsx", sheet = 2)
head(suicide)
## # A tibble: 6 × 20
## FIP Year STATE HFR HFR_se universl permit Fem_FS_S Male_FS_S BRFSS GALLUP
## <dbl> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 1980 Alab… 0.608 0.031 0 0 0.824 0.834 -9 0.554
## 2 1 1981 Alab… 0.597 0.047 0 0 0.692 0.831 -9 -9
## 3 1 1982 Alab… 0.661 0.036 0 0 0.772 0.821 -9 -9
## 4 1 1983 Alab… 0.586 0.038 0 0 0.688 0.819 -9 0.611
## 5 1 1984 Alab… 0.624 0.036 0 0 0.71 0.776 -9 -9
## 6 1 1985 Alab… 0.644 0.031 0 0 0.756 0.835 -9 0.612
## # ℹ 9 more variables: GSS <dbl>, PEW <dbl>, HuntLic <dbl>, GunsAmmo <dbl>,
## # BackChk <dbl>, PewQChng <dbl>, BS1 <dbl>, BS2 <dbl>, BS3 <dbl>
dim(suicide)
## [1] 1850 20
str(suicide)
## tibble [1,850 × 20] (S3: tbl_df/tbl/data.frame)
## $ FIP : num [1:1850] 1 1 1 1 1 1 1 1 1 1 ...
## $ Year : num [1:1850] 1980 1981 1982 1983 1984 ...
## $ STATE : chr [1:1850] "Alabama" "Alabama" "Alabama" "Alabama" ...
## $ HFR : num [1:1850] 0.608 0.597 0.661 0.586 0.624 0.644 0.567 0.609 0.606 0.627 ...
## $ HFR_se : num [1:1850] 0.031 0.047 0.036 0.038 0.036 0.031 0.038 0.036 0.031 0.031 ...
## $ universl : num [1:1850] 0 0 0 0 0 0 0 0 0 0 ...
## $ permit : num [1:1850] 0 0 0 0 0 0 0 0 0 0 ...
## $ Fem_FS_S : num [1:1850] 0.824 0.692 0.772 0.688 0.71 ...
## $ Male_FS_S: num [1:1850] 0.834 0.831 0.821 0.819 0.776 ...
## $ BRFSS : num [1:1850] -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 ...
## $ GALLUP : num [1:1850] 0.554 -9 -9 0.611 -9 ...
## $ GSS : num [1:1850] 0.584 -9 0.655 -9 0.627 ...
## $ PEW : num [1:1850] -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 ...
## $ HuntLic : num [1:1850] 0.291 0.295 0.291 0.285 0.282 ...
## $ GunsAmmo : num [1:1850] -0.509 -0.619 -0.527 -0.713 -0.733 ...
## $ BackChk : num [1:1850] -9 -9 -9 -9 -9 -9 -9 -9 -9 -9 ...
## $ PewQChng : num [1:1850] 0 0 0 0 0 0 0 0 0 0 ...
## $ BS1 : num [1:1850] 0 1 2 3 4 5 6 7 7.91 8.73 ...
## $ BS2 : num [1:1850] 0 0 0 0 0 0 0 0 0.09 0.27 ...
## $ BS3 : num [1:1850] 0 0 0 0 0 0 0 0 0 0 ...
I chose to use a US Census API that contained state-wide data on median household income and poverty rates, by year. To access the API, I had to register for a key with the US Census Bureau. I also wrote a for loop to iterate over all of the available years (1995 - 2016) to import and collate those data into a single dataframe that I could later join with the gun-related suicide data. Note: Census data only available from 1995 forward.
years = (unique(suicide$Year))
years = years[years > 1994]
years = as.character(years)
header <- c("Median_Household_Income", "All_Ages_Poverty_Count", "All_Ages_Poverty_Rate", "All_Ages_Poverty_Universe", "State_Name", "State_Abbr", "Year", "State_FIPS")
census_all = data.frame(matrix(ncol = length(header), nrow = 0))
for (y in 1:length(years)) {
year <- years[y]
print(year)
key <- "44427d638aa029da61ae1cce5abe89e33be89f8e"
get <- "SAEMHI_PT&&SAEPOVALL_PT&SAEPOVRTALL_PT&SAEPOVU_ALL&NAME&STABREV"
for.statemt <- "state:*&time="
# url <- "https://api.census.gov/data/timeseries/poverty/saipe?get=SAEMHI_PT&&SAEPOVALL_PT&NAME&for=state:*&time=2018"
base.url <- "https://api.census.gov/data/timeseries/poverty/saipe"
url <- paste(base.url, "?get=", get, "&for=", for.statemt, year, sep = "")
key.path <- paste("&key=", key, sep = "")
path <- paste(url, key.path, sep = "")
census <- as.data.frame(fromJSON(path))
census <- census[-1, ]
names(census) <- header
census_all = rbind(census_all, census)
}
## [1] "1995"
## [1] "1996"
## [1] "1997"
## [1] "1998"
## [1] "1999"
## [1] "2000"
## [1] "2001"
## [1] "2002"
## [1] "2003"
## [1] "2004"
## [1] "2005"
## [1] "2006"
## [1] "2007"
## [1] "2008"
## [1] "2009"
## [1] "2010"
## [1] "2011"
## [1] "2012"
## [1] "2013"
## [1] "2014"
## [1] "2015"
## [1] "2016"
## Drop All_Ages_Poverty_Universe since it was an empty column:
census_all <- census_all %>% select(-All_Ages_Poverty_Universe)
## Fix the first 3 columns, which came in as character:
census_all <- census_all %>%
mutate(Median_Household_Income = as.numeric(Median_Household_Income),
All_Ages_Poverty_Count = as.numeric(All_Ages_Poverty_Count),
All_Ages_Poverty_Rate = as.numeric(All_Ages_Poverty_Rate))
head(census_all)
## Median_Household_Income All_Ages_Poverty_Count All_Ages_Poverty_Rate
## 2 27357 752097 17.6
## 3 42255 60735 10.1
## 4 31736 722660 16.3
## 5 26515 455776 18.2
## 6 36767 5215575 16.5
## 7 37235 392938 10.4
## State_Name State_Abbr Year State_FIPS
## 2 Alabama AL 1995 01
## 3 Alaska AK 1995 02
## 4 Arizona AZ 1995 04
## 5 Arkansas AR 1995 05
## 6 California CA 1995 06
## 7 Colorado CO 1995 08
# View(census_all)
# table(census_all$Year)
Next, I merged the suicide rate data with the census data by year. First, I converted year to character type in the suicide dataframe. I also chose to rename the “State_Name” column that was imported from the Census API to “STATE” to make the join simpler. I performed a right_join on the dataframes because I wanted all of the suicide data retained.
suicide$Year <- as.character(suicide$Year)
census_all <- census_all %>%
rename(STATE = State_Name)
suicide_census <- right_join(suicide, census_all, by = c("Year", "STATE"))
head(suicide_census)
## # A tibble: 6 × 25
## FIP Year STATE HFR HFR_se universl permit Fem_FS_S Male_FS_S BRFSS GALLUP
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 1995 Alab… 0.554 0.047 0 0 0.640 0.786 -9 -9
## 2 1 1996 Alab… 0.568 0.031 0 0 0.699 0.8 -9 0.503
## 3 1 1997 Alab… 0.557 0.029 0 0 0.697 0.782 -9 0.594
## 4 1 1998 Alab… 0.577 0.036 0 0 0.658 0.795 -9 -9
## 5 1 1999 Alab… 0.537 0.036 0 0 0.698 0.802 -9 0.520
## 6 1 2000 Alab… 0.538 0.026 0 0 0.616 0.760 -9 0.576
## # ℹ 14 more variables: GSS <dbl>, PEW <dbl>, HuntLic <dbl>, GunsAmmo <dbl>,
## # BackChk <dbl>, PewQChng <dbl>, BS1 <dbl>, BS2 <dbl>, BS3 <dbl>,
## # Median_Household_Income <dbl>, All_Ages_Poverty_Count <dbl>,
## # All_Ages_Poverty_Rate <dbl>, State_Abbr <chr>, State_FIPS <chr>
suicide_census$ave_sr = rowMeans(suicide_census[,8:9])
These data were downloaded from a publicly available site that gave the center long,lat coordinates for every state in the US.
st_geo = read.csv("state_lat_lon.csv")
This was then joined to the merged suicide-census dataframe to make a complete dataframe with necessary geographic information for mapping.
suicide_census_geo = full_join(suicide_census, st_geo, by = "STATE")
head(suicide_census_geo)
## # A tibble: 6 × 29
## FIP Year STATE HFR HFR_se universl permit Fem_FS_S Male_FS_S BRFSS GALLUP
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 1995 Alab… 0.554 0.047 0 0 0.640 0.786 -9 -9
## 2 1 1996 Alab… 0.568 0.031 0 0 0.699 0.8 -9 0.503
## 3 1 1997 Alab… 0.557 0.029 0 0 0.697 0.782 -9 0.594
## 4 1 1998 Alab… 0.577 0.036 0 0 0.658 0.795 -9 -9
## 5 1 1999 Alab… 0.537 0.036 0 0 0.698 0.802 -9 0.520
## 6 1 2000 Alab… 0.538 0.026 0 0 0.616 0.760 -9 0.576
## # ℹ 18 more variables: GSS <dbl>, PEW <dbl>, HuntLic <dbl>, GunsAmmo <dbl>,
## # BackChk <dbl>, PewQChng <dbl>, BS1 <dbl>, BS2 <dbl>, BS3 <dbl>,
## # Median_Household_Income <dbl>, All_Ages_Poverty_Count <dbl>,
## # All_Ages_Poverty_Rate <dbl>, State_Abbr.x <chr>, State_FIPS <chr>,
## # ave_sr <dbl>, State_Abbr.y <chr>, lat <dbl>, lon <dbl>