Capitolo 14 Alberi di Classificazione (Classification Trees: CTREE)

14.1 Introduzione

Gli alberi decisionali sono uno degli strumenti comuni per l’analisi esplorativa dei dati e la segmentazione.
Il grande vantaggio legato all’uso degli alberi decisionali è che il loro output è relativamente semplice da comprendere o interpretare.
I metodi basati su ableri possono essere usati sia per problemi di claossificazione che problemi di regressione. Questi problemi richiedono la stratificazione o segmentazione dello spazio dei predittori in un numero di regioni semplici. Una previsione per una data osservazione è quindi ottenuta tipicamente usando la media o la moda delle osservazioni di training nella regione in cui ricade l’osservazione.

Un modo semplice per comprendere gli alberi decisionali è quello di un approccio gerarchico per partizionare i dati di input: ad ogni nodo (step) si usa una sola variabile indipendente, con uno dei suoi valori, per generare la partizione.

Gli alberi di classificazione (CT) sono usati per prevedere una risposta qualitativa. Nei CT la previsione di una osservazione generalmente corrisponde alla classe più comune nelle osservazioni di training nella regione in cui ricade. Nell’interpretazione dei risultati di un albero di classificazione, usualmente siamo interessati alla previsione di una classe corrispondente alla regione di un particolare nodo terminale, ma anche alle proporzioni nelle numerosità tra le classi delle osservazioni di training che ricadono in quella stessa regione.

La costruzione di un albero segue usualmente un processo in due fasi: crescita (growth) e potatura (pruning).

Per far crescere un albero di classificazione, usualmente si adopera una suddivisione binaria. Per “spezzare” i nodi, si ricerca la “variabilità entro nodo” minima; la “variabilità” è usualmente misuratacon due indici alternativi:

  • l’indice di Gini, che fornisce una misura dell’incertezza totale tra le \(k\) classi; è spesso indicato anche con il nome di misura di “purezza” (“purity”) del nodo, poiché un valore piccolo indica che il nodo in maniera predominante osservazioni da una sola classe.

  • la cross-entropia, che, come l’indice di Gini, assume un valore piccolo se il nodo è puro.

Per “potare” l’albero, invece, è usato principalmente il tasso di errata classificazione, se l’obiettivo è quello dell’accuratezza della previsione.

Per migliorare l’accuratezza predittiva, si possono combinare più alberi per produrre una previsione aggregata. “Bagging”, “random forests” e “boosting” sono alcuni approcci che implementano una tale strategia. Il prezzo da pagare per l’accresciuta accuratezza è una perdita in interpretabilità.

Ci sono diversi package R con funzioni per costruire alberi di classificazione singoli. Uno dei più popolari è rpart.

Illustreremo questo package con qualche esempio.

14.2 Esempio: Dati iris

In questo esempio cercheremo di introdurre in maniera semplice il processo di costruzione dell’albero.
L’obiettivo dell’esempio è quello di prevedere ls specie corretta di iris date le misure di lunghezza e larghezza di petali e sepali.
Cominciamo quindi con un albero “quasi non potato”:

## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 ..
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

Possiamo controllare le regole e le suddivisioni (split) usando l’opzione control nella chiamata della funzione dell’algoritmo di rpart. Per esempio il numero minimo di osservazioni per un nodo perché questo sia considerato per uno split è impostabile tramite l’uso di minsplit. Il numero minimo di osservazioni per un nodo foglia (nodo non più suddivisibile) è impostabile tramite il parametro minbucket.
Ora stampiamo i contenuti dell’albero appena prodotto:

