Vai al contenuto principale

Tutorial sulla regressione logistica in R

Scopri tutto sulla regressione logistica: in cosa differisce dalla regressione lineare, come adattare e valutare questi modelli in R con la funzione glm() e altro ancora!
· 14 min leggi

Scopri con l'IA

Esegui e modifica il codice da questo tutorial online

Esegui codice

La regressione logistica è un modello semplice ma potente per prevedere esiti binari. Cioè, se qualcosa accadrà oppure no. È un tipo di modello di classificazione per l’apprendimento supervisionato.

La regressione logistica è usata in quasi tutti i settori—marketing, sanità, scienze sociali e altri—ed è una parte essenziale della cassetta degli attrezzi di ogni data scientist.

Per ottenere il massimo da questo tutorial ti serve una conoscenza di base operativa di R. Aiuta anche conoscere un modello correlato, la regressione lineare. Leggi il Tutorial sulla regressione lineare in R per saperne di più.

Panoramica della regressione logistica

Supponiamo tu voglia prevedere se oggi sarà una giornata di sole o no. Ci sono due possibili esiti: "soleggiato" o "non soleggiato". La variabile di esito è anche nota come "variabile target" o "variabile dipendente".

Ci sono molte variabili che potrebbero influenzare l’esito, come "temperatura del giorno prima", "pressione atmosferica", ecc. Le variabili che influenzano sono note come feature, variabili indipendenti o predittori—tutti questi termini significano la stessa cosa. 

Altri esempi includono se un cliente acquisterà o meno il tuo prodotto, se un’email è spam o no, se una transazione è fraudolenta o no, e se un farmaco curerà un paziente o no.  

Come funziona la regressione logistica?

La regressione logistica trova il miglior possibile adattamento tra variabili predittive e target per prevedere la probabilità che la variabile target appartenga a una classe/categoria etichettata. 

La regressione lineare cerca di trovare la migliore retta che predice l’esito a partire dalle feature. Forma un’equazione come

y_predictions = intercept + slope * features

e usa l’ottimizzazione per cercare di trovare i migliori valori possibili di intercetta e pendenza.

La regressione logistica funziona in modo simile, tranne per il fatto che esegue la regressione sulle probabilità dell’esito di appartenere a una categoria. Usa una funzione sigmoide (la funzione di ripartizione cumulativa della distribuzione logistica) per trasformare il lato destro di quell’equazione.

y_predictions = logistic_cdf(intercept + slope * features)

Anche qui, il modello usa l’ottimizzazione per cercare i migliori valori possibili di intercetta e pendenza.

Poiché l’algoritmo della regressione logistica è molto simile all’equazione della regressione lineare, fa parte di una famiglia di modelli chiamati "modelli lineari generalizzati". È per questo che la regressione logistica ha "regressione" nel nome, anche se è un modello di classificazione.

La funzione sigmoide assomiglia a una curva a S nell’immagine qui sotto. Prende valori reali in ingresso e li converte tra 0 e 1 (restringendo da entrambi i lati, cioè i valori negativi verso 0 e quelli positivi molto alti verso 1). Inoltre, la soglia di cut-off è il fattore decisivo sovrapposto che raggruppa l’output in categorie o classi quando applicata su queste probabilità.

image4.png

I concetti complessi si capiscono meglio con esempi, quindi usiamo un’analogia per fissare il funzionamento dell’algoritmo di RL. Supponiamo che il modello di RL abbia il compito di identificare una transazione fraudolenta osservando diversi indicatori di frode, come la posizione dell’utente, l’importo dell’acquisto, l’indirizzo IP, ecc. L’obiettivo è determinare la probabilità che una data transazione sia legittima o fraudolenta – questa è la variabile target.

Il modello assegna pesi ai predittori in base a come influenzano la variabile target e li combina per calcolare il punteggio normalizzato o la probabilità di frode. 

Il dataset

Useremo un dataset di campagne di marketing diretto di un istituto bancario portoghese tramite chiamate telefoniche. La campagna mira a vendere sottoscrizioni di un deposito a termine bancario rappresentate dalla variabile y (sottoscrizione o non sottoscrizione). L’obiettivo del modello di regressione logistica è prevedere se un cliente acquisterà una sottoscrizione o no in base alle variabili predittive, cioè agli attributi del cliente, come le informazioni demografiche.

image1.png

Il data dictionary per questo dataset e molti altri dataset utili si trova sul sito di Datacamp.

