Introduction:

During the midst of the COVID-19 pandemic, Buffalo, New York, experienced a surge in violent crime. According to Byron Brown, who was the mayor at the time, the pandemic interrupted violence prevention programs creating a spike in homicides. In attempt to address the violence, the Buffalo Police Department focused on specific locations tied to shootings (Plants, 2021).

The research documented in this paper focuses on Buffalo-based homicides which occurred between 1 January 2019 and 31 December 2022. The research identified several neighborhoods which experienced a higher volume of homicides, compared to other neighborhoods within Buffalo, New York.

Load Packages

library(tidyverse)
library(janitor)
library(here)
library(skimr)
library(ggbeeswarm)
library(lubridate)
library(RColorBrewer)
library(leaflet)
library(sf)
library(USA.state.boundaries)

Read in Data

The original data was obtained from the Buffalo Police Department via PENDATA Buffalo, an online open data portal.

crime <- read_csv(here("data", "buffalocrime.csv"))

Data Preparation:

Homicides from 2019 - 2021

Before conducting any analysis and plotting crime data, data processing was performed for easy manipulation. In this stage, the dataset was cleaned using the tidyverse and janitor libraries then separated into three categories (Day, Month, and Year). In order to review the information pertaining to homicides which occurred during the COVID-19 Pandemic, the data was limited to incidents which took place between 2019 and 2021.

cleancrime3 <- crime %>%
  clean_names() %>% #tidying data
  rename(incident_category = parent_incident_type) %>% #rename for better understanding
  separate(incident_datetime, c("day", "month", "year"), remove = FALSE) %>% #separate to filter by year
  filter(incident_category == "Homicide") %>% #limit data to homicides
  filter(year >= 2019 & year <= 2021) %>% #limit data to incidents between 2019 & 2021
  group_by(neighborhood)%>% #group by neighborhood
  mutate(year = ifelse(is.na(year), 0, year)) %>%   # Setting NA values to 0
  mutate(longitude = ifelse(is.na(longitude), 0, longitude)) %>%   # Setting NA values to 0
  mutate(latitude = ifelse(is.na(latitude), 0, latitude)) %>%   # Setting NA values to 0
  st_as_sf(coords = c("longitude", "latitude"), crs = 4326)

Below is a glimpse of data, after it was cleaned.

glimpse(cleancrime3) 
## Rows: 187
## Columns: 31
## Groups: neighborhood [35]
## $ case_number              <chr> "19-2721048", "19-0460331", "19-0820934", "19…
## $ incident_datetime        <chr> "09/29/2019 12:00:00 AM", "02/15/2019 11:54:0…
## $ day                      <chr> "09", "02", "03", "08", "06", "08", "02", "07…
## $ month                    <chr> "29", "15", "23", "16", "13", "15", "06", "30…
## $ year                     <chr> "2019", "2019", "2019", "2019", "2019", "2019…
## $ incident_id              <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ incident_type_primary    <chr> "MURDER", "MURDER", "MURDER", "MURDER", "MURD…
## $ incident_description     <chr> "Buffalo Police are investigating this report…
## $ incident_category        <chr> "Homicide", "Homicide", "Homicide", "Homicide…
## $ hour_of_day              <dbl> 0, 11, 22, 10, 20, 0, 2, 1, 0, 23, 17, 0, 0, …
## $ day_of_week              <chr> "Sunday", "Friday", "Saturday", "Friday", "Th…
## $ address                  <chr> "1 Block INTER PARK AV", "400 Block GRIDER ST…
## $ city                     <chr> "Buffalo", "Buffalo", "Buffalo", "Buffalo", "…
## $ state                    <chr> "NY", "NY", "NY", "NY", "NY", "NY", "NY", "NY…
## $ location                 <chr> "POINT (-78.84 42.915)", "POINT (-78.829 42.9…
## $ created_at               <chr> "09/30/2019 07:15:00 AM", "02/15/2019 06:00:0…
## $ updated_at               <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ x2010_census_tract       <chr> "34", "34", "38", "168", "41", "69.02", "165"…
## $ x2010_census_block_group <chr> "3", "5", "3", "3", "3", "1", "1", "1", "4", …
## $ x2010_census_block       <chr> "3007", "5019", "3002", "3013", "3000", "1000…
## $ census_tract             <chr> "34", "34", "38", "168.02", "41", "69.03", "1…
## $ census_block             <chr> "3006", "5017", "3002", "1014", "3000", "1000…
## $ census_block_group       <chr> "3", "5", "3", "1", "3", "1", "1", "1", "3", …
## $ neighborhood             <chr> "Delavan Grider", "Delavan Grider", "Schiller…
## $ police_district          <chr> "District E", "District E", "District C", "Di…
## $ council_district         <chr> "MASTEN", "MASTEN", "LOVEJOY", "MASTEN", "UNI…
## $ tractce20                <chr> "003400", "003400", "003800", "016802", "0041…
## $ geoid20_tract            <chr> "36029003400", "36029003400", "36029003800", …
## $ geoid20_blockgroup       <chr> "360290001103", "360290007005", "360290001103…
## $ geoid20_block            <chr> "360290163003006", "360290034005017", "360290…
## $ geometry                 <POINT [°]> POINT (-78.84 42.915), POINT (-78.829 4…