## n= 150 
## 
## node), split, n, loss, yval, (yprob)
##       * denotes terminal node
## 
##  1) root 150 100 setosa (0.33333333 0.33333333 0.33333333)  
##    2) Petal.Length< 2.45 50   0 setosa (1.00000000 0.00000000 0.00000000) *
##    3) Petal.Length>=2.45 100  50 versicolor (0.00000000 0.50000000 0.50000000)  
##      6) Petal.Width< 1.75 54   5 versicolor (0.00000000 0.90740741 0.09259259)  
##       12) Petal.Length< 4.95 48   1 versicolor (0.00000000 0.97916667 0.02083333)  
##         24) Petal.Width< 1.65 47   0 versicolor (0.00000000 1.00000000 0.00000000) *
##         25) Petal.Width>=1.65 1   0 virginica (0.00000000 0.00000000 1.00000000) *
##       13) Petal.Length>=4.95 6   2 virginica (0.00000000 0.33333333 0.66666667)  
##         26) Petal.Width>=1.55 3   1 versicolor (0.00000000 0.66666667 0.33333333) *
##         27) Petal.Width< 1.55 3   0 virginica (0.00000000 0.00000000 1.00000000) *
##      7) Petal.Width>=1.75 46   1 virginica (0.00000000 0.02173913 0.97826087) *

Nell’output qui sopra è mostrato un riepilogo della procedura di splitting:

  1. Al primo step è valutato l’albero composto dal solo “nodo radice”;
  2. Al secondo step, la procedura scansiona tutte le variabili ricercando la partizione che riduce al massimo la misura di “variabilità” scelta (indice di Gini o misura entropica) sulla variabile dipendente; a questo punto si usa come prima “diramazione” quella data dal predittore (“feature”) che minimizza la variabilità, con la sua partizione (in questo caso, Petal.Length con soglia uguale a 2.45), e il dataset è quindi “spezzato” in due sottoinsiemi;
  3. Al terzo step, per ogni sottoinsieme la procedura scansiona di nuovo tutte le variabili cercado la partizione che minimizza la misura di “variabilià” sulla variabile dipendente, e quindi utilizza il predittore (“feature”) che riduce massimamente la variabilità, con la sua partizione (Petal.Width e 1.75); quindi viene di nuovo “spezzato” il sotto-sottoinsieme;
  4. E via di seguito ….

Quello che segue è un riepilogo dettagliato dell’albero:

