Introduction

The data used in this analysis is titled “Boston Crimes.” The information provided by this data set includes the details of crimes that have been committed from Jan 1, 2023-Dec 29, 2024

Dataset

The 17 column names are: incident_number, offense_code, offense_code_group, offense_description, district, reporting_area, shooting, occurred_on_date, year, month, day_of_week, hour, ucr_part, street, lat, long, location

There are 155,959 rows.
There are 332, 030 NA’s in the data frame; however, offense_description, district, year, month, day_of_week, hour, and street have zero NA’s.

Findings

The following tabs provide detailed information regarding crimes that happened Boston from Jan 1, 2023 to Dec 29, 2024

#setwd("//apporto.com/dfs/LOYOLA/Users/briely_loyola/Desktop/")

library(dplyr)
library(DescTools)
library(ggplot2)
library(data.table)
library(scales)
library(RColorBrewer)
library(ggthemes)
library(ggrepel)

df <- read.csv("//apporto.com/dfs/LOYOLA/Users/briely_loyola/Desktop/2023 to date.csv")

Tab 1

Bar Chart The bar chart shows the 10 worse districts in the Boston area. D4 covers the South End neighborhood of Boston, along with parts of Back Bay, lower Roxbury, and the Fenway area. B2 covers the neighborhood of Roxbury

# count the number of criminal offensives in each district 
DistrictCount <- data.frame(count(df,DISTRICT ))

#compute the values of the top 10
DistrictCount<-DistrictCount[order(DistrictCount$n, decreasing = TRUE),]
result = DistrictCount[1:10,]

# set up a way to label each bar in the bar graph
values = result$n

# create bar graph
ggplot(DistrictCount[1:10,], aes(x =reorder(DISTRICT,-n),y = n ))+
  geom_bar(colour ="darkblue", fill="lightblue", stat = "identity")+
  labs(title = "Number of Crimes in Boston Districts (Top 10)", x = "District", y = "Number of Incidents")+
  theme(plot.title=element_text(hjust = 0.5))+
  scale_y_continuous(labels = label_comma()) +
  geom_text(aes(label = comma(values)),vjust= -0.5,color="black") 

### Tab 2 stacked bar chart The stacked bar chart shows the number of crimes per month for the worst 10 districts

hours_df<-df %>%
  select(HOUR) %>%
  group_by(HOUR) %>%
  summarise(n = length(HOUR), .groups ='keep') %>%
  data.frame()

x_axis_labels = min(hours_df$HOUR):max(hours_df$HOUR)

hi_lo <- hours_df %>%
  filter(n == min(n) | n == max(n)) %>%
  data.frame()

ggplot(hours_df, aes(x =HOUR, y = n))+
  geom_line(color = 'black', linewidth =1)+
  geom_point(shape =21, size=4, color = 'red', fill = 'white')+
  labs(x ="Hour",y = "Number of Crimes", title="Number of Crimes by Hour", caption="Source: Boston Crime Data")+
  scale_y_continuous(labels=comma)+
  theme_light()+
  theme(plot.title=element_text(hjust = 0.5))+
  scale_x_continuous(labels=x_axis_labels, breaks=x_axis_labels,minor_breaks=NULL)+
  geom_point(data = hours_df %>% filter(HOUR == 23), aes(x = HOUR, y = n), shape = 21, size = 4, fill = 'red', color = 'red') +
  geom_point(data= hi_lo,aes(x =HOUR, y = n), shape =21, size =4, fill = 'red',color = 'red')+
  geom_label_repel(aes(label =  ifelse(n==max(n) | n==min(n)|HOUR == max(HOUR), scales::comma(n), "")), 
                   box.padding = 2,
                   point.padding = 1, 
                   size = 4, 
                   color='Grey50',
                   segment.color='darkblue') 

### Tab 3 Wire Shows the number of crimes per hour

#shootings
top_shootins <- count(df,DAY_OF_WEEK)

