Applicazioni pratiche di machine learning/Previsione di reati

Caricamento librerie

modifica
library(dplyr)
library(ggplot2)
library(caret)
library(h2o)


Parte 1: Dati

modifica

Il dataset crimes.csv scaricabile da qui : https://www.kaggle.com/AnalyzeBoston/crimes-in-boston contiene 317.751 records relativi a reati forniti dal Dipartimento di Polizia di Boston (BPD) con informazioni su dove e quando essi si sono verificati. Le variabili contenute nel dataset sono le seguenti :

  • INCIDENT_NUMBER:Numero interno dell'incidente stabilito da BPD
  • OFFENSE_CODE: Codice numerico della descrizione dell'incidente
  • OFFENSE_CODE_GROUP: Categoria interna per la descrizione dell'incidente
  • OFFENSE_DESCRIPTION:Descrizione primaria dell'incidente
  • DISTRICT:Quartiere in cui si è verificato l'incidente
  • REPORTING_AREA: Numero RA associato con il luogo in cui si è verificato l'incidente
  • SHOOTING:Indica se la registrazione è avvenuta nel luogo del fatto
  • OCCURRED_ON_DATE:Giorno e ora in cui l'incidente si è verificato
  • YEAR: Anno dell'incidente
  • MONTH: Mese dell'incidente
  • DAY_OF_WEEK:Giorno della settimana
  • HOUR:Ora
  • UCR_PART:Uniform Crime Report che può assumere 3 valori (Part 1,Part 2, Part 3).
    • Part 1 include crimini violenti e crimini contro il patrimonio. Ad esempio Aggressione aggravata , stupro forzato , omicidio e rapina mentre incendio doloso , furto con scasso , furto e furto di veicoli a motore sono classificati come reati contro il patrimonio.
    • Parte 2, vengono incluse le seguenti categorie: aggressione semplice, reati di coprifuoco e vagabondaggio, appropriazione indebita, falsificazione e contraffazione, condotta disordinata, guida sotto l'influenza di droghe, reati di droga, frode, gioco d'azzardo, reati di alcol, reati contro la famiglia, prostituzione, ubriachezza in pubblico, fughe, reati sessuali, beni rubati, atti vandalici, vagabondaggio e reati legati alle armi.
    • Parte 3 : Altro
  • STREET:Nome della strada in cui l'incidente si è verificato
  • Lat: Latitudine del luogo in cui si è verificato l'incidente
  • Long: Longitudine
  • Location:(Latitudine, Longitudine)

Caricamento dati:

crime <- read.csv("crime.csv")

Parte 2: Esplorazione dati

modifica
crime %>%
  filter(!is.na(OFFENSE_CODE_GROUP)) %>%
  group_by(OFFENSE_CODE_GROUP) %>%
  summarise(n=n()) %>%
  filter(n>200) %>%
  mutate(OFFENSE_CODE_GROUP=reorder(OFFENSE_CODE_GROUP,n))  %>%
  ggplot(aes(OFFENSE_CODE_GROUP,n))+
  geom_bar(stat="identity", fill="red")+
  coord_flip()+
 geom_text(aes(label=n), hjust=0, size=2)+
  guides(fill=FALSE)+
  ylab("Numero totale") +
  xlab("Crimine") +
  ggtitle("Tipo di incidenti o reati a Boston")
 
crime %>%
  group_by(STREET) %>%
  summarise(n=n()) %>%
  filter(n>800) %>%
  mutate(STREET=reorder(STREET,n))  %>%
  ggplot(aes(STREET,n, fill=STREET))+
  geom_bar(stat="identity", fill="blue")+
  coord_flip()+
 geom_text(aes(label=n), hjust=0, size=2)+
  guides(fill=FALSE)+
  ylab("Numero totale") +
  xlab("Strade") +
  ggtitle("Strade di Boston con più crimini")
 
crime %>%
  group_by(DISTRICT,UCR_PART) %>%
  summarise(n=n()) %>%
  filter(n>800) %>%
  mutate(STREET=reorder(DISTRICT,n))  %>%
  ggplot(aes(STREET,n, fill=UCR_PART))+
  geom_bar(stat="identity")+
  coord_flip()+
  ylab("Numero totale") +
  xlab("Quartieri") +
  ggtitle("Quartieri di Boston per UCR_PART")
 

Parte 3: Domanda di ricerca

modifica

Si vuole predire che tipo di reato verrà compiuto, cioè se di UCR_PART 1,2 o 3 in base al luogo e al tempo indicato. Quindi UCR_PART è la variabile da predire tramite le variabili : Lat, Long, YEAR, MONTH, HOUR, DAYS_OF_WEEK


Parte 4: Modellizzazione

modifica
crime$UCR_PART <- as.character(crime$UCR_PART)
crime<- crime[-which(crime$UCR_PART==""),]
crime<- crime[-which(crime$UCR_PART=="Other"),]
crime$UCR_PART <- as.factor(crime$UCR_PART)