## Call:
## rpart(formula = Species ~ ., data = iris, method = "class", control = rpart.control(minsplit = 4, 
##     cp = 1e-06))
##   n= 150 
## 
##        CP nsplit rel error xerror       xstd
## 1 5.0e-01      0      1.00   1.19 0.04959167
## 2 4.4e-01      1      0.50   0.70 0.06110101
## 3 2.0e-02      2      0.06   0.10 0.03055050
## 4 1.0e-02      3      0.04   0.10 0.03055050
## 5 1.0e-06      5      0.02   0.09 0.02908608
## 
## Variable importance
##  Petal.Width Petal.Length Sepal.Length  Sepal.Width 
##           34           32           20           14 
## 
## Node number 1: 150 observations,    complexity param=0.5
##   predicted class=setosa      expected loss=0.6666667  P(node) =1
##     class counts:    50    50    50
##    probabilities: 0.333 0.333 0.333 
##   left son=2 (50 obs) right son=3 (100 obs)
##   Primary splits:
##       Petal.Length < 2.45 to the left,  improve=50.00000, (0 missing)
##       Petal.Width  < 0.8  to the left,  improve=50.00000, (0 missing)
##       Sepal.Length < 5.45 to the left,  improve=34.16405, (0 missing)
##       Sepal.Width  < 3.35 to the right, improve=19.03851, (0 missing)
##   Surrogate splits:
##       Petal.Width  < 0.8  to the left,  agree=1.000, adj=1.00, (0 split)
##       Sepal.Length < 5.45 to the left,  agree=0.920, adj=0.76, (0 split)
##       Sepal.Width  < 3.35 to the right, agree=0.833, adj=0.50, (0 split)
## 
## Node number 2: 50 observations
##   predicted class=setosa      expected loss=0  P(node) =0.3333333
##     class counts:    50     0     0
##    probabilities: 1.000 0.000 0.000 
## 
## Node number 3: 100 observations,    complexity param=0.44
##   predicted class=versicolor  expected loss=0.5  P(node) =0.6666667
##     class counts:     0    50    50
##    probabilities: 0.000 0.500 0.500 
##   left son=6 (54 obs) right son=7 (46 obs)
##   Primary splits:
##       Petal.Width  < 1.75 to the left,  improve=38.969400, (0 missing)
##       Petal.Length < 4.75 to the left,  improve=37.353540, (0 missing)
##       Sepal.Length < 6.15 to the left,  improve=10.686870, (0 missing)
##       Sepal.Width  < 2.45 to the left,  improve= 3.555556, (0 missing)
##   Surrogate splits:
##       Petal.Length < 4.75 to the left,  agree=0.91, adj=0.804, (0 split)
##       Sepal.Length < 6.15 to the left,  agree=0.73, adj=0.413, (0 split)
##       Sepal.Width  < 2.95 to the left,  agree=0.67, adj=0.283, (0 split)
## 
## Node number 6: 54 observations,    complexity param=0.02
##   predicted class=versicolor  expected loss=0.09259259  P(node) =0.36
##     class counts:     0    49     5
##    probabilities: 0.000 0.907 0.093 
##   left son=12 (48 obs) right son=13 (6 obs)
##   Primary splits:
##       Petal.Length < 4.95 to the left,  improve=4.4490740, (0 missing)
##       Sepal.Length < 7.1  to the left,  improve=1.6778480, (0 missing)
##       Petal.Width  < 1.35 to the left,  improve=0.9971510, (0 missing)
##       Sepal.Width  < 2.65 to the right, improve=0.2500139, (0 missing)
## 
## Node number 7: 46 observations
##   predicted class=virginica   expected loss=0.02173913  P(node) =0.3066667
##     class counts:     0     1    45
##    probabilities: 0.000 0.022 0.978 
## 
## Node number 12: 48 observations,    complexity param=0.01
##   predicted class=versicolor  expected loss=0.02083333  P(node) =0.32
##     class counts:     0    47     1
##    probabilities: 0.000 0.979 0.021 
##   left son=24 (47 obs) right son=25 (1 obs)
##   Primary splits:
##       Petal.Width  < 1.65 to the left,  improve=1.95833300, (0 missing)
##       Sepal.Length < 4.95 to the right, improve=0.95833330, (0 missing)
##       Sepal.Width  < 2.55 to the right, improve=0.10119050, (0 missing)
##       Petal.Length < 4.45 to the left,  improve=0.06359649, (0 missing)
## 
## Node number 13: 6 observations,    complexity param=0.01
##   predicted class=virginica   expected loss=0.3333333  P(node) =0.04
##     class counts:     0     2     4
##    probabilities: 0.000 0.333 0.667 
##   left son=26 (3 obs) right son=27 (3 obs)
##   Primary splits:
##       Petal.Width  < 1.55 to the right, improve=1.3333330, (0 missing)
##       Sepal.Width  < 2.65 to the right, improve=0.6666667, (0 missing)
##       Petal.Length < 5.35 to the left,  improve=0.6666667, (0 missing)
##       Sepal.Length < 6.95 to the left,  improve=0.2666667, (0 missing)
##   Surrogate splits:
##       Sepal.Length < 6.5  to the right, agree=0.833, adj=0.667, (0 split)
##       Sepal.Width  < 2.65 to the right, agree=0.833, adj=0.667, (0 split)
## 
## Node number 24: 47 observations
##   predicted class=versicolor  expected loss=0  P(node) =0.3133333
##     class counts:     0    47     0
##    probabilities: 0.000 1.000 0.000 
## 
## Node number 25: 1 observations
##   predicted class=virginica   expected loss=0  P(node) =0.006666667
##     class counts:     0     0     1
##    probabilities: 0.000 0.000 1.000 
## 
## Node number 26: 3 observations
##   predicted class=versicolor  expected loss=0.3333333  P(node) =0.02
##     class counts:     0     2     1
##    probabilities: 0.000 0.667 0.333 
## 
## Node number 27: 3 observations
##   predicted class=virginica   expected loss=0  P(node) =0.02
##     class counts:     0     0     3
##    probabilities: 0.000 0.000 1.000

E finalmente produciamo un grafico (ad “albero rovesciato”) che rappresenta l’albero:

Per leggere meglio il grafico qui sopra (dendrogramma) ci sono parecchie opzioni:

Se vogliamo anche vedere le etichette di un oggetto di tipo dendrogramma creato da rpart, possiamo usare la funzione labels():