shooting_df <- df %>%
  select(SHOOTING, DAY_OF_WEEK) %>%
  mutate(ShotsFired = ifelse(SHOOTING == "1", "Shooting", ifelse(SHOOTING == "0", "No Shooting", "Nothing Reported"))) %>%
  group_by(DAY_OF_WEEK, ShotsFired) %>%
  summarise(n=length(ShotsFired), .groups = 'keep') %>%
  group_by(DAY_OF_WEEK) %>%
  mutate(percent_of_total= round(100*n/sum(n),1))%>%
  ungroup()%>%
  data.frame()

ggplot(data = shooting_df, aes(x="", y=n, fill=ShotsFired)) +
  geom_bar(stat = "identity", position = "fill") +
  coord_polar(theta = "y", start = 0) +
  labs (fill = "Days", x = NULL, y = NULL, title = "Percentage of Crime that Involve Guns by Day") +
  theme(plot.title = element_text(hjust = 0.5),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        panel.grid = element_blank()) +
  facet_wrap(~ DAY_OF_WEEK, ncol = 4, nrow = 2) +
  scale_fill_brewer(palette = "Reds") +
  geom_text(aes(x = 1.7, label = paste0(percent_of_total,"%")),
            size = 2, 
            position = position_fill(vjust = 0.5)) 

# change numbers 1,2, etc to January, February, etc
df$month_name <- month.name[df$MONTH]
 
days_df <- df %>%
  select(month_name, DAY_OF_WEEK) %>%
  group_by(month_name, DAY_OF_WEEK) %>%
  summarise(n = length(DAY_OF_WEEK), .groups = 'keep') %>%
  data.frame()
 
ggplot(days_df, aes(
  x = factor(DAY_OF_WEEK,
             levels = c("Monday", "Tuesday", "Wednesday",
                        "Thursday", "Friday", "Saturday", "Sunday")),
  y = n,
  fill = month_name
)) +
  geom_bar(stat = "identity", position = "dodge") +
  theme_light() +
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Multiple Bar Charts - Total Crimes by Month and by Day",
    x = "Day of the Week",
    y = "Number of Crimes",
    fill = "Month"
  ) +
  scale_fill_brewer(
    palette = "Paired",
    limits = month.name
  ) +
  facet_wrap(
    ~ factor(month_name, levels = month.name),
    ncol = 4,
    nrow = 3
  ) +
  theme(axis.text.x = element_text(angle = 90, size = 8)) 

# count the number of criminal offensives in each district 
DistrictCount <- data.frame(count(df,DISTRICT ))

#compute the values of the top 10
DistrictCount<-DistrictCount[order(DistrictCount$n, decreasing = TRUE),]
result = DistrictCount[1:10,]

df_reasons <-count(df, DISTRICT)

df_reasons <- df_reasons[order(df_reasons$n,decreasing = TRUE),]
top_reasons <- df_reasons$DISTRICT[1:10]

new_df <- df %>% 
  filter(DISTRICT %in% top_reasons)%>%
  select(MONTH,DISTRICT)%>%
  group_by(DISTRICT,MONTH)%>%
  summarise(n=length(DISTRICT),.groups = 'keep')%>%
  data.frame()

agg_tot <-new_df %>%
  select(DISTRICT,n) %>%
  group_by(DISTRICT) %>%
  summarise(tot = sum(n),.groups = 'keep')%>%
  data.frame()

new_df$MONTH<-as.factor(new_df$MONTH)
ggplot(new_df, aes(
  x = reorder(DISTRICT, n, sum),
  y = n,
  fill = factor(MONTH, levels = 1:12, labels = month.name)
)) +
  geom_bar(stat = "identity") +
  coord_flip() +
  labs(
    title = "Number of Crimes by Districts in Boston",
    x = "Districts in Boston",
    y = "Number of Crimes",
    fill = "Month"
  ) +
  theme_light() +
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_fill_brewer(palette = "Paired") +
  geom_text(
    data = agg_tot,
    aes(x = DISTRICT, y = tot, label = comma(tot), fill = NULL),
    hjust = -0.1
  ) +
  scale_y_continuous(labels = comma, limits = c(0, 25000))