This project analyzes the crime data from the City of Chicago for May 26, 27, 28, and briefly the 29 of this year (2024) to understand patterns and trends in criminal activity. I chose this topic because I visited Chicago last year and was warned about the high crime rate there, so, I decided to analyze the crime data to find out the facts myself. As a tourist, I want to find out:
For this analysis, we use a dataset provided by the City of Chicago which includes records of reported crimes. The dataset contains information such as the type of crime, the date, and the location.
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
dataset_url <- "https://data.cityofchicago.org/resource/ijzp-q8t2.csv"
crime_data <- read.csv(dataset_url, check.names = FALSE, stringsAsFactors = FALSE, header = TRUE)
#Displaying the data
head(crime_data)
## id case_number date block iucr
## 1 13477487 JH283625 2024-05-29T00:00:00.000 034XX W DIVERSEY AVE 0820
## 2 13476461 JH283196 2024-05-29T00:00:00.000 053XX N CUMBERLAND AVE 0560
## 3 13476295 JH282996 2024-05-29T00:00:00.000 088XX S ADA ST 0486
## 4 13476780 JH283388 2024-05-29T00:00:00.000 062XX S CHAMPLAIN AVE 0486
## 5 13476330 JH283058 2024-05-29T00:00:00.000 028XX W 36TH ST 0930
## 6 13476644 JH283414 2024-05-29T00:00:00.000 045XX W WEST END AVE 1310
## primary_type description
## 1 THEFT $500 AND UNDER
## 2 ASSAULT SIMPLE
## 3 BATTERY DOMESTIC BATTERY SIMPLE
## 4 BATTERY DOMESTIC BATTERY SIMPLE
## 5 MOTOR VEHICLE THEFT THEFT / RECOVERY - AUTOMOBILE
## 6 CRIMINAL DAMAGE TO PROPERTY
## location_description arrest domestic beat district ward
## 1 DEPARTMENT STORE false false 1412 14 35
## 2 STREET false false 1614 16 41
## 3 RESIDENCE false true 2222 22 21
## 4 APARTMENT false true 313 3 20
## 5 STREET false false 911 9 12
## 6 RESIDENCE - YARD (FRONT / BACK) false true 1113 11 28
## community_area fbi_code x_coordinate y_coordinate year
## 1 22 06 1153078 1918408 2024
## 2 76 08A 1119314 1934514 2024
## 3 71 08B 1168875 1846163 2024
## 4 42 08B 1181638 1863877 2024
## 5 58 07 1158088 1880653 2024
## 6 26 14 1145947 1900586 2024
## updated_on latitude longitude
## 1 2024-06-05T15:41:03.000 41.93196 -87.71288
## 2 2024-06-05T15:41:03.000 41.97676 -87.83661
## 3 2024-06-05T15:41:03.000 41.73339 -87.65692
## 4 2024-06-05T15:41:03.000 41.78171 -87.60961
## 5 2024-06-05T15:41:03.000 41.82826 -87.69550
## 6 2024-06-05T15:41:03.000 41.88320 -87.73954
## location
## 1 \n, \n(41.931962854, -87.712876373)
## 2 \n, \n(41.976763216, -87.836613764)
## 3 \n, \n(41.733387234, -87.656915358)
## 4 \n, \n(41.781711555, -87.609612588)
## 5 \n, \n(41.828258575, -87.695496439)
## 6 \n, \n(41.883196036, -87.739535384)
We will use several libraries for data manipulation, visualization, and analysis, including tidyverse for data manipulation and ggplot2 for visualization.
library(tidyverse)
library(ggplot2)
The dataset includes fields such as the date of the crime, the primary type of crime, the description, and the location.
# Summary statistics of the dataset
summary(crime_data)
## id case_number date block
## Min. : 28141 Length:1000 Length:1000 Length:1000
## 1st Qu.:13475193 Class :character Class :character Class :character
## Median :13475804 Mode :character Mode :character Mode :character
## Mean :13422351
## 3rd Qu.:13476384
## Max. :13484068
##
## iucr primary_type description location_description
## Length:1000 Length:1000 Length:1000 Length:1000
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## arrest domestic beat district
## Length:1000 Length:1000 Min. : 111.0 Min. : 1.00
## Class :character Class :character 1st Qu.: 529.2 1st Qu.: 5.00
## Mode :character Mode :character Median :1113.0 Median :11.00
## Mean :1162.3 Mean :11.39
## 3rd Qu.:1723.0 3rd Qu.:17.00
## Max. :2535.0 Max. :25.00
##
## ward community_area fbi_code x_coordinate
## Min. : 1.00 Min. : 1.00 Length:1000 Min. :1097306
## 1st Qu.: 9.00 1st Qu.:22.00 Class :character 1st Qu.:1154308
## Median :22.00 Median :32.00 Mode :character Median :1167592
## Mean :22.81 Mean :36.39 Mean :1165716
## 3rd Qu.:34.00 3rd Qu.:53.00 3rd Qu.:1176794
## Max. :50.00 Max. :77.00 Max. :1204787
## NA's :11
## y_coordinate year updated_on latitude
## Min. :1816604 Min. :2024 Length:1000 Min. :41.65
## 1st Qu.:1859197 1st Qu.:2024 Class :character 1st Qu.:41.77
## Median :1893721 Median :2024 Mode :character Median :41.86
## Mean :1886939 Mean :2024 Mean :41.85
## 3rd Qu.:1909988 3rd Qu.:2024 3rd Qu.:41.91
## Max. :1950563 Max. :2024 Max. :42.02
## NA's :11 NA's :11
## longitude location
## Min. :-87.92 Length:1000
## 1st Qu.:-87.71 Class :character
## Median :-87.66 Mode :character
## Mean :-87.67
## 3rd Qu.:-87.63
## Max. :-87.53
## NA's :11
# Verifying correct column names as data set
colnames(crime_data)
## [1] "id" "case_number" "date"
## [4] "block" "iucr" "primary_type"
## [7] "description" "location_description" "arrest"
## [10] "domestic" "beat" "district"
## [13] "ward" "community_area" "fbi_code"
## [16] "x_coordinate" "y_coordinate" "year"
## [19] "updated_on" "latitude" "longitude"
## [22] "location"
# Verifying rows
head(crime_data)
## id case_number date block iucr
## 1 13477487 JH283625 2024-05-29T00:00:00.000 034XX W DIVERSEY AVE 0820
## 2 13476461 JH283196 2024-05-29T00:00:00.000 053XX N CUMBERLAND AVE 0560
## 3 13476295 JH282996 2024-05-29T00:00:00.000 088XX S ADA ST 0486
## 4 13476780 JH283388 2024-05-29T00:00:00.000 062XX S CHAMPLAIN AVE 0486
## 5 13476330 JH283058 2024-05-29T00:00:00.000 028XX W 36TH ST 0930
## 6 13476644 JH283414 2024-05-29T00:00:00.000 045XX W WEST END AVE 1310
## primary_type description
## 1 THEFT $500 AND UNDER
## 2 ASSAULT SIMPLE
## 3 BATTERY DOMESTIC BATTERY SIMPLE
## 4 BATTERY DOMESTIC BATTERY SIMPLE
## 5 MOTOR VEHICLE THEFT THEFT / RECOVERY - AUTOMOBILE
## 6 CRIMINAL DAMAGE TO PROPERTY
## location_description arrest domestic beat district ward
## 1 DEPARTMENT STORE false false 1412 14 35
## 2 STREET false false 1614 16 41
## 3 RESIDENCE false true 2222 22 21
## 4 APARTMENT false true 313 3 20
## 5 STREET false false 911 9 12
## 6 RESIDENCE - YARD (FRONT / BACK) false true 1113 11 28
## community_area fbi_code x_coordinate y_coordinate year
## 1 22 06 1153078 1918408 2024
## 2 76 08A 1119314 1934514 2024
## 3 71 08B 1168875 1846163 2024
## 4 42 08B 1181638 1863877 2024
## 5 58 07 1158088 1880653 2024
## 6 26 14 1145947 1900586 2024
## updated_on latitude longitude
## 1 2024-06-05T15:41:03.000 41.93196 -87.71288
## 2 2024-06-05T15:41:03.000 41.97676 -87.83661
## 3 2024-06-05T15:41:03.000 41.73339 -87.65692
## 4 2024-06-05T15:41:03.000 41.78171 -87.60961
## 5 2024-06-05T15:41:03.000 41.82826 -87.69550
## 6 2024-06-05T15:41:03.000 41.88320 -87.73954
## location
## 1 \n, \n(41.931962854, -87.712876373)
## 2 \n, \n(41.976763216, -87.836613764)
## 3 \n, \n(41.733387234, -87.656915358)
## 4 \n, \n(41.781711555, -87.609612588)
## 5 \n, \n(41.828258575, -87.695496439)
## 6 \n, \n(41.883196036, -87.739535384)
# summary of data set by providing dimensions
str(crime_data)
## 'data.frame': 1000 obs. of 22 variables:
## $ id : int 13477487 13476461 13476295 13476780 13476330 13476644 13482056 13477597 13477931 13478910 ...
## $ case_number : chr "JH283625" "JH283196" "JH282996" "JH283388" ...
## $ date : chr "2024-05-29T00:00:00.000" "2024-05-29T00:00:00.000" "2024-05-29T00:00:00.000" "2024-05-29T00:00:00.000" ...
## $ block : chr "034XX W DIVERSEY AVE" "053XX N CUMBERLAND AVE" "088XX S ADA ST" "062XX S CHAMPLAIN AVE" ...
## $ iucr : chr "0820" "0560" "0486" "0486" ...
## $ primary_type : chr "THEFT" "ASSAULT" "BATTERY" "BATTERY" ...
## $ description : chr "$500 AND UNDER" "SIMPLE" "DOMESTIC BATTERY SIMPLE" "DOMESTIC BATTERY SIMPLE" ...
## $ location_description: chr "DEPARTMENT STORE" "STREET" "RESIDENCE" "APARTMENT" ...
## $ arrest : chr "false" "false" "false" "false" ...
## $ domestic : chr "false" "false" "true" "true" ...
## $ beat : int 1412 1614 2222 313 911 1113 313 1135 1912 1024 ...
## $ district : int 14 16 22 3 9 11 3 11 19 10 ...
## $ ward : int 35 41 21 20 12 28 20 28 47 24 ...
## $ community_area : int 22 76 71 42 58 26 42 29 5 29 ...
## $ fbi_code : chr "06" "08A" "08B" "08B" ...
## $ x_coordinate : int 1153078 1119314 1168875 1181638 1158088 1145947 1182280 1157861 1163062 1154489 ...
## $ y_coordinate : int 1918408 1934514 1846163 1863877 1880653 1900586 1864379 1895062 1928197 1891024 ...
## $ year : int 2024 2024 2024 2024 2024 2024 2024 2024 2024 2024 ...
## $ updated_on : chr "2024-06-05T15:41:03.000" "2024-06-05T15:41:03.000" "2024-06-05T15:41:03.000" "2024-06-05T15:41:03.000" ...
## $ latitude : num 41.9 42 41.7 41.8 41.8 ...
## $ longitude : num -87.7 -87.8 -87.7 -87.6 -87.7 ...
## $ location : chr "\n, \n(41.931962854, -87.712876373)" "\n, \n(41.976763216, -87.836613764)" "\n, \n(41.733387234, -87.656915358)" "\n, \n(41.781711555, -87.609612588)" ...
We handle missing values by replacing them with “Unknown” where appropriate. The date column is converted to a suitable format for analysis.
# Converting the date column into the proper date format
crime_data$date <- as.POSIXct(crime_data$date, format="%Y-%m-%dT%H:%M:%OS")
colSums(is.na(crime_data))
## id case_number date
## 0 0 0
## block iucr primary_type
## 0 0 0
## description location_description arrest
## 0 0 0
## domestic beat district
## 0 0 0
## ward community_area fbi_code
## 0 0 0
## x_coordinate y_coordinate year
## 11 11 0
## updated_on latitude longitude
## 0 11 11
## location
## 0
crime_data <- crime_data %>%
mutate(across(everything(), ~ifelse(is.na(.), "Unknown", .)))
crime_data <- crime_data %>%
filter(!is.na(date))
# cleaned data
head(crime_data)
## id case_number date block iucr
## 1 13477487 JH283625 1716966000 034XX W DIVERSEY AVE 0820
## 2 13476461 JH283196 1716966000 053XX N CUMBERLAND AVE 0560
## 3 13476295 JH282996 1716966000 088XX S ADA ST 0486
## 4 13476780 JH283388 1716966000 062XX S CHAMPLAIN AVE 0486
## 5 13476330 JH283058 1716966000 028XX W 36TH ST 0930
## 6 13476644 JH283414 1716966000 045XX W WEST END AVE 1310
## primary_type description
## 1 THEFT $500 AND UNDER
## 2 ASSAULT SIMPLE
## 3 BATTERY DOMESTIC BATTERY SIMPLE
## 4 BATTERY DOMESTIC BATTERY SIMPLE
## 5 MOTOR VEHICLE THEFT THEFT / RECOVERY - AUTOMOBILE
## 6 CRIMINAL DAMAGE TO PROPERTY
## location_description arrest domestic beat district ward
## 1 DEPARTMENT STORE false false 1412 14 35
## 2 STREET false false 1614 16 41
## 3 RESIDENCE false true 2222 22 21
## 4 APARTMENT false true 313 3 20
## 5 STREET false false 911 9 12
## 6 RESIDENCE - YARD (FRONT / BACK) false true 1113 11 28
## community_area fbi_code x_coordinate y_coordinate year
## 1 22 06 1153078 1918408 2024
## 2 76 08A 1119314 1934514 2024
## 3 71 08B 1168875 1846163 2024
## 4 42 08B 1181638 1863877 2024
## 5 58 07 1158088 1880653 2024
## 6 26 14 1145947 1900586 2024
## updated_on latitude longitude
## 1 2024-06-05T15:41:03.000 41.931962854 -87.712876373
## 2 2024-06-05T15:41:03.000 41.976763216 -87.836613764
## 3 2024-06-05T15:41:03.000 41.733387234 -87.656915358
## 4 2024-06-05T15:41:03.000 41.781711555 -87.609612588
## 5 2024-06-05T15:41:03.000 41.828258575 -87.695496439
## 6 2024-06-05T15:41:03.000 41.883196036 -87.739535384
## location
## 1 \n, \n(41.931962854, -87.712876373)
## 2 \n, \n(41.976763216, -87.836613764)
## 3 \n, \n(41.733387234, -87.656915358)
## 4 \n, \n(41.781711555, -87.609612588)
## 5 \n, \n(41.828258575, -87.695496439)
## 6 \n, \n(41.883196036, -87.739535384)
crime_data$date <- as.POSIXct(crime_data$date, format="%Y-%m-%d %H:%M:%S")
crime_data <- crime_data %>%
mutate(date_hour = format(date, "%Y-%m-%d %H:00:00"))
hourly_counts <- crime_data %>%
count(date_hour) %>%
mutate(date_hour = as.POSIXct(date_hour, format="%Y-%m-%d %H:%M:%S"))
hourly_counts <- hourly_counts %>%
mutate(day = format(date_hour, "%Y-%m-%d"))
# Plotting graph
ggplot(hourly_counts, aes(x = date_hour, y = n, fill = day)) +
geom_bar(stat = "identity", color = "black") +
geom_text(aes(label = format(date_hour, "%I %p")), vjust = -0.5, size = 2.5) +
theme_minimal() +
labs(title = "Crimes Over Time by Hour", x = "Date and Hour", y = "Count of Crimes") +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank()) +
scale_fill_manual(values = c("2024-05-27" = "#FFB6C1", "2024-05-28" = "#ADD8E6", "2024-05-29" = "#98FB98")) +
guides(fill = guide_legend(title = "Day"))
The crimes are generally high throughout the day except in the night from 1 AM to 9 AM.
We conduct a frequency analysis to identify the most common types of crimes.
# Frequency of crime types
crime_type_freq <- crime_data %>%
group_by(primary_type) %>%
summarize(Frequency = n()) %>%
arrange(desc(Frequency))
# Displaying the top crime types
head(crime_type_freq, 10)
## # A tibble: 10 × 2
## primary_type Frequency
## <chr> <int>
## 1 BATTERY 192
## 2 THEFT 190
## 3 ASSAULT 128
## 4 CRIMINAL DAMAGE 111
## 5 OTHER OFFENSE 76
## 6 MOTOR VEHICLE THEFT 71
## 7 BURGLARY 46
## 8 WEAPONS VIOLATION 37
## 9 DECEPTIVE PRACTICE 35
## 10 ROBBERY 30
We visualize the distribution of different types of crimes using a plot.
# Plotting graph
ggplot(crime_data, aes(x = primary_type)) +
geom_bar(fill = "blue", color = "black") +
theme_minimal() +
labs(title = "Crimes by Type", x = "Type of Crime", y = "Count") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
The following crimes are more frequent (Evident from the statistical analysis and graph): 1. Theft 2. Battery 3. Assault 4. Criminal Damage 5. Motor Vehicle Theft
Although stalking is also a concern for tourists, but the number of reported incidents are low.
We explore the distribution of crimes by location description.
ggplot(crime_data, aes(x = location_description)) +
geom_bar(fill = "green", color = "black") +
theme_minimal() +
labs(title = "Crimes by Location", x = "Location Description", y = "Count") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
Most number of crimes take place in the following areas: 1) Apartment 2) Street 3) Parking lot/ Garage (non residential) 4) Residence 5) Sidewalk 6) Small Retail Store
# Filtering the data to include only Theft, Assault, and Battery
filtered_crime_data <- crime_data %>%
filter(primary_type %in% c("THEFT", "ASSAULT", "BATTERY"))
location_counts <- filtered_crime_data %>%
count(location_description) %>%
filter(n > 0) %>%
filter(location_description %in% c("STREET", "PARKING LOT / GARAGE (NON RESIDENTIAL)", "SIDEWALK", "SMALL RETAIL STORE"))
# Plotting
ggplot(location_counts, aes(x = reorder(location_description, n), y = n)) +
geom_bar(stat = "identity", fill = "green", color = "black") +
theme_minimal() +
labs(title = "Crimes by Location (Theft, Assault, Battery)", x = "Location Description", y = "Count") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 6))
coord_flip()
## <ggproto object: Class CoordFlip, CoordCartesian, Coord, gg>
## aspect: function
## backtransform_range: function
## clip: on
## default: FALSE
## distance: function
## expand: TRUE
## is_free: function
## is_linear: function
## labels: function
## limits: list
## modify_scales: function
## range: function
## render_axis_h: function
## render_axis_v: function
## render_bg: function
## render_fg: function
## setup_data: function
## setup_layout: function
## setup_panel_guides: function
## setup_panel_params: function
## setup_params: function
## train_panel_guides: function
## transform: function
## super: <ggproto object: Class CoordFlip, CoordCartesian, Coord, gg>
The tourists have to stay vigilant at all these four locations.
crime_data$date <- as.POSIXct(crime_data$date, format="%Y-%m-%d %H:%M:%S")
# Filtering data for Theft, Assault, and Battery
filtered_crime_data <- crime_data %>%
filter(primary_type %in% c("THEFT", "ASSAULT", "BATTERY")) %>%
mutate(date_hour = format(date, "%Y-%m-%d %H:00:00"))
hourly_counts <- filtered_crime_data %>%
count(date_hour) %>%
mutate(date_hour = as.POSIXct(date_hour, format="%Y-%m-%d %H:%M:%S"))
hourly_counts <- hourly_counts %>%
mutate(day = format(date_hour, "%Y-%m-%d"))
# Plotting the graph
ggplot(hourly_counts, aes(x = date_hour, y = n, fill = day)) +
geom_bar(stat = "identity", color = "black") +
scale_x_datetime(date_breaks= "1 hour", date_labels = "%I %p") + # Format x-axis to show hour
theme_minimal() +
labs(title = "Crimes Over Time by Hour for Theft, Assault, and Battery", x = "Hour", y = "Count of Crimes") +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) + # Rotate x-axis labels
scale_fill_manual(values = c("2024-05-27" = "pink", "2024-05-28" = "blue", "2024-05-29" = "purple")) +
guides(fill = guide_legend(title = "Day"))
These three crimes are generally high throughout the day except in the night from 1 AM to 7 AM. It is therefore important to stay vigilant when outside at all time.
# Calculate the counts of crimes by district
district_counts <- crime_data %>%
count(district) %>%
filter(n > 0)
# Create the plot
ggplot(district_counts, aes(x = reorder(as.factor(district), -n), y = n)) +
geom_bar(stat = "identity", fill = "blue", color = "black") +
theme_minimal() +
labs(title = "Number of Crimes by District", x = "District", y = "Count of Crimes") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
District 16 and 20 are safe relative to others.
# Convert date column to POSIXct if it's not already
crime_data$date <- as.POSIXct(crime_data$date, format="%Y-%m-%d %H:%M:%S")
# Filtering data for district 20
district_20_data <- crime_data %>%
filter(district == 20)
# Aggregate the counts of crimes by community area for Theft, Assault, and Battery
community_area_counts <- district_20_data %>%
filter(primary_type %in% c("THEFT", "ASSAULT", "BATTERY")) %>%
count(community_area)
# Create a complete sequence of community areas
all_community_areas <- unique(district_20_data$community_area)
# Ensure all community areas are represented
community_area_counts <- community_area_counts %>%
complete(community_area = all_community_areas, fill = list(n = 0))
# Plotting the graph
ggplot(community_area_counts, aes(x = as.factor(community_area), y = n)) +
geom_bar(stat = "identity", fill = "lightblue", color = "black") +
geom_text(aes(label = n), vjust = -0.5, color = "black") +
theme_minimal() +
labs(title = "Number of Crimes by Community Area in District 20",
x = "Community Area", y = "Count of Crimes") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
The safest place for tourists to stay in Chicago is Community Area 2 in District 20 where no crime of battery, theft and assault are reported on the given dates.
What is the nature of most common crimes that tourists should be concerned about? Conclusion: The most frequent types of crimes concerning the tourists are theft, battery, and assault.
What are the places where these crimes are mostly committed? Conclusion: These crimes are mostly committed on the streets, sidewalks, small retail stores, and non-residential parking lots. All these areas are generally full of tourists.
When are these crimes committed during the day? Is there a pattern to guide the tourists? Conclusion: These crimes are being committed throughout the day except in the night (1 AM - 7 AM). The tourists therefore must stay vigilant when outdoors.
Which is the safest community area to stay in Chicago? Conclusion: The safest place for tourists to stay in Chicago is Community Area 2 in District 20 where no crime of battery, theft and assault are reported on the given dates.
Which districts have high crime rate that tourists have to be aware about? Conclusion: The top 5 districts with highest reported crimes are: 3, 12, 11, 6, and 8.
In conclusion, our analysis of Chicago’s crime data revealed significant insights into the types and locations of crimes, as well as their temporal patterns. These findings can inform law enforcement strategies, policy-making, and community initiatives aimed at reducing crime and enhancing public safety. By understanding where and when crimes are most likely to occur, stakeholders can develop more effective approaches to crime prevention and resource allocation, ultimately contributing to a safer Chicago.