##  [1] "root"               "Petal.Length< 2.45" "Petal.Length>=2.45"
##  [4] "Petal.Width< 1.75"  "Petal.Length< 4.95" "Petal.Width< 1.65" 
##  [7] "Petal.Width>=1.65"  "Petal.Length>=4.95" "Petal.Width>=1.55" 
## [10] "Petal.Width< 1.55"  "Petal.Width>=1.75"

Per vedere quindi come lo spazio delle “feature” (cioè, dei predittori) è stato partizionato in questo esempio, produciamo il grafico seguente:

Ora, un concetto importante nei metodi basati su alberi è quello della potatura (“pruning”): la potatura permette di evitare l’overfitting. E’ importante perché:

  • assicura che l’albero sia sufficientemente piccolo da evitare di mettere variabilità casuale nella previsione,
  • assicura che l’albero sia sufficientemente grande per evitare di mettere distorsioni sistematiche nelle previsioni.

Per potare l’albero, rpart usa la misura di complessità \(R(\alpha)\), definita come:
\(R(\alpha) = R + \alpha \cdot T\)
dove

  • \(R\) è il “rischio dell’albero” (per la classificazione, il tasso di errata classificazione; per la regressione: RSS);
  • \(\alpha\) è il parametro di complessità che altro non è che un termine di penalizzazione che controlla la dimensione dell’albero;
  • \(T\) è il numero di split/nodi terminali nell’albero

Quando \(\alpha\) cresce, l’albero con \(R(\alpha)\) minimo è un sottoalbero più piccolo dell’albero originario.
Quando \(\alpha\) cresce, quindi, la sequenza di conseguenti sottoalberi è nidificata.
Quindi, ogni sottoalbero è collegato ad un valore del parametro di complessità \(\alpha\) per cui possiamo accettare il sottoalbero come quello a “complessità minima”.

Il codice che segue stampa una tabella di potatura ottimale basata sul parametro di complessità:

## 
## Classification tree:
## rpart(formula = Species ~ ., data = iris, method = "class", control = rpart.control(minsplit = 4, 
##     cp = 1e-06))
## 
## Variables actually used in tree construction:
## [1] Petal.Length Petal.Width 
## 
## Root node error: 100/150 = 0.66667
## 
## n= 150 
## 
##        CP nsplit rel error xerror     xstd
## 1 5.0e-01      0      1.00   1.19 0.049592
## 2 4.4e-01      1      0.50   0.70 0.061101
## 3 2.0e-02      2      0.06   0.10 0.030551
## 4 1.0e-02      3      0.04   0.10 0.030551
## 5 1.0e-06      5      0.02   0.09 0.029086

Nella tabella qui sopra:

  • CP è il parametro \(\alpha\);
  • nsplit è il numero degli split de l miglior albero trovato in base a CP;
  • rel error è il valore dell’errore relativo di “resubstitution” (cioè calcolato prevedendo i dati usati per il training dell’albero stesso) dell’albero selezionato rispetto all’albero con “sola radice”.
  • xerror è il valore di errore di cross-validation, ottenuto spezzando i dati in xval sottoinsiemi, applicando la procedura di training iterativamente sui dati in cui uno dei sottoinsiemi è rimosso, e quindi applicado la previsione sui dati del sottoinsieme rimosso; xerror è la media dei valori di errore di crossvalidation xval. Questa procedura serve per evitare di individuare una configurazione di albero che si adatta “troppo” ai dati correnti e quindi poco generalizzabile (il cosiddetto overfitting).
  • xstd è la deviazione standard dell’errore stimato tramite cross-validation

L’albero più semplice con il valore di errore di cross-validation più basso (xerror) o inferiore al minimo + 1 volta xstd è il numero 3.
L’albero che ritorna il valore minimo di tasso di errore “resubstitution” è l’albero numero 5.
L’albero più grande sarà inevitabilmente sempre quello con il tasso di errore “resubstitution” più basso.

A questo punto ci sono due criteri usati per decidere l’ammontare di potatura da applicare all’albero:

  • L’albero con l’errore di cross-validation più basso
  • Il più piccolo albero con valore di cross-validation inferiore al minimo valore di errore di cross-validation più 1 volta la sua deviazione standard.

Un grafico del tasso d’errore resubstitution per l’albero si può ottenere con:

Il grafico del tasso d’errore di cross-validation è invece ottenuto con:

Come abbiamo già notato, la configurazione di albero più semplice con il valore di xerror “ottimo” (in questo caso il più semplice albero con valore di xerror inferiore al minimo + 1 volta xsrd) è la numero 3.
Si noti che i valori in ascissa sono diversi da quelli della tabella CP: i valori di CP sono calcolati come la media geometrica di valori adiacenti della tabella CP.

Il codice che segue mostra come estrarre interattivamente sottoalberi da un albero dato:

Questo invece è il codice per un grafico “veloce” degli errori con legenda:

E quello che segue è l’albero finale potato per cp=0.02 (la configurazione di albero con valore xerror “ottimo” dalla tabella dei CP):

Infine, di seguito la partizione dello spazio delle “feature” per l’albero potato:

Le previsioni per nuovi dati a partire da un albero stimato si possono ottenere, come d’uso, con il metodo predict():

La corrispettiva matrice di confusione si può generare semplicemente con

##             
## iris_pred    setosa versicolor virginica
##   setosa         50          0         0
##   versicolor      0         49         5
##   virginica       0          1        45

Oppure usando confusionMatrix():

## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         50          0         0
##   versicolor      0         49         5
##   virginica       0          1        45
## 
## Overall Statistics
##                                          
##                Accuracy : 0.96           
##                  95% CI : (0.915, 0.9852)
##     No Information Rate : 0.3333         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.94           
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9800           0.9000
## Specificity                 1.0000            0.9500           0.9900
## Pos Pred Value              1.0000            0.9074           0.9783
## Neg Pred Value              1.0000            0.9896           0.9519
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3267           0.3000
## Detection Prevalence        0.3333            0.3600           0.3067
## Balanced Accuracy           1.0000            0.9650           0.9450

14.3 Esempio: Dati di credito in Germania

Consideriamo ora il dataset german, che riguarda dati di credito in Germania.
In questo caso vogliamo prevedere se un cliente andrà in default (Bad) o pagherà (Good), sempre con la carta di credito. Quindi, abbiamo dati di input che contengono sia dati di clienti “buoni” (good) che di clienti “cattivi” (bad). Vogliamo trovare le regole o le condizioni che separano buoni clienti e cattivi clienti. Le regole dovrebbero aiutare il ricercatore a trovare i segmenti con percentuali sufficientemente alte di buoni clienti.

## 
## Good  Bad 
##  700  300

Prima di iniziare l’analisi spezziamo il campione in due sottoinsiemi, di training e di test, per permettere il test dell’albero:

## 
## Good  Bad 
##  413  187
## 
## Good  Bad 
##  287  113

Cominciamo quindi l’analisi costruendo l’albero senza altre specificazioni:

In questo caso il rpart() applica automaticamente la procedura di crescita e potatura dell’albero in maniera automatica, utilizzando parametri predefiniti per le varie fasi.

Ora proviamo a tracciare la curva ROC per l’albero generato:

## Setting levels: control = FALSE, case = TRUE
## Setting direction: controls > cases

## 
## Call:
## roc.default(response = (test$Class == "Bad"), predictor = probs,     auc = TRUE, ci = TRUE, plot = TRUE, main = "Curva ROC sui dati di credito in Germania",     legacy.axes = TRUE)
## 
## Data: probs in 287 controls ((test$Class == "Bad") FALSE) > 113 cases ((test$Class == "Bad") TRUE).
## Area under the curve: 0.6958
## 95% CI: 0.642-0.7496 (DeLong)

Possiamo quindi verificare le performance dell’albero sui dati di training

##       
##        Good Bad
##   Good  355  42
##   Bad    58 145
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Good Bad
##       Good  355  42
##       Bad    58 145
##                                           
##                Accuracy : 0.8333          
##                  95% CI : (0.8011, 0.8623)
##     No Information Rate : 0.6883          
##     P-Value [Acc > NIR] : 3.661e-16       
##                                           
##                   Kappa : 0.6204          
##                                           
##  Mcnemar's Test P-Value : 0.1336          
##                                           
##             Sensitivity : 0.7754          
##             Specificity : 0.8596          
##          Pos Pred Value : 0.7143          
##          Neg Pred Value : 0.8942          
##              Prevalence : 0.3117          
##          Detection Rate : 0.2417          
##    Detection Prevalence : 0.3383          
##       Balanced Accuracy : 0.8175          
##                                           
##        'Positive' Class : Bad             
## 