To help breakdown the data into three different maps, based on the year, i was required to filter the data first. Below are three sections (2019 - 2021) preparing the data based on the year. ### 2019 Homicides

cleancrime2019 <- crime %>%
  clean_names() %>% #tidying data
  rename(incident_category = parent_incident_type) %>% #rename for better understanding
  separate(incident_datetime, c("day", "month", "year"), remove = FALSE) %>% #separate to filter by year
  filter(incident_category == "Homicide") %>% #limit data to homicides
  filter(year == 2019) %>% #limit data to incidents  in 2019
  group_by(neighborhood)%>% #group by neighborhood
  mutate(year = ifelse(is.na(year), 0, year)) %>%   # Setting NA values to 0
  mutate(longitude = ifelse(is.na(longitude), 0, longitude)) %>%   # Setting NA values to 0
  mutate(latitude = ifelse(is.na(latitude), 0, latitude)) %>%   # Setting NA values to 0
  st_as_sf(coords = c("longitude", "latitude"), crs = 4326)

2020 Homicides

cleancrime2020 <- crime %>%
  clean_names() %>% #tidying data
  rename(incident_category = parent_incident_type) %>% #rename for better understanding
  separate(incident_datetime, c("day", "month", "year"), remove = FALSE) %>% #separate to filter by year
  filter(incident_category == "Homicide") %>% #limit data to homicides
  filter(year == 2020) %>% #limit data to incidents  in 2020
  group_by(neighborhood)%>% #group by neighborhood
  mutate(year = ifelse(is.na(year), 0, year)) %>%   # Setting NA values to 0
  mutate(longitude = ifelse(is.na(longitude), 0, longitude)) %>%   # Setting NA values to 0
  mutate(latitude = ifelse(is.na(latitude), 0, latitude)) %>%   # Setting NA values to 0
  st_as_sf(coords = c("longitude", "latitude"), crs = 4326)

2021 Homicides

cleancrime2021 <- crime %>%
  clean_names() %>% #tidying data
  rename(incident_category = parent_incident_type) %>% #rename for better understanding
  separate(incident_datetime, c("day", "month", "year"), remove = FALSE) %>% #separate to filter by year
  filter(incident_category == "Homicide") %>% #limit data to homicides
  filter(year == 2021) %>% #limit data to incidents  in 2021
  group_by(neighborhood)%>% #group by neighborhood
  mutate(year = ifelse(is.na(year), 0, year)) %>%   # Setting NA values to 0
  mutate(longitude = ifelse(is.na(longitude), 0, longitude)) %>%   # Setting NA values to 0
  mutate(latitude = ifelse(is.na(latitude), 0, latitude)) %>%   # Setting NA values to 0
  st_as_sf(coords = c("longitude", "latitude"), crs = 4326)

Map of Homicides with Baffalo, New York (2019 - 2021)

Map the homicides which occurred within Buffalo, New York, between 2019 and 2021.

# Create a palette that map the homicides by year 
pal <- colorFactor(c("darkgreen", "navy", "red"), domain = c("2019", "2020", "2021")) 