Variabile

Descrizione

Dettagli

age

età del cliente

 

job

tipo di lavoro

categorica: "admin.","blue-collar","entrepreneur","housemaid","management","retired","self-employed","services","student","technician","unemployed","unknown"

marital

stato civile

categorica: "divorced","married","single","unknown"; nota: "divorced" significa divorziato o vedovo

education

titolo di studio più alto del cliente

categorica: "basic.4y","basic.6y","basic.9y","high.school","illiterate","professional.course","university.degree","unknown"

default

ha crediti in sofferenza?

categorica: "no","yes","unknown"

housing

ha un mutuo sulla casa?

categorica: "no","yes","unknown"

loan

ha un prestito personale?

categorica: "no","yes","unknown"

contact

tipo di comunicazione del contatto

categorica: "cellular","telephone"

month

mese dell’ultimo contatto dell’anno

categorica: "jan", "feb", "mar", ..., "nov", "dec"

day_of_week

giorno della settimana dell’ultimo contatto

categorica: "mon","tue","wed","thu","fri"

campaign

numero di volte in cui il cliente è stato contattato durante questa campagna

numerica, include l’ultimo contatto

pdays

numero di giorni dall’ultimo contatto del cliente in una campagna precedente

numerica; 999 significa che il cliente non è stato contattato in precedenza

previous

numero di contatti effettuati prima di questa campagna per questo cliente

numerica

poutcome

esito della precedente campagna di marketing

categorica: "failure","nonexistent","success"

emp.var.rate

tasso di variazione dell’occupazione - indicatore trimestrale

numerica

cons.price.idx

indice dei prezzi al consumo - indicatore mensile

numerica

cons.conf.idx

indice di fiducia dei consumatori - indicatore mensile

numerica

euribor3m

tasso euribor a 3 mesi - indicatore giornaliero

numerica

nr.employed

numero di occupati - indicatore trimestrale

numerica

y

il cliente ha sottoscritto un deposito a termine?

binaria: "yes","no"

Flusso di lavoro per la regressione logistica

L’intero flusso di lavoro di machine learning è trattato nell’infografica Guida per principianti al flusso di lavoro del machine learning. Qui ci concentreremo sulla preparazione dei dati e sui passaggi di modellazione. In particolare, vedremo:

  • Suddivisione dei dati in set di training e di test
  • Adattamento (training) del modello
  • Generazione di previsioni
  • Valutazione delle prestazioni del modello
  • Ottimizzazione degli iperparametri

Pacchetti per la regressione logistica

In R, esistono due flussi di lavoro popolari per modellare la regressione logistica: base-R e tidymodels.

Il flusso di lavoro base-R è più semplice e include funzioni come glm() e summary() per adattare il modello e generare un riepilogo del modello.

Il flusso di lavoro tidymodels consente una gestione più semplice di più modelli e un’interfaccia coerente per lavorare con diversi tipi di modello.

Questo tutorial userà il flusso di lavoro tidymodels.

Visualizzare i dati

Importa il pacchetto tidymodels chiamando la funzione library(). 

Il dataset è in un file CSV con formattazione in stile europeo (virgole per i decimali e punti e virgola come separatori). Lo leggeremo con read_csv2() dal pacchetto readr. 

Converti la variabile target, y, in una variabile factor per la modellazione. 

Usando la funzione ggplot() traccia il conteggio di ogni professione (job) rispetto a y.

library(readr)
library(tidymodels)

# Read the dataset and convert the target variable to a factor
bank_df <- read_csv2("bank-full.csv")
bank_df$y = as.factor(bank_df$y)

# Plot job occupation against the target variable
ggplot(bank_df, aes(job, fill = y)) +
    geom_bar() +
    coord_flip()

image5.png

Suddividere i dati

Dividiamo il dataset in un set di training per adattare il modello e un set di test per valutarlo, in modo da assicurarci che il modello così addestrato funzioni su dati non visti.

La suddivisione in training e test può essere effettuata usando la funzione initial_split() e l’attributo prop che definisce la proporzione di dati di training.

# Split data into train and test
set.seed(421)
split <- initial_split(bank_df, prop = 0.8, strata = y)
train <- split %>% 
         training()
test <- split %>% 
        testing()

Adattare e valutare il modello