E quindi fare la stessa verifica sui dati di test

##       
##        Good Bad
##   Good  204  59
##   Bad    83  54
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Good Bad
##       Good  204  59
##       Bad    83  54
##                                           
##                Accuracy : 0.645           
##                  95% CI : (0.5959, 0.6919)
##     No Information Rate : 0.7175          
##     P-Value [Acc > NIR] : 0.99933         
##                                           
##                   Kappa : 0.1773          
##                                           
##  Mcnemar's Test P-Value : 0.05359         
##                                           
##             Sensitivity : 0.4779          
##             Specificity : 0.7108          
##          Pos Pred Value : 0.3942          
##          Neg Pred Value : 0.7757          
##              Prevalence : 0.2825          
##          Detection Rate : 0.1350          
##    Detection Prevalence : 0.3425          
##       Balanced Accuracy : 0.5943          
##                                           
##        'Positive' Class : Bad             
## 

Come atteso, le performance dell’albero con i dati di test sono scarsi, rispetto ai dati di training. Proveremo ora a potare l’albero a cp = 0.031 (il valore di cp con errore xval minimo nel grafico), per vedere se see si presenta qualche overfitting (sovra adattamento)

Possiamo quindi verificare questo nuovo albero usando il campione di test

##       
##        Good Bad
##   Good  249  81
##   Bad    38  32
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Good Bad
##       Good  249  81
##       Bad    38  32
##                                           
##                Accuracy : 0.7025          
##                  95% CI : (0.6551, 0.7469)
##     No Information Rate : 0.7175          
##     P-Value [Acc > NIR] : 0.7659840       
##                                           
##                   Kappa : 0.1704          
##                                           
##  Mcnemar's Test P-Value : 0.0001181       
##                                           
##             Sensitivity : 0.2832          
##             Specificity : 0.8676          
##          Pos Pred Value : 0.4571          
##          Neg Pred Value : 0.7545          
##              Prevalence : 0.2825          
##          Detection Rate : 0.0800          
##    Detection Prevalence : 0.1750          
##       Balanced Accuracy : 0.5754          
##                                           
##        'Positive' Class : Bad             
## 

Riducendo la complessità dell’albero, anche le performances cambiano. Se l’accuratezza globale si riduce solo di poco, anche il numero di clienti cattivi trovati dall’albero si riduce. Inoltre, la specificità cresce mentre la sensibilità cala.

I risultati qui sopra potrebbero dipendere dal fatto che l’albero dà la stessa “importanza” ai clienti buoni e ai clienti cattivi. Ciò non è nella realtà corretto, poiché la perdita legata ad una erra classificazione di un cliente cattivo è maggiore della perdita dovuta all’errata classificazione di un cliente buono.

Per provare a superare questo problema possiamo provare a costruire l’albero dando valori di perdita diversi ai due tipi di errore di errata classificazione, e quindi dando maggiore “peso”" ai clienti Bad mal classificati. Proviamo quindi creare una matrice di perdita, dove assegnamo una perdita di 5 per clienti cattivi mal classificati ed una perdita di 1 per clienti buoni mal classificati.

##      [,1] [,2]
## [1,]    0    1
## [2,]    5    0
## 
## Classification tree:
## rpart(formula = Class ~ ., data = train, parms = list(loss = lmat), 
##     cp = 0)
## 
## Variables actually used in tree construction:
##  [1] CreditAmount        CreditHistory       Duration           
##  [4] EmployedSince       Housing             Job                
##  [7] OtherBebtorsGarants OtherInstallPlans   Property           
## [10] Purpose             RatePercIncome      SavingsAccountBonds
## [13] StatusAccount       StatusAndSex       
## 
## Root node error: 413/600 = 0.68833
## 
## n= 600 
## 
##           CP nsplit rel error xerror    xstd
## 1  0.1670702      0   1.00000 5.0000 0.13735
## 2  0.0520581      1   0.83293 2.2155 0.13349
## 3  0.0351090      3   0.72881 2.7966 0.14184
## 4  0.0290557      5   0.65860 2.6174 0.13980
## 5  0.0242131      6   0.62954 2.5811 0.13935
## 6  0.0169492      8   0.58111 2.6877 0.14070
## 7  0.0145278      9   0.56416 2.6416 0.14008
## 8  0.0112994     11   0.53511 2.6683 0.14031
## 9  0.0096852     14   0.50121 2.4673 0.13715
## 10 0.0072639     19   0.45036 2.4068 0.13627
## 11 0.0024213     21   0.43584 2.3341 0.13514
## 12 0.0012107     23   0.43099 2.2663 0.13385
## 13 0.0000000     27   0.42615 2.2615 0.13350

