This dataset contains crimes committed in the city of Chicago since 2001. The source of the dataset is the Chicago Police Department. The email for the maintainer of the dataset is '[email protected]ice.org', which is the email of the Research and Development Division of the Chicago police force. Officially, the dataset is from data.cityofchicago.org. Chicago Crime Since 2001
data.cityofchicago.org. (2017). Crimes - 2001 to present [Comma Separate Value file]. Retrieved from https://catalog.data.gov/dataset/crimes-2001-to-present-398a4.
There are 6,291,788 rows in this dataset and there are 22 columns. The dataset is the crimes in Chicago since 2001. The data is extracted from the Chicago Police Department's CLEAR (Citizen Law Enforcement Analysis and Reporting) system.
A description of the columns is as follows:
The code below imports the dataset as a comma separated value file and assigns it to a variable named 'chicago.crime' and call the tidyverse and lubridate packages. The dataset should be in the folder of the working directory before attempting to import. Prior to importing, the dataset was significantly reduced in size so it was possible to import.
# Set the location for R packages .libPaths(new = "~/Rlibs") # Load the Tidyverse packages library(tidyverse) library(lubridate) chicago.crime<-read.csv("ChicagoCrime.csv")
I cleaned the dataset which originally had 6,291,788 rows and 22 columns to only include the years 2015 to 2017. This reduced the dataset to 577,130 rows. I did this in RStudio outside of SageMathCloud.
I then removed columns which would not be needed for my analysis including X, Case.Number, Updated.On, Location, X.Coordinate, Y.Coordinate, ID, Case.Number, FBI.Code, Block, Beat, Latitude, Longitude, and Location. Some of these columns had values of "NA", "NULL", or "NaN" such as "Ward", "X.Coordinate", "Y.Coordinate", "Latitude", and "Longitude" but were removed as they were not necessary for this analysis.
I separated the column "Date" into 2 separate columns, "DateTime" and "TimeofDay".
I mutated the column "DateTime" into a dateTime format that could be referenced.
I checked again for values in columns of NA, NULL, or NaN prior to data analysis.
The code below checks to see if there are any 'NA', NULL, or 'NaN' values first by using the apply() function. Then, it removes the columns that are unnecessary for this analysis by subsetting the tibble using the subset function() and using a negative index to combine the columns and remove them. The 'Date' column is separated into 'DateTime' and the 'TimeofDay' (which is AM or PM) using the separate() function. This is for ease of analysis. The final line of code converts the 'DateTime' column into the type 'datetime' and format of month-day-year hour-minute-second using the mutate() function. All of these actions assign the result to a variable named 'chicago.crime.test' for each new operation applied to the dataset. Finally, the code to check for NULL or NA values is repeated to confirm a 'clean' dataset and the top of the dataset is shown using the head() function. The dataset appears to conform to 'tidy' data principles.
apply(chicago.crime, 2, function(x) any(is.na(x) | is.null(x) | is.nan(x))) chicago.crime.test<-subset(chicago.crime, select = -c(X,Case.Number,Updated.On,Location,X.Coordinate,Y.Coordinate,ID,Case.Number,Beat,Latitude,Longitude,Location,Ward,FBI.Code, District)) chicago.crime.test<-separate(chicago.crime.test,Date,c("DateTime","TimeOfDay"),sep=-3,convert=TRUE) chicago.crime.test<-mutate(chicago.crime.test, DateTime= mdy_hms(chicago.crime.test$DateTime)) apply(chicago.crime.test, 2, function(x) any(is.na(x) | is.null(x) | is.nan(x))) head(chicago.crime.test)
|2016-04-14 06:25:00||PM||004XX E 46TH ST||143A||WEAPONS VIOLATION||UNLAWFUL POSS OF HANDGUN||SIDEWALK||true||false||38||2016|
|2016-04-17 02:00:00||PM||070XX S ELIZABETH ST||2820||OTHER OFFENSE||TELEPHONE THREAT||RESIDENCE||true||true||67||2016|
|2016-03-20 05:00:00||PM||013XX W 81ST ST||0560||ASSAULT||SIMPLE||RESIDENCE||true||true||71||2016|
|2016-04-18 04:48:00||PM||007XX E 50TH ST||0470||PUBLIC PEACE VIOLATION||RECKLESS CONDUCT||STREET||true||false||38||2016|
|2016-04-18 11:01:00||PM||070XX S STATE ST||0484||BATTERY||PRO EMP HANDS NO/MIN INJURY||SIDEWALK||true||false||69||2016|
|2016-04-19 12:40:00||AM||009XX W 95TH ST||1310||CRIMINAL DAMAGE||TO PROPERTY||RESIDENCE||true||false||73||2016|
The code below creates a new column using the mutate() function as well as arithmetic operations.
The new column shows the proportion of certain crimes by counting number of crimes of specific type and dividing that amount by the total amount of crimes for that year. First it groups the dataset by year and primary type of crime. Then, a column representing the count of total crimes for each category for each year is created and called 'count' and the tibble is organized in descending order of number of crimes. Finally a new column is created called "Proportion" that represents how many crimes out of the total number of crimes for that year were of a certain category.
by_type<-group_by(chicago.crime.test,Year,Primary.Type) by_type<-arrange(summarize(by_type, count=n()),desc(count)) by_type<-mutate(by_type, Proportion=count/sum(count)) by_type
|2016||MOTOR VEHICLE THEFT||11341||0.04254130|
|2015||MOTOR VEHICLE THEFT||10073||0.03828262|
|2017||LIQUOR LAW VIOLATION||51||1.075496e-03|
|2016||CONCEALED CARRY LICENSE VIOLATION||36||1.350398e-04|
|2015||CONCEALED CARRY LICENSE VIOLATION||34||1.292176e-04|
|2015||NON - CRIMINAL||20||7.601037e-05|
|2017||CONCEALED CARRY LICENSE VIOLATION||12||2.530578e-04|
|2015||OTHER NARCOTIC VIOLATION||5||1.900259e-05|
|2016||NON - CRIMINAL||5||1.875553e-05|
|2016||OTHER NARCOTIC VIOLATION||4||1.500443e-05|
|2016||NON-CRIMINAL (SUBJECT SPECIFIED)||1||3.751107e-06|
|2017||NON-CRIMINAL (SUBJECT SPECIFIED)||1||2.108815e-05|
As demonstrated above, theft, battery, and criminal damage were the most common crimes committed in the city of Chicago. And actually the number of these categories of crimes rose slightly from 2015 to 2016.
The code below uses the group_by() function to group the dataset by Community.Area and then summarize to count the total amount of crimes for each community area for each year.
by_community<-group_by(chicago.crime.test,Year,Community.Area) by_community<-arrange(summarize(by_community, count=n()),desc(count)) by_community
25,8,28,43,29 are some communities with the consistently high amounts of crimes for 2016 and 2015.
The two most noticeable community areas with consistently high amounts of crimes for 2016 and 2015 are 25 and 8. Community Area 25 corresponds to 'Austin' neighborhood in Chicago. Community Area 8 corresponds to 'Near Northside' neighborhood in Chicago.
The code below first filters the dataset to only show homicides for the years 2016 and 2015 using the filter() function and specifying the 'Year' and 'Primary.Type'.
count(filter(chicago.crime.test, Year=='2015' & Primary.Type == "HOMICIDE")) count(filter(chicago.crime.test, Year=='2016' & Primary.Type == "HOMICIDE"))
It appears that in general homicides have been on the rise recently.
Do crimes tend to rise during summer? Yes. Especially during June, July, and August.
What drugs were being manufactured/delivered in Chicago in 2016? Mainly white heroin, crack, and marijuana under 10 grams. However, marijuana over 10 grams is on the rise in 2016.
Neighbors with most crimes? How many crimes typically? The community area "Austin" had around 45 crimes a day in 2016 and Community Area 'Near Northside' had around 28 crimes a day in 2016.
Is Trump right to demand that "Chicago fix the horrible "carnage" going on, 228 shootings in 2017 with 42 killings (up 24% from 2016)?" Should he "send in the feds"?
How many homicides happened in 2017 from January 1st to when Trump tweeted this? How many homicides in this same time period for 2016? From January 1st to January 24th, there were 37 homicides in 2016 and 45 homicides in 2017.
How many crimes involving handguns or 'shootings' have happened in 2017 during this time period? According to the data, not only were there no 'shootings' in 2017 but there were no crimes related to handguns at all in 2017.
The code below filters the dataset to only show homicides using the filter() function. It then separates the 'DateTime' column into two columns 'Date' and 'Time using the separate() function. Finally, it separates the 'Date' column into 3 different columns 'Year1','Month', and 'Day'. The 'Year1' column was not removed because the end goal was to make a plot, therefore the 'tidyness' of the dataset was not a priority. The dataset was then grouped by the Year, Month, and Primary Type using the group_by() dataset. This dataset was then summarized to count the number of homicides that happened each month for each year.
A plot was then made to show the number of homicides for each month for each year, using different colors for different years.
This plot is a representation of a correlation between homicides and months. It does appear as if homicides go up during the summer or hotter months, specifically June, July, and August.
chicago.crime.test.scatter<-filter(chicago.crime.test, (Primary.Type == 'HOMICIDE' )) chicago.crime.test.scatter<-separate(chicago.crime.test.scatter,DateTime,c("Date","Time"),sep=" ",convert=TRUE) chicago.crime.test.scatter<-separate(chicago.crime.test.scatter,Date,c("Year1","Month","Day"),sep="-",convert=TRUE) by_month<-group_by(chicago.crime.test.scatter,Year,Month) #head(by_month) by_month<-arrange(summarize(by_month, count=n())) #by_month first.plot<- ggplot(data=by_month) + geom_point(mapping= aes(x=factor(Month),y=count,colour = factor(Year))) first.plot
The code below alters the dataset to separate the 'DateTime' column into two separate columns 'Date' and 'Time' and assigns it to a variable 'chicago.crime.test.narc' using the separate() function. It then filters the new dataset to only show those offenses that happened in the year 2016 and were drug-related using the filter() function. The filter() function is used again to filter the previously created dataset to only show the offenses that contained the string 'MANU' in the description of the crime to represent only drug-related crimes that were manufacturing and distributing drugs.
The code then separates the 'Date' column into three separate columns 'Year1','Month', and 'Day'. 'Year1' column was not removed as the ultimate goal was a graph, and thus the 'tidyness' of the tibble was not a priority.
The code then uses the group_by() function to group the dataset by year, month, and description and finally uses the summarize() and arrange() functions to count the number of crimes per category per month and then organizes the tibble in descending order of number of crimes. The top of the tibble is shown using the head() function. It appears as if the main drug being distributed in Chicago is 'white heroin'.
chicago.crime.test.narc<-separate(chicago.crime.test,DateTime,c("Date","Time"),sep=" ",convert=TRUE) chicago.crime.test.narc<-filter(chicago.crime.test.narc, (Year == '2016' & Primary.Type == 'NARCOTICS')) chicago.crime.test.narc<-filter(chicago.crime.test.narc, grepl('MANU', Description)) chicago.crime.test.narc<-separate(chicago.crime.test.narc,Date,c("Year1","Month","Day"),sep="-",convert=TRUE) by_date_and_type<-group_by(chicago.crime.test.narc,Year,Month,Description) by_date_and_type<-arrange(summarize(by_date_and_type, count=n()),desc(count)) head(by_date_and_type)
|2016||1||MANU/DELIVER: HEROIN (WHITE)||138|
|2016||3||MANU/DELIVER: HEROIN (WHITE)||125|
|2016||5||MANU/DELIVER: HEROIN (WHITE)||112|
|2016||2||MANU/DELIVER: HEROIN (WHITE)||109|
|2016||9||MANU/DELIVER: HEROIN (WHITE)||102|
|2016||6||MANU/DELIVER: HEROIN (WHITE)||100|
The code below takes the tibble 'by_date_and_type' and creates a line graph for each type of offense in manufacturing/distributing drugs over a period of months for 2016 and assigns it to a variable 'q'. The options() function controls the height and width of the graph display window.
options(repr.plot.width = 15, repr.plot.height=25) q<-ggplot(data=by_date_and_type,aes(x=as.factor(Month), y=count, colour=Description)) + geom_line(aes(group=Description)) q
The graph shows that initially there was a large amount of 'white heroin' being distributed in Chicago at the beginning of 2016 and swiftly declined near the end of 2016 while the manufacture/distribution of marijuana in quantities over 10 grams rose as the year went on.
The code below separates the dataset column 'Date' into two separate columns 'Date' and 'Time by using the separate() function and then filters the dataset to show only data for the year 2016 using the filter() function.
The resulting dataset is then grouped by Year, Community.Area, and Date using the group_by() function. A new column is added counting the number of crimes per day per community area using the summarize() function nested in the arrange() function.
The summarize() function is used again to get summary statistics for the dataset such as the mean, minimum, maximum, upper and lower quartiles, median, variance, and standard deviation of the dataset.
Finally the dataset is arranged in descending order of mean amount of crimes using the arrange() function. The top of this dataset is shown using the head() function.
by_comm<-separate(chicago.crime.test,DateTime,c("Date","Time"),sep=" ",convert=TRUE) by_comm<-filter(by_comm, Year == '2016') by_comm<-group_by(by_comm,Year,Community.Area,Date) by_comm<-arrange(summarize(by_comm, count=n()),desc(count)) by_comm<-summarize(by_comm, mean.comm=sum(count)/length(unique(by_comm$Date)),min.comm=min(count),med.comm=median(count),max.comm=max(count), y25=quantile(count, 0.25),y75=quantile(count, 0.75),var.comm=var(count), sd.comm=sd(count)) by_comm<-arrange(by_comm,desc(mean.comm)) head(by_comm)
The code below is used to create a boxplot for each community showing some of the summary statistics for each community.area for the year of 2016. As is shown by the boxplot the community areas 25, 8, and 28 have very high rates of crime compared to other community areas. ggplot() and geom_boxplot() are used.
options(repr.plot.width = 40, repr.plot.height=6) ggplot(by_comm, aes(x = as.factor(Community.Area))) + geom_boxplot(aes( lower = y25, upper = y75, middle = med.comm, ymin = min.comm, ymax = max.comm), stat = "identity")
The code below filters the dataset to only show homicides for 2016 from January 1st to January 24th using the filter() function and finally filters the dataset to show homicides within the same time period for the year January 2017 using the filter() function. This is to check the validity of Trump's claim that homicides in Chicago are up.
count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312015) & as_date(DateTime) < mdy(01252016))), Primary.Type == 'HOMICIDE')) count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312016) & as_date(DateTime) < mdy(01252017))), Primary.Type == 'HOMICIDE'))
This was done to test the validity of a comment Trump made about the rising number of homicides in Chicago. It appears that he was telling the truth, that homicides in Chicago have been on the rise during the time period Trump specified from 2016 to 2017. However, during this time period homicides rose 22% from 2016 not 24% and there were actually 45 homicides rather than 42 in 2017.
The code below is filtered using the filter() function to show different types of crime that were handgun related during the time period Trump suggested that there was 228 shootings.
count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312016) & as_date(DateTime) < mdy(01252017))), Primary.Type == 'ATTEMPT AGG: HANDGUN')) count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312016) & as_date(DateTime) < mdy(01252017))), Primary.Type == 'AGGRAVATED PO:HANDGUN')) count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312016) & as_date(DateTime) < mdy(01252017))), Primary.Type == 'ATTEMPT: ARMED-HANDGUN')) count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312016) & as_date(DateTime) < mdy(01252017))), Primary.Type == 'AGG PRO.EMP: HANDGUN')) count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312016) & as_date(DateTime) < mdy(01252017))), Primary.Type == 'AGGRAVATED:HANDGUN')) count(filter((filter(chicago.crime.test, as_date(DateTime) > mdy(12312016) & as_date(DateTime) < mdy(01252017))), Primary.Type == 'AGGRAVATED DOMESTIC BATTERY: HANDGUN'))
It appears as if Trump fabricated his data about shootings in Chicago for 2017 as there were no crimes involving handguns from January 1 2017 to the day Trump tweeted that he 'should call in the feds for Chicago'.