Per creare il modello, dichiara un modello logistic_reg(). Richiede gli argomenti mixture e penalty che controllano la quantità di regolarizzazione. Un valore di mixture pari a 1 indica un modello lasso e 0 indica una ridge regression. Sono ammessi anche valori intermedi. L’argomento penalty indica l’intensità della regolarizzazione.

Nota che devi passare numeri in virgola mobile di tipo "double" a mixture e penalty

Imposta l’"engine" (il software backend usato per eseguire i calcoli) con set_engine(). Ci sono diverse opzioni: l’engine predefinito è "glm", che esegue una regressione logistica classica. È spesso preferito dagli statistici perché fornisce p-value per ciascun coefficiente, il che rende più semplice capire l’importanza di ogni coefficiente.

Qui useremo l’engine "glmnet". È preferito dagli esperti di machine learning perché consente la regolarizzazione, che può migliorare le previsioni, in particolare se hai molte feature. (In Python, il pacchetto scikit-learn include per impostazione predefinita un po’ di regolarizzazione nella regressione logistica.)

Chiama il metodo fit() per addestrare il modello sui dati di training creati nel passaggio precedente. Questo accetta una formula come primo argomento. Sul lato sinistro della formula usi la variabile target (in questo caso y). Sul lato destro puoi includere qualsiasi feature desideri. Un punto significa "usa tutte le variabili che non sono state scritte sul lato sinistro della formula". Per maggiori informazioni sulla scrittura delle formule, leggi il Tutorial sulle formule in R.

# Train a logistic regression model
model <- logistic_reg(mixture = double(1), penalty = double(1)) %>%
  set_engine("glmnet") %>%
  set_mode("classification") %>%
  fit(y ~ ., data = train)

# Model summary
tidy(model)

L’output è mostrato sotto, con la colonna estimate che rappresenta i coefficienti dei predittori.

# A tibble: 43 × 3
   term              estimate penalty
   <chr>                <dbl>   <dbl>
 1 (Intercept)      -2.59           0
 2 age              -0.000477       0
 3 jobblue-collar   -0.183          0
 4 jobentrepreneur  -0.206          0
 5 jobhousemaid     -0.270          0
 6 jobmanagement    -0.0190         0
 7 jobretired        0.360          0
 8 jobself-employed -0.101          0
 9 jobservices      -0.105          0
10 jobstudent        0.415          0
# ... with 33 more rows
# ℹ Use `print(n = ...)` to see more rows

Fare previsioni

Effettua previsioni sui dati di test usando la funzione predict(). Hai la possibilità di scegliere il tipo di previsione.

  • type = "class" restituisce il valore target più probabile per ogni osservazione. Qui restituirà "yes" o "no" a seconda che il modello ritenga che il cliente sia propenso o meno a sottoscrivere un deposito a termine.
  • type = "prob" restituisce la probabilità di ciascun valore target per ogni osservazione. Qui restituirà la probabilità di "yes" e la probabilità di "no" (che sommano a uno per ogni osservazione).
# Class Predictions
pred_class <- predict(model,
                      new_data = test,
                      type = "class")

# Class Probabilities
pred_proba <- predict(model,
                      new_data = test,
                      type = "prob")

Valuta il modello usando la funzione accuracy() con l’argomento truth impostato a y e l’argomento estimate impostato alle previsioni del passaggio precedente.

results <- test %>%
           select(y) %>%
           bind_cols(pred_class, pred_proba)

accuracy(results, truth = y, estimate = .pred_class)

Ottimizzazione degli iperparametri

Invece di passare valori specifici agli argomenti mixture e penalty (gli "iperparametri"), puoi ottimizzare il potere predittivo del modello eseguendone il tuning. 

L’idea è eseguire il modello molte volte con valori diversi degli iperparametri e vedere quale offre le previsioni migliori.

  • Nella funzione logistic_reg(), imposta gli argomenti mixture e penalty con una chiamata a tune().
  • Usa la funzione grid_regular() per definire una griglia di valori possibili per mixture e penalty.
  • La funzione workflow() crea un oggetto per memorizzare i dettagli del modello, utile quando lo esegui molte volte. 
  • Scegli il modello migliore usando la funzione select_best(). Puoi scegliere tra varie metriche che definiscono il "migliore". Qui useremo la metrica "area sotto la curva ROC" (ROC AUC).
# Define the logistic regression model with penalty and mixture hyperparameters
log_reg <- logistic_reg(mixture = tune(), penalty = tune(), engine = "glmnet")

