Final Project

Author

Skylar Wong

Research Question: What factors are most influential in the type of crime that is committed in the DC-Metro area?

New Method: Support Vector Machines

To investigate whether different types of crimes are more likely to occur during specific times of day in the DC-Metro area, I used a Support Vector Machine (SVM) classification model. In essence, a SVM identifies “boundaries” that which find different categories within the data by determining the furthest distance between the closest points of these categories and draws a boundary (a hyper-plane) at this location.

My model was trained using factors such as the time_of_day: morning, afternoon, evening, and night, the method used in the crime, the offense committed, geographic coordinates (x and y), and the neighborhood_cluster in the DC-Metro area that the crime occurred in.

In the context of this problem, a ‘high’ classification accuracy would indicate that different types of crimes are associated with particular times of day, suggesting that time of day, or perhaps even the amount of daylight or visibility plays a significant role in a specific crime occurrence. Although, it is worth noting that a traditionally ‘high’ classification accuracy won’t necessarily be achieved in this model, as there are nine different offenses, with some having imbalanced classes (a lot of observations in some classes and not many in others).

Assessing the SVM Model Performance

Below is a confusion matrix that shows how well the SVM model predicted each type of crime based on the time of day. Each row represents the actual crime type, and each column shows the predicted crime type.

Looking at the confusion matrix, we can see that some classes were not predicted by the model, such as arson, which only had four total observations, which may not have been represented in the training data. However, considering that although there are nine crime categories, a theft-related crime accounts for about 67% of the total offenses committed in the data set, so the model would have a higher accuracy if it simply guessed a theft crime every time, but this is not a helpful tool.

In this context, the SVM’s 49% accuracy indicates that the model predicts some smaller classes, which indicates that time of day, the method used in the crime, and the neighborhood that the crime was committed in do have some predictive power in identifying what type of crime is committed.

Code
kable(as.table(confusionMatrix(preds2, factor(testing_data$offense))),
      caption = "Confusion Matrix: Predicted vs. Actual Offense")
Table 1: Confusion Matrix: Predicted vs. Actual Offense
arson assault w/dangerous weapon burglary homicide motor vehicle theft robbery sex abuse theft f/auto theft/other
arson 0 0 0 0 0 0 0 0 0
assault w/dangerous weapon 0 110 2 7 1 48 2 1 33
burglary 0 0 0 0 0 0 0 0 0
homicide 0 0 0 0 0 0 0 0 0
motor vehicle theft 0 2 11 2 114 13 3 72 77
robbery 0 318 4 78 12 611 8 21 19
sex abuse 0 0 0 0 0 0 0 0 0
theft f/auto 0 0 20 0 116 5 1 154 93
theft/other 3 59 481 10 2320 391 57 3115 6250

In-Class Methods: Random Forest and XGBoost

To further explore the relationship between crime type and factors like time of day, method, and neighborhood cluster, I used Random Forest and XGBoost models.

In this context, using these additional models allowed me to slightly improve the accuracy of predicting crime types (49% to about 51%), but also allowed me to understand which variables were ‘most important’ in determining the type of crime committed, which we can see appear to be location and time of day.

Below is the beeswarm plot created to assess how important each feature in the dataset was to the final prediction.

Code
sv_importance(crimes_shap_values, kind = "beeswarm")
Figure 1: Beeswarm Plot of Offenses

Conclusion

This project looked at how the time of day and other factors relate to different types of crimes in the DC-Metro area. Using the Support Vector Machine model, I found that while some patterns could be detected, the model’s accuracy was limited, likely because there are many types of crimes, some happening much more often than others, making it harder to predict the exact crime based only on the variables used.

To get another perspective on the dataset and try to improve my predictions, I also used Random Forest and XGBoost models. These models helped identify which factors, like time of day, method of crime, and neighborhood, were most important for understanding crime patterns.

Regarding which factors are most influential and the original research question, the analysis showed that the time of day and the location that the crime was committed in played significant roles. The method used in the crime also affected the offense committed, although not as influential as time of day and the location. Overall, these findings suggest that when and where a crime occurs, along with how it is carried out, all contribute to the kind of crime committed, highlighting that crime types do depend on time and place, but predicting them perfectly is challenging. Future studies could improve by adding more detailed information, such as weather, socio-economic conditions, or even data related to the offenders’ mental-states to better explain when and where different crimes happen.

Sources

  1. District of Columbia. Metropolitan Police Department. “Crime Incidents in 2024”. Data.gov, https://catalog.data.gov/dataset/crime-incidents-in-2024/resource/48eeb897-aa75-4d14-9f73-8765f6e7f93a. Accessed 20 May 2025.

  2. IBM. “What Are Support Vector Machines (SVMs)?” IBM Think, 27 Dec. 2023, https://www.ibm.com/think/topics/support-vector-machine. Accessed 20 May 2025.

Appendix

Code
crimes <- crime_data |>
  mutate(
    start_date_clean = str_remove(START_DATE, "\\+\\d+$"),
    time_parsed = as.POSIXct(start_date_clean, format = "%Y/%m/%d %H:%M:%S", tz = "UTC"),
    hour = as.integer(format(time_parsed, "%H")),
    time_of_day = case_when(
      hour >= 4 & hour < 12 ~ "Morning",
      hour >= 12 & hour < 18 ~ "Afternoon",
      hour >= 18 & hour < 21 ~ "Evening",
      TRUE ~ "Night"
    )) |>
  select(X, Y, METHOD, OFFENSE, time_of_day, NEIGHBORHOOD_CLUSTER) |>
  na.omit() |>
  clean_names() |>
  mutate(
    across(where(is.character), tolower),
    method = factor(method),
    offense = factor(offense),
    neighborhood_cluster = factor(neighborhood_cluster))

# Exploratory data analysis
crimes |>
  group_by(offense) |>
  count()
# A tibble: 9 × 2
# Groups:   offense [9]
  offense                        n
  <fct>                      <int>
1 arson                          4
2 assault w/dangerous weapon  1024
3 burglary                    1004
4 homicide                     187
5 motor vehicle theft         5127
6 robbery                     2110
7 sex abuse                    142
8 theft f/auto                6681
9 theft/other                13008
Code
# Test-train split
training_data_rows <- sample(1:nrow(crimes), size = nrow(crimes) / 2)
training_data <- crimes[training_data_rows, ]
testing_data <- crimes[-training_data_rows, ]

training_data |>
  group_by(offense) |>
  count()
# A tibble: 9 × 2
# Groups:   offense [9]
  offense                        n
  <fct>                      <int>
1 arson                          1
2 assault w/dangerous weapon   494
3 burglary                     504
4 homicide                      86
5 motor vehicle theft         2594
6 robbery                     1053
7 sex abuse                     69
8 theft f/auto                3324
9 theft/other                 6518
Code
# Build SVM model
crimes_svm2 <- svm(factor(offense) ~ factor(time_of_day) + method + neighborhood_cluster,
                   data = training_data,
                   scale = TRUE)
preds2 <- predict(crimes_svm2, newdata = testing_data, levels = levels(training_data$offense))