Notate come l’albero con tasso xerror minimo è quello con parametro CP pari a 0.
Questo significa che non si può pensare di applicare il pruning all’albero senza perdere potenzialmente in capacità predittiva dell’albero stesso.

## n= 600 
## 
## node), split, n, loss, yval, (yprob)
##       * denotes terminal node
## 
##   1) root 600 413 Bad (0.68833333 0.31166667)  
##     2) StatusAccount=ge.200,noCA 279 175 Good (0.87455197 0.12544803)  
##       4) EmployedSince=ge.4y.lt7y,ge.7y 134  45 Good (0.93283582 0.06716418)  
##         8) OtherInstallPlans=stores,none 116  20 Good (0.96551724 0.03448276)  
##          16) CreditAmount>=1570 77   0 Good (1.00000000 0.00000000) *
##          17) CreditAmount< 1570 39  20 Good (0.89743590 0.10256410)  
##            34) SavingsAccountBonds=lt.100,unkown.no 27   5 Good (0.96296296 0.03703704) *
##            35) SavingsAccountBonds=ge.100.lt.500,ge.500.lt.1000,ge.1000 12   9 Bad (0.75000000 0.25000000) *
##         9) OtherInstallPlans=bank 18  13 Bad (0.72222222 0.27777778) *
##       5) EmployedSince=unemployed,lt.1y,ge.1y.lt.4y 145 119 Bad (0.82068966 0.17931034)  
##        10) Purpose=car (new),car (used),others,domestic appliances,retraining 56  20 Good (0.92857143 0.07142857)  
##          20) Duration< 25.5 48   5 Good (0.97916667 0.02083333) *
##          21) Duration>=25.5 8   5 Bad (0.62500000 0.37500000) *
##        11) Purpose=furniture/equipment,radio/television,repairs,education,business 89  67 Bad (0.75280899 0.24719101)  
##          22) CreditAmount< 1840.5 40  25 Good (0.87500000 0.12500000)  
##            44) CreditAmount>=1359.5 14   0 Good (1.00000000 0.00000000) *
##            45) CreditAmount< 1359.5 26  21 Bad (0.80769231 0.19230769)  
##              90) Property=noRE but building savings agreem/insurance 8   0 Good (1.00000000 0.00000000) *
##              91) Property=real estate,noREorBuild but car or oth not in Savings,unknown/no property 18  13 Bad (0.72222222 0.27777778) *
##          23) CreditAmount>=1840.5 49  32 Bad (0.65306122 0.34693878)  
##            46) Purpose=furniture/equipment,radio/television,repairs,education 38  28 Bad (0.73684211 0.26315789)  
##              92) StatusAndSex=maleDivorced,maleSingle,maleMarriedWidowed 20  10 Good (0.90000000 0.10000000)  
##               184) CreditAmount< 4180.5 13   0 Good (1.00000000 0.00000000) *
##               185) CreditAmount>=4180.5 7   5 Bad (0.71428571 0.28571429) *
##              93) StatusAndSex=femaleDivorcedOrMarried 18  10 Bad (0.55555556 0.44444444) *
##            47) Purpose=business 11   4 Bad (0.36363636 0.63636364) *
##     3) StatusAccount=lt.0,ge.0.lt200 321 169 Bad (0.52647975 0.47352025)  
##       6) Duration< 11.5 50  41 Bad (0.82000000 0.18000000)  
##        12) StatusAndSex=maleSingle,maleMarriedWidowed 29   0 Good (1.00000000 0.00000000) *
##        13) StatusAndSex=maleDivorced,femaleDivorcedOrMarried 21  12 Bad (0.57142857 0.42857143)  
##          26) Purpose=car (new),domestic appliances,retraining 7   0 Good (1.00000000 0.00000000) *
##          27) Purpose=car (used),furniture/equipment,radio/television,education 14   5 Bad (0.35714286 0.64285714) *
##       7) Duration>=11.5 271 128 Bad (0.47232472 0.52767528)  
##        14) Purpose=car (used),others,radio/television,retraining,business 123  74 Bad (0.60162602 0.39837398)  
##          28) Duration< 33 87  63 Bad (0.72413793 0.27586207)  
##            56) OtherBebtorsGarants=co-applicant,guarantor 14   0 Good (1.00000000 0.00000000) *
##            57) OtherBebtorsGarants=none 73  49 Bad (0.67123288 0.32876712)  
##             114) EmployedSince=ge.4y.lt7y,ge.7y 26  20 Good (0.84615385 0.15384615)  
##               228) Job=unskilled-resident,high-skill 8   0 Good (1.00000000 0.00000000) *
##               229) Job=skilled employee/official 18  14 Bad (0.77777778 0.22222222) *
##             115) EmployedSince=unemployed,lt.1y,ge.1y.lt.4y 47  27 Bad (0.57446809 0.42553191)  
##               230) Purpose=car (used),others,retraining 12  10 Good (0.83333333 0.16666667) *
##               231) Purpose=radio/television,business 35  17 Bad (0.48571429 0.51428571)  
##                 462) SavingsAccountBonds=ge.500.lt.1000,ge.1000,unkown.no 8   5 Good (0.87500000 0.12500000) *
##                 463) SavingsAccountBonds=lt.100,ge.100.lt.500 27  10 Bad (0.37037037 0.62962963) *
##          29) Duration>=33 36  11 Bad (0.30555556 0.69444444) *
##        15) Purpose=car (new),furniture/equipment,domestic appliances,repairs,education 148  54 Bad (0.36486486 0.63513514)  
##          30) RatePercIncome< 2.5 53  27 Bad (0.50943396 0.49056604)  
##            60) Housing=for free 7   5 Good (0.85714286 0.14285714) *
##            61) Housing=rent,own 46  21 Bad (0.45652174 0.54347826) *
##          31) RatePercIncome>=2.5 95  27 Bad (0.28421053 0.71578947)  
##            62) CreditHistory=delay in paying in past,critical account/credit in other 34  16 Bad (0.47058824 0.52941176)  
##             124) SavingsAccountBonds=ge.500.lt.1000,ge.1000,unkown.no 7   5 Good (0.85714286 0.14285714) *
##             125) SavingsAccountBonds=lt.100 27  10 Bad (0.37037037 0.62962963) *
##            63) CreditHistory=no credits,all credits this bank paid,credits this bank paid back till now 61  11 Bad (0.18032787 0.81967213) *

Adesso quindi verificheremo l’albero usado il campioe di test:

##       
##        Good Bad
##   Good  150  37
##   Bad   137  76
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Good Bad
##       Good  150  37
##       Bad   137  76
##                                           
##                Accuracy : 0.565           
##                  95% CI : (0.5148, 0.6142)
##     No Information Rate : 0.7175          
##     P-Value [Acc > NIR] : 1               
##                                           
##                   Kappa : 0.1539          
##                                           
##  Mcnemar's Test P-Value : 6.135e-14       
##                                           
##             Sensitivity : 0.6726          
##             Specificity : 0.5226          
##          Pos Pred Value : 0.3568          
##          Neg Pred Value : 0.8021          
##              Prevalence : 0.2825          
##          Detection Rate : 0.1900          
##    Detection Prevalence : 0.5325          
##       Balanced Accuracy : 0.5976          
##                                           
##        'Positive' Class : Bad             
## 

L’accurateza globale dell’albero è calata ancora, ma la sensibilità è cresciuta in maniera sensibile, al costo di una riduzione in specificità.

Globalmente, quest’ultimo albero “riconosce” molti più clienti “cattivi” rispetto all’albero che non usava la matrice di perdita.