Corso
Introduzione: Machine Learning in R
Il machine learning è un ramo dell’informatica che studia la progettazione di algoritmi in grado di apprendere. I compiti tipici includono l’apprendimento di concetti, l’apprendimento di funzioni o “modellazione predittiva”, il clustering e l’individuazione di pattern predittivi. Questi compiti vengono appresi a partire da dati disponibili, osservati attraverso esperienze o istruzioni, per esempio. Il machine learning punta a migliorare l’apprendimento includendo l’esperienza nei propri compiti. L’obiettivo finale è rendere l’apprendimento così efficace da diventare automatico, in modo che persone come noi non debbano più intervenire.
Questo breve tutorial ha lo scopo di introdurti alle basi del machine learning in R: più nello specifico, ti mostrerà come usare R per lavorare con il noto algoritmo di machine learning chiamato “KNN” o k-nearest neighbors.
Se ti interessa seguire un corso, dai un’occhiata alla nostra Introduction to Machine Learning with R o al corso di DataCamp Unsupervised Learning in R!
Usare R per k-Nearest Neighbors (KNN)
L’algoritmo KNN o k-nearest neighbors è uno dei più semplici algoritmi di machine learning ed è un esempio di apprendimento basato sulle istanze: i nuovi dati vengono classificati in base a istanze memorizzate ed etichettate.
Più precisamente, la distanza tra i dati memorizzati e la nuova istanza viene calcolata tramite una misura di similarità. Questa misura è in genere espressa come distanza, ad esempio la distanza euclidea, la similarità del coseno o la distanza di Manhattan.
In altre parole, per ogni nuovo punto dati che inserisci nel sistema viene calcolata la similarità rispetto ai dati già presenti.
Quindi, usi questo valore di similarità per fare modellazione predittiva. La modellazione predittiva può essere classificazione, cioè assegnare un’etichetta o una classe alla nuova istanza, oppure regressione, cioè assegnare un valore alla nuova istanza. Se classifichi o assegni un valore dipende ovviamente da come imposti il tuo modello con KNN.
L’algoritmo dei k vicini più prossimi aggiunge a questo schema di base il fatto che, dopo aver calcolato la distanza del nuovo punto da tutti i punti memorizzati, i valori delle distanze vengono ordinati e si determinano i k vicini più prossimi. Si raccolgono le etichette di questi vicini e si usa un voto di maggioranza o un voto pesato per fini di classificazione o regressione.
In altre parole, più alto è il punteggio per un certo punto dati già memorizzato, più è probabile che la nuova istanza riceva la stessa classificazione di quel vicino. Nel caso della regressione, il valore assegnato al nuovo punto dati è la media dei suoi k vicini più prossimi.
Primo passo. Procurati i dati
Il machine learning di solito parte da dati osservati. Puoi usare un tuo dataset oppure cercarne uno da altre fonti.
Dataset integrati di R
Questo tutorial usa il dataset Iris, molto noto nell’ambito del machine learning. Questo dataset è integrato in R, quindi puoi dargli un’occhiata digitando il seguente comando in console:
UC Irvine Machine Learning Repository
Se preferisci scaricare il dataset invece di usare quello integrato in R, puoi andare allo UC Irvine Machine Learning Repository e cercare il dataset Iris.
Consiglio: non limitarti a controllare la cartella dei dati del dataset Iris, ma dai anche un’occhiata alla pagina di descrizione dei dati!
Quindi, usa il seguente comando per caricare i dati:
Il comando legge dal sito il file .csv, ovvero “Comma Separated Value”. L’argomento header è impostato su FALSE, il che significa che il dataset Iris da questa fonte non fornisce i nomi degli attributi.
Al posto dei nomi degli attributi, quando ispezioni l’oggetto iris con una funzione come head(), potresti vedere nomi di colonna strani come “V1” o “V2”. Sono assegnati in modo arbitrario.
Per semplificare il lavoro con il dataset, è una buona idea assegnare tu stesso i nomi delle colonne: puoi farlo con la funzione names(), che legge o imposta i nomi di un oggetto. Concatena i nomi degli attributi come vuoi che compaiano. Nel blocco di codice sopra, avrai elencato Sepal.Length, Sepal.Width, Petal.Length, Petal.Width e Species.
Ancora una volta, questi nomi non spuntano dal nulla: consulta la descrizione del dataset linkata sopra; di solito troverai elencati proprio questi nomi.
Secondo passo. Conosci i tuoi dati
Ora che hai caricato il dataset Iris in RStudio, dovresti cercare di capirne a fondo il contenuto. Limitarsi a guardare o leggere qualcosa sui dati non basta per iniziare!
Rimboccati le maniche: esplora e visualizza il dataset e, se ti sembra troppo ostico, acquisisci anche un po’ di conoscenza del dominio.
Probabilmente possiedi già le nozioni che ti servono, ma come promemoria: tutti i fiori hanno un sepalo e un petalo. Il sepalo racchiude i petali ed è tipicamente verde e simile a una foglia, mentre i petali sono solitamente foglie colorate. Per i fiori di iris, è un po’ diverso, come puoi vedere nell’immagine seguente:

Panoramica iniziale del dataset
Per iniziare, puoi farti un’idea dei dati creando alcuni grafici, come istogrammi o boxplot. In questo caso, però, gli scatter plot possono darti un’ottima percezione di ciò che hai di fronte: è interessante vedere quanto una variabile sia influenzata da un’altra.
In altre parole, vuoi verificare se c’è correlazione tra due variabili.
Puoi creare scatter plot, per esempio, con il ggvis package.
Nota: prima devi caricare il pacchetto ggvis:
# Load in `ggvis`
library(ggvis)
# Iris scatter plot
iris %>% ggvis(~Sepal.Length, ~Sepal.Width, fill = ~Species) %>% layer_points()

Si vede che c’è un’alta correlazione tra la lunghezza e la larghezza del sepalo dei fiori di iris Setosa, mentre la correlazione è un po’ meno marcata per i fiori Virginica e Versicolor: i punti sono più sparsi sul grafico e non formano un cluster come nel caso dei fiori Setosa.
Lo scatter plot che mappa la lunghezza e la larghezza del petalo racconta una storia simile:
iris %>% ggvis(~Petal.Length, ~Petal.Width, fill = ~Species) %>% layer_points()

Questo grafico indica una correlazione positiva tra lunghezza e larghezza del petalo per tutte le diverse specie incluse nel dataset Iris. Ovviamente, dovrai probabilmente testare ulteriormente questa ipotesi se vuoi esserne davvero sicuro:
Quando combini tutte e tre le specie, la correlazione risulta un po’ più forte rispetto a quando le guardi separatamente: la correlazione complessiva è 0,96, mentre per Versicolor è 0,79. Setosa e Virginica, invece, hanno correlazioni tra lunghezza e larghezza del petalo pari rispettivamente a 0,31 e 0,32 arrotondando i numeri.
Consiglio: curioso di ggvis, grafici o istogrammi in particolare? Scopri il nostro tutorial sugli istogrammi e/o il corso ggvis.
Dopo una panoramica generale visuale dei dati, puoi anche visualizzare il dataset digitando
Tuttavia, come vedrai dal risultato di questo comando, non è il modo migliore per ispezionare a fondo il dataset: occupa molto spazio in console, impedendoti di farti un’idea chiara. È quindi meglio ispezionarlo eseguendo head(iris) o str(iris).
Nota che l’ultimo comando ti aiuta a distinguere chiaramente il tipo di dato num e i tre livelli dell’attributo Species, che è un fattore. Questo è molto comodo, dato che molti classificatori di machine learning in R richiedono che la variabile target sia codificata come fattore.
Ricorda che le variabili fattoriali rappresentano variabili categoriche in R. Possono quindi assumere un numero limitato di valori diversi.
Un rapido sguardo all’attributo Species ti dice che la ripartizione delle specie di fiori è 50-50-50. Se invece vuoi controllare la ripartizione percentuale di Species, puoi chiedere una tabella di proporzioni:
Nota che l’argomento round arrotonda i valori del primo argomento, prop.table(table(iris$Species))*100, al numero di cifre specificato, qui una cifra dopo la virgola. Puoi modificarlo facilmente cambiando il valore dell’argomento digits.
Comprensione approfondita dei dati
Non fermiamoci a questa panoramica di alto livello! R ti permette di andare più a fondo con la funzione summary(). Per i tipi numerici, questa fornisce valore minimo, primo quartile, mediana, media, terzo quartile e valore massimo del dataset Iris. Per la variabile di classe, restituisce il conteggio dei fattori:
Come vedi, alla chiamata originale è stata aggiunta la funzione c(): le colonne petal width e sepal width vengono concatenate e si chiede un summary solo di queste due colonne del dataset Iris.
Terzo passo. Dove andare adesso?
Dopo aver acquisito una buona comprensione dei dati, devi decidere i casi d’uso rilevanti per il tuo dataset. In altre parole, pensa a cosa i tuoi dati possono insegnarti o a cosa ritieni di poter imparare. Da lì, puoi valutare quali algoritmi applicare per ottenere i risultati che pensi di poter raggiungere.
Consiglio: più conosci i tuoi dati, più sarà facile definire i casi d’uso per il tuo dataset specifico. Lo stesso vale per trovare l’algoritmo di machine learning appropriato.
Per questo tutorial, il dataset Iris verrà usato per la classificazione, un esempio di modellazione predittiva. L’ultimo attributo del dataset, Species, sarà la variabile target, ossia la variabile che vuoi prevedere in questo esempio.
Nota che puoi anche prendere una delle variabili numeriche come target se vuoi usare KNN per fare regressione.
Quarto passo. Prepara il tuo ambiente di lavoro
Molti algoritmi usati nel machine learning non sono incorporati di default in R. Molto probabilmente dovrai scaricare i pacchetti che vuoi usare quando inizi con il machine learning.
Consiglio: hai un’idea di quale algoritmo usare, ma non di quale pacchetto ti serve? Puoi trovare una panoramica abbastanza completa di tutti i pacchetti usati in R proprio qui.
Per illustrare l’algoritmo KNN, questo tutorial usa il pacchetto class:
Se non hai ancora questo pacchetto, puoi installarlo in modo rapido e semplice digitando la seguente riga di codice:
install.packages("<package name>")
Ricorda il consiglio da nerd: se non sei sicuro di averlo, puoi eseguire il seguente comando per scoprirlo!
any(grepl("<name of your package>", installed.packages()))
Quinto passo. Prepara i tuoi dati
Dopo aver esplorato i dati e preparato l’ambiente di lavoro, puoi finalmente tornare al compito principale: costruire un modello di machine learning. Tuttavia, prima di farlo, è importante preparare anche i dati. La sezione seguente illustra due modi per farlo: normalizzando i dati (se necessario) e suddividendoli in set di training e test.
Normalizzazione
Nell’ambito della preparazione dei dati, potresti doverli normalizzare per renderli coerenti. Per questo tutorial introduttivo, ricorda solo che la normalizzazione facilita l’apprendimento per l’algoritmo KNN. Esistono due tipi di normalizzazione:
- la normalizzazione per esempio (example normalization) è l’adeguamento di ciascun esempio individualmente, mentre
- la normalizzazione per caratteristica (feature normalization) indica che adegui ciascuna feature allo stesso modo in tutti gli esempi.
Quando devi normalizzare il tuo dataset?
In breve: quando sospetti che i dati non siano coerenti.
Puoi accorgertene facilmente guardando i risultati della funzione summary(). Osserva i valori minimi e massimi di tutti gli attributi numerici. Se vedi che un attributo ha un ampio intervallo di valori, dovrai normalizzare il dataset, perché la distanza sarà dominata da quella feature.
Per esempio, se il tuo dataset ha solo due attributi, X e Y, e X ha valori tra 1 e 1000, mentre Y ha valori tra 1 e 100, l’influenza di Y sulla funzione di distanza verrà di solito sovrastata da quella di X.
Quando normalizzi, in pratica adegui l’intervallo di tutte le feature, così che le distanze tra variabili con range più ampi non vengano enfatizzate eccessivamente.
Consiglio: torna al risultato di summary(iris) e prova a capire se la normalizzazione è necessaria.
Il dataset Iris non ha bisogno di normalizzazione: l’attributo Sepal.Length ha valori da 4,3 a 7,9 e Sepal.Width contiene valori da 2 a 4,4, mentre i valori di Petal.Length vanno da 1 a 6,9 e quelli di Petal.Width da 0,1 a 2,5. Tutti i valori di tutti gli attributi sono compresi tra 0,1 e 7,9, un intervallo accettabile.
Nonostante ciò, è comunque una buona idea studiare la normalizzazione e i suoi effetti, soprattutto se sei agli inizi con il machine learning. Puoi effettuare la normalizzazione per feature, per esempio, creando prima una tua funzione normalize().
Puoi poi usare questo argomento in un altro comando, dove metti i risultati della normalizzazione in un data frame tramite as.data.frame() dopo che la funzione lapply() ha restituito una lista della stessa lunghezza del dataset dato in input. Ogni elemento della lista è il risultato dell’applicazione dell’argomento normalize al dataset fornito come input:
YourNormalizedDataSet <- as.data.frame(lapply(YourDataSet, normalize))
Mettilo alla prova nel blocco DataCamp Light qui sotto!
Per il dataset Iris, avresti applicato l’argomento normalize ai quattro attributi numerici del dataset (Sepal.Length, Sepal.Width, Petal.Length, Petal.Width) e messo i risultati in un data frame.
Consiglio: per illustrare meglio l’effetto della normalizzazione sul dataset, confronta il risultato seguente con il summary del dataset Iris mostrato al passo due.
Training e test set
Per valutare in seguito le prestazioni del tuo modello, dovrai dividere il dataset in due parti: un training set e un test set.
Il primo viene usato per addestrare il sistema, mentre il secondo per valutarlo una volta addestrato. In pratica, la divisione in training e test set è disgiunta: la scelta più comune è usare 2/3 del dataset originale come training set, mentre il terzo restante compone il test set.
Un’ultima occhiata al dataset ti insegna che, se effettuassi la divisione così com’è, potresti ottenere un training set con tutte le istanze di “Setosa” e “Versicolor”, ma nessuna di “Virginica”. Il modello classificerebbe quindi tutte le istanze sconosciute come “Setosa” o “Versicolor”, ignorando la presenza di una terza specie.
In breve, otterresti previsioni errate sul test set.
Devi quindi assicurarti che tutte e tre le classi di specie siano presenti nel modello di training. Inoltre, il numero di istanze delle tre specie deve essere più o meno uguale per non favorire una classe nelle previsioni.
Per creare training e test set, imposti prima un seed. È un numero del generatore di numeri casuali di R. Il vantaggio principale è che puoi ottenere la stessa sequenza di numeri casuali ogni volta che fornisci lo stesso seed al generatore.
set.seed(1234)
Poi, vuoi assicurarti che il dataset Iris sia mescolato e che tu abbia una quantità uguale di ciascuna specie nei training e test set.
Usi la funzione sample() per estrarre un campione con dimensione pari al numero di righe del dataset Iris, ossia 150. Esegui il campionamento con reinserimento: scegli da un vettore di 2 elementi e assegni 1 o 2 alle 150 righe del dataset. L’assegnazione è soggetta a pesi di probabilità 0,67 e 0,33.
ind <- sample(2, nrow(iris), replace=TRUE, prob=c(0.67, 0.33))
Nota che l’argomento replace è impostato su TRUE: significa che assegni 1 o 2 a una certa riga e poi ripristini il vettore di 2 al suo stato originale. Ciò significa che, per le righe successive, puoi assegnare di nuovo 1 o 2 ogni volta. La probabilità di scegliere 1 o 2 non deve essere proporzionale ai pesi tra gli elementi rimanenti, quindi specifichi i pesi. Nota anche che, sebbene non si veda nel blocco DataCamp Light, il seed è ancora impostato a 1234.
Ricorda che vuoi che il training set sia 2/3 del dataset originale: per questo assegni “1” con probabilità 0,67 e “2” con probabilità 0,33 alle 150 righe campionate.
Puoi poi usare il campione memorizzato nella variabile ind per definire training e test set:
Nota che, oltre alle proporzioni 2/3 e 1/3 specificate sopra, non consideri tutti gli attributi per formare training e test set. In particolare, prendi solo Sepal.Length, Sepal.Width, Petal.Length e Petal.Width. Questo perché vuoi prevedere il quinto attributo, Species: è la tua variabile target. Tuttavia, vuoi includerla nell’algoritmo KNN, altrimenti non ci sarebbe alcuna previsione per essa.
Devi quindi memorizzare le etichette di classe in vettori fattoriali e dividerle tra training e test set:
Sesto passo. Il modello KNN vero e proprio
Costruire il classificatore
Dopo tutti questi preparativi, ti sei assicurato che tutti i tuoi dati noti (di training) siano memorizzati. Finora non è stato costruito alcun modello né eseguito alcun apprendimento. Ora vuoi trovare i k vicini più prossimi del tuo training set.
Un modo semplice per fare questi due passaggi è usare la funzione knn(), che usa la distanza euclidea per trovare i k vicini più prossimi della tua nuova istanza sconosciuta. Qui, il parametro k lo imposti tu.
Come detto, le nuove istanze vengono classificate in base al voto di maggioranza o al voto pesato. Nel caso della classificazione, il punto dati con il punteggio più alto vince e l’istanza sconosciuta riceve l’etichetta del punto vincente. Se c’è parità, la classificazione avviene in modo casuale.
Nota: il parametro k è spesso un numero dispari per evitare pareggi nelle votazioni.
Per costruire il classificatore, prendi la funzione knn() e aggiungi semplicemente alcuni argomenti, come in questo esempio:
Memorizzi in iris_pred la funzione knn() che prende come argomenti il training set, il test set, le etichette di training e il numero di vicini che vuoi trovare con questo algoritmo. Il risultato è un vettore fattoriale con le classi predette per ogni riga dei dati di test.
Nota che non vuoi inserire le etichette di test: ti serviranno per verificare se il modello sa prevedere correttamente le classi effettive!
Quando ispezioni il risultato, iris_pred, ottieni il vettore con le classi predette per ogni riga dei dati di test.
Settimo passo. Valutazione del modello
Un passo essenziale nel machine learning è la valutazione delle prestazioni del modello. In altre parole, vuoi analizzare il grado di correttezza delle previsioni.
Per una vista più astratta, puoi semplicemente confrontare i risultati di iris_pred con le etichette di test definite in precedenza:
Si vede che il modello fa previsioni abbastanza accurate, con l’eccezione di una classificazione errata alla riga 29, dove è stato predetto “Versicolor” mentre l’etichetta di test è “Virginica”.
È già un’indicazione delle prestazioni del modello, ma potresti voler andare ancora più a fondo nell’analisi. A questo scopo puoi importare il pacchetto gmodels:
install.packages("package name")
Tuttavia, se lo hai già installato, puoi semplicemente digitare
library(gmodels)
Poi puoi creare una tabella incrociata o tabella di contingenza. Questo tipo di tabella è spesso usato per capire la relazione tra due variabili. In questo caso, vuoi capire come le classi dei tuoi dati di test, memorizzate in iris.testLabels, si relazionano al tuo modello memorizzato in iris_pred:
CrossTable(x = iris.testLabels, y = iris_pred, prop.chisq=FALSE)