Si dividono i dati in un training set costituito dal 70% dei records su cui si costruisce il modello e in un testing set costituito dal rimanente 30% su cui si testa il modello:


trainIndex <- createDataPartition(crime$UCR_PART,p=0.7, list = FALSE)
training <- crime[trainIndex,]
testing <- crime[-trainIndex,]
h2o.init()
H2O is not running yet, starting it now...
openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10-post-Ubuntu-0ubuntu120.04)
OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Ubuntu-0ubuntu120.04, mixed mode, sharing)
Starting H2O JVM and connecting: ..... Connection successful!
R is connected to the H2O cluster: 
   H2O cluster uptime:         6 seconds 187 milliseconds 
   H2O cluster timezone:       Europe/Rome 
   H2O data parsing timezone:  UTC 
   H2O cluster version:        3.30.1.3 
   H2O cluster version age:    8 days  
   H2O cluster name:           H2O_started_from_R_gian_vxl021 
   H2O cluster total nodes:    1 
   H2O cluster total memory:   1.92 GB 
   H2O cluster total cores:    2 
   H2O cluster allowed cores:  2 
   H2O cluster healthy:        TRUE 
   H2O Connection ip:          localhost 
   H2O Connection port:        54321 
   H2O Connection proxy:       NA 
   H2O Internal Security:      FALSE 
   H2O API Extensions:         Amazon S3, XGBoost, Algos, AutoML, Core V3, TargetEncoder, Core V4 
   R Version:                  R version 3.6.3 (2020-02-29)
training_hf <- as.h2o(training)
y <- "UCR_PART"
x <- c("Lat","Long", "YEAR" ,"MONTH" , "HOUR" , "DAY_OF_WEEK") 

aml <- h2o.automl(x = x, y = y,
                  training_frame = training_hf ,max_runtime_secs = 600)

I primi 6 modelli trovati sono i seguenti :

lb <- aml@leaderboard
lb
                                            model_id mean_per_class_error
1                    XGBoost_2_AutoML_20201007_033612            0.6050108
2                        DRF_1_AutoML_20201007_033612            0.6127668
3      XGBoost_grid__1_AutoML_20201007_033612_model_1            0.6195701
4                        XRT_1_AutoML_20201007_033612            0.6196397
5                        GBM_5_AutoML_20201007_033612            0.6269082
6 StackedEnsemble_BestOfFamily_AutoML_20201007_033612            0.6303185

Si calcola l'Accuracy dei primi 5 modelli :

test <- as.h2o(testing)
for (i in 1:5) {
  m<-h2o.getModel(lb[i,1])
  p1 = h2o.predict(m, newdata=test)
  df2 <- as.data.frame(p1$predict)
  print(mean(df2$predict==testing$UCR_PART))
}
 |======================================================================| 100%
 |======================================================================| 100%
[1] 0.5007081
 |======================================================================| 100%
[1] 0.4525141
 |======================================================================| 100%
[1] 0.519948
 |======================================================================| 100%
[1] 0.4719323
 |======================================================================| 100%
[1] 0.5122583
 |======================================================================| 100%

Il modello XGBoost_grid__1_AutoML_20201007_033612_model_1 ha l'Accuracy maggiore pari al 52% quindi lo si sceglie :

test <- as.h2o(testing)
model <- h2o.getModel(lb[3,1])
p1 = h2o.predict(model, newdata=test)
df2 <- as.data.frame(p1$predict)
confusionMatrix(df2$predict,testing$UCR_PART)
Confusion Matrix and Statistics
           Reference
Prediction   Part One Part Three Part Two
 Part One       1621        844      640
 Part Three    15359      43627    24315
 Part Two       1508       3094     4315
Overall Statistics
              Accuracy : 0.5199          
                95% CI : (0.5168, 0.5231)
   No Information Rate : 0.499           
   P-Value [Acc > NIR] : < 2.2e-16       
                 Kappa : 0.0924          
Mcnemar's Test P-Value : < 2.2e-16       
Statistics by Class:
                    Class: Part One Class: Part Three Class: Part Two
Sensitivity                  0.08768            0.9172         0.14742
Specificity                  0.98069            0.1693         0.93033
Pos Pred Value               0.52206            0.5237         0.48391
Neg Pred Value               0.81710            0.6724         0.71119
Prevalence                   0.19395            0.4990         0.30706
Detection Rate               0.01701            0.4577         0.04527
Detection Prevalence         0.03257            0.8739         0.09355
Balanced Accuracy            0.53418            0.5432         0.53887

Controversie sull'uso del modello

modifica

Se il modello viene usato per predire i reati "Parte 1" ossia i crimini violenti non c'è nulla da ridire, ma se si la polizia si concentra su quelli "Parte 2" che comprendono vagabondaggio, accattonaggio, consumo in modica quantità di stupefacenti o alcol c'è il rischio di concentrarsi sui quartieri degradati della città e arrestare persone povere che diventerebbero vittime civili del modello.[1]


  1. Cathy O'Neil, Armi di distruzione matematica, Saggi Bompiani.