# Define the grid search for the hyperparameters
grid <- grid_regular(mixture(), penalty(), levels = c(mixture = 4, penalty = 3))

# Define the workflow for the model
log_reg_wf <- workflow() %>%
  add_model(log_reg) %>%
  add_formula(y ~ .)

# Define the resampling method for the grid search
folds <- vfold_cv(train, v = 5)

# Tune the hyperparameters using the grid search
log_reg_tuned <- tune_grid(
  log_reg_wf,
  resamples = folds,
  grid = grid,
  control = control_grid(save_pred = TRUE)
)

select_best(log_reg_tuned, metric = "roc_auc")
# A tibble: 1 × 3
       penalty mixture .config              
         <dbl>   <dbl> <chr>                
1 0.0000000001       0 Preprocessor1_Model01

Altre metriche di valutazione

Usando i migliori iperparametri:

  1. Alleniamo un modello di regressione logistica
  2. Usiamolo per generare previsioni sul set di test
  3. Creiamo una matrice di confusione usando i valori reali e le stime
# Fit the model using the optimal hyperparameters
log_reg_final <- logistic_reg(penalty = 0.0000000001, mixture = 0) %>%
                 set_engine("glmnet") %>%
                 set_mode("classification") %>%
                 fit(y~., data = train)

# Evaluate the model performance on the testing set
pred_class <- predict(log_reg_final,
                      new_data = test,
                      type = "class")
results <- test %>%
  select(y) %>%
  bind_cols(pred_class, pred_proba)

# Create confusion matrix
conf_mat(results, truth = y,
         estimate = .pred_class)
Truth
Prediction   no  yes
       no  7838  738
       yes  147  320

Puoi calcolare la precision (valore predittivo positivo, il numero di veri positivi diviso per il numero di positivi previsti) con la funzione precision().

precision(results, truth = y,
          estimate = .pred_class)
# A tibble: 1 × 3
  .metric   .estimator .estimate
  <chr>     <chr>          <dbl>
1 precision binary         0.914

Allo stesso modo, puoi calcolare la recall (sensibilità, il numero di veri positivi diviso per il numero di positivi reali) con la funzione recall().

recall(results, truth = y,
          estimate = .pred_class)
# A tibble: 1 × 3
  .metric .estimator .estimate
  <chr>   <chr>          <dbl>
1 recall  binary         0.982

Capiremmo ora quali variabili influenzano la decisione di acquistare la sottoscrizione. In uno scenario di regressione logistica, i coefficienti determinano quanto la variabile target sia sensibile ai singoli predittori. Più alto è il valore dei coefficienti, maggiore è la loro importanza. Ordina le variabili in ordine decrescente del valore assoluto dei loro coefficienti e mostra solo i coefficienti con valore assoluto superiore a 0,5.

coeff <- tidy(log_reg_final) %>% 
  arrange(desc(abs(estimate))) %>% 
  filter(abs(estimate) > 0.5)
# A tibble: 10 × 3
   term            estimate      penalty
   <chr>              <dbl>        <dbl>
 1 (Intercept)       -2.59  0.0000000001
 2 poutcomesuccess    2.08  0.0000000001
 3 monthmar           1.62  0.0000000001
 4 monthoct           1.08  0.0000000001
 5 monthsep           1.03  0.0000000001
 6 contactunknown    -1.01  0.0000000001
 7 monthdec           0.861 0.0000000001
 8 monthjan          -0.820 0.0000000001
 9 housingyes        -0.550 0.0000000001
10 monthnov          -0.517 0.0000000001

Rappresenta graficamente l’importanza delle feature usando la funzione ggplot().

ggplot(coeff, aes(x = term, y = estimate, fill = term)) + geom_col() + coord_flip()

image2.png

Fai un passo oltre

Con questo, siamo arrivati alla fine di questo tutorial che ha mostrato come addestrare e valutare un modello di regressione logistica usando il pacchetto tidymodels. Abbiamo anche visto come interpretare i risultati del modello e rappresentarli graficamente, ad esempio con l’importanza delle feature. 

Se sei curioso di approfondire la modellazione di modelli di AI con tidymodels, dai un’occhiata al corso Modeling with tidymodels in R. Per la modellazione con l’approccio base-R, dai un’occhiata ai corsi Introduction to Regression in R, Intermediate Regression in R e Generalized Linear Models in R.

Argomenti

Correlato