Nota che l’ultimo argomento prop.chisq indica se includere o meno il contributo chi-quadro di ogni cella. La statistica chi-quadro è la somma dei contributi delle singole celle e serve per decidere se la differenza tra valori osservati e attesi è significativa.
Da questa tabella puoi ricavare il numero di previsioni corrette e errate: un’istanza del test set è stata etichettata Versicolor dal modello, mentre in realtà era una Virginica. Lo vedi nella prima riga della specie “Virginica” nella colonna iris.testLabels. In tutti gli altri casi, le previsioni sono corrette. Puoi concludere che le prestazioni del modello sono sufficienti e che non serve migliorarlo!
Machine Learning in R con caret
Nelle sezioni precedenti hai iniziato con l’apprendimento supervisionato in R tramite l’algoritmo KNN. Come avrai intuito, il machine learning in R può diventare davvero complesso, perché esistono vari algoritmi, sintassi diverse, parametri differenti, ecc. Forse sarai d’accordo che ricordare i nomi dei pacchetti per ogni algoritmo può essere difficile, e applicarne la sintassi specifica può risultare troppo.
È qui che il pacchetto caret può tornare utile: è l’acronimo di “Classification and Regression Training” e offre tutto ciò che ti serve per risolvere problemi di machine learning supervisionato: fornisce un’interfaccia uniforme a una miriade di algoritmi. Se conosci un po’ il machine learning in Python, potresti notare somiglianze con scikit-learn!
Di seguito ripercorrerai i passaggi descritti sopra, ma questa volta userai caret per classificare i tuoi dati. Nota che, se hai seguito i passaggi, hai già fatto molto del lavoro: hai compreso i dati, li hai esplorati, hai preparato l’ambiente, ecc. Ora è il momento di preprocessare i dati con caret!
Come in precedenza, puoi studiare l’effetto della normalizzazione, ma lo vedrai più avanti nel tutorial.
Il prossimo passo lo conosci già! Dividiamo i dati in training e test set. In questo caso, però, gestiamo la cosa in modo leggermente diverso: dividiamo i dati in base alle etichette in iris$Species. Inoltre, il rapporto è impostato a 75-25 per training e test.
Ora sei pronto per addestrare i modelli! Ma, come forse ricordi, caret è un progetto enorme che include molti algoritmi. Se hai dubbi su quali siano inclusi, puoi ottenere l’elenco completo. Visualizzalo eseguendo names(getModelInfo()), come mostrato nel blocco seguente. Poi scegli un algoritmo e addestra un modello con la funzione train():
Nota che creare altri modelli è estremamente semplice una volta arrivato fin qui; ti basta cambiare l’argomento method, proprio come in questo esempio:
model_cart <- train(iris.training[, 1:4], iris.training[, 5], method='rpart2')
Ora che hai addestrato il modello, è il momento di prevedere le etichette del test set che hai appena creato e valutare come si è comportato sui tuoi dati:
Inoltre, puoi provare lo stesso test di prima per esaminare l’effetto del preprocessing, come scaling e centering, sul tuo modello. Esegui il seguente blocco di codice:
Passa ai Big Data
Congratulazioni! Sei arrivato alla fine di questo tutorial!
Questo tutorial si è concentrato principalmente sull’esecuzione del semplice algoritmo di machine learning KNN con l’aiuto di R. Il dataset Iris usato era piccolo e gestibile; Non solo hai visto come eseguire da solo tutti i passaggi, ma hai anche visto come puoi usare facilmente un’interfaccia uniforme, come quella offerta da caret, per dare slancio al tuo machine learning.
Ma puoi fare molto di più!
Se hai sperimentato abbastanza con le basi presentate in questo tutorial e con altri algoritmi di machine learning, potresti voler approfondire R e l’analisi dei dati.