# Map Homicide Data for 2019 - 2021
leaflet() %>% 
  setView(lng=-78.84 , lat=42.915, zoom = 12.45) %>% 
  addProviderTiles(providers$CartoDB)%>% #apply CartoDB map
  addMiniMap(position = "topright")%>% # add map of the general area, place in top right corner
  addCircleMarkers(data = cleancrime3, #add homicide markers
                   label = ~case_number, #label with the case number for quick reference
                   color = ~pal(year), #color by year
                   fillOpacity = .5, 
                   stroke = FALSE, 
                   popup = ~address)%>% #add popup to include the address 
  addLegend(title = "Years", #add legend titled years 
            pal = pal, # associate color to years and title years
            value =cleancrime3$year, # use $year to only pull 2019-2021 years
            position = "bottomright") #place in the bottom right corner

Cluster Maps Broken Down by the Year

To help visualize the number of crimes for each year as well as the locations, the homicide data was broken down into three cluster maps (as show below).

2019 - Homicide Cluster Map

Map the homicides which occurred within Buffalo, New York, in 2019.

leaflet() %>% 
  setView(lng=-78.84 , lat=42.915, zoom = 12.45) %>% 
  addProviderTiles(providers$CartoDB)%>% #apply CartoDB ma
  addMiniMap(position = "topright")%>% # add map of the general area, place in top right corner
  addCircleMarkers(data = cleancrime2019, #add homicide markers
                   label = ~case_number, #label with the case number for quick reference
                   color = ~pal(year), #color by year
                   fillOpacity = .5, 
                   stroke = FALSE, 
                   popup = ~address, 
                   clusterOptions = markerClusterOptions()) #add popup to include the address 

2020 - Homicide Cluster Map

Map the homicides which occurred within Buffalo, New York, in 2020.

leaflet() %>% 
  setView(lng=-78.84 , lat=42.915, zoom = 12.45) %>% 
  addProviderTiles(providers$CartoDB)%>% #apply CartoDB ma
  addMiniMap(position = "topright")%>% # add map of the general area, place in top right corner
  addCircleMarkers(data = cleancrime2020, #add homicide markers
                   label = ~case_number, #label with the case number for quick reference
                   color = ~pal(year), #color by year
                   fillOpacity = .5, 
                   stroke = FALSE, 
                   popup = ~address, 
                   clusterOptions = markerClusterOptions()) #add popup to include the address 

2021 - Homicide Cluster Map

Map the homicides which occurred within Buffalo, New York, in 2021.

leaflet() %>% 
  setView(lng=-78.84 , lat=42.915, zoom = 12.45) %>% 
  addProviderTiles(providers$CartoDB)%>% #apply CartoDB ma
  addMiniMap(position = "topright")%>% # add map of the general area, place in top right corner
  addCircleMarkers(data = cleancrime2021, #add homicide markers
                   label = ~case_number, #label with the case number for quick reference
                   color = ~pal(year), #color by year
                   fillOpacity = .5, 
                   stroke = FALSE, 
                   popup = ~address, 
                   clusterOptions = markerClusterOptions()) #add popup to include the address 

Future Considerations & Recommendations:

Additional feature layers may help the audience understand the crime data better. Adding neighborhood polygons may help the audience conceptualize areas with a higher percentage of homicides; this data will likely be available via PENDATA Buffalo.

Additionally, other criminal incident types (rape, assault, etc.) may augment the maps. While homicides are most definitely violent crimes, other violent incidents should be taken into consideration assessing when violent neighborhoods.

Sources:

Buffalo Police Department. 2023. PENDATA Buffalo. “Crime Incidents” https://data.buffalony.gov/Public-Safety/Crime-Incidents/d6g9-xbgu. Accessed 15 May 2023.

Plants, R. 2021. WGRZ. “Buffalo Police talk strategy to stem violent crime surge after 2 fatal shooting Sunday.” https://www.wgrz.com/article/news/crime/buffalo-police-department-talks-strategy-to-stem-violent-crime-surge/71-99d0e40d-1620-462c-a405-1a388a71b9be. Accessed 30 May 2023.