Analisi discriminante in R Strumenti quantitativi per la gestione Emanuele Taufer Default data LDA con R Output Plot Previsione Tabella di classificazione Cambiare il criterio di classificazione Costruire la curva ROC Crossvalidazione LOOCV Stima del test error rate con LOOCV QDA LOOCV per QDA Confronto LDA QDA Confronto LDA QDA con la curva ROC Riferimenti bibliografici Default data Carichiamo il data set Default library(islr) data(default) head(default) default student balance income 1 No No 729.5265 44361.625 2 No Yes 817.1804 12106.135 3 No No 1073.5492 31767.139 4 No No 529.2506 35704.494 5 No No 785.6559 38463.496 6 No Yes 919.5885 7491.559 LDA con R La funzione lda(), presente nella libreria MASS, permette di affrontare problemi di classificazione con LDA. La sintassi è analoga a quella che si usa nelle funzioni lm e glm file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 1/9
library(mass) lda.fit=lda(default~balance+income+student,data=default) Output lda.fit Call: lda(default ~ balance + income + student, data = Default) Prior probabilities of groups: No Yes 0.9667 0.0333 Group means: balance income studentyes No 803.9438 33566.17 0.2914037 Yes 1747.8217 32089.15 0.3813814 Coefficients of linear discriminants: LD1 balance 2.243541e 03 income 3.367310e 06 studentyes 1.746631e 01 Plot plot(lda.fit) file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 2/9
Previsione La classificazione delle unità training (o test) può essere fatta con la funzione predict() L output di predict() contiene una serie di oggetti, utilizziamo la funzione names() per vedere quali sono e, per poterli analizzare ed utilizzare, mettiamo il tutto in un data.frame. lda.pred=predict(lda.fit, Default) names(lda.pred) [1] "class" "posterior" "x" previsione< as.data.frame(lda.pred) head(previsione) file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 3/9
class posterior.no posterior.yes LD1 1 No 0.9967765 0.003223517 0.14953711 2 No 0.9973105 0.002689531 0.23615933 3 No 0.9852914 0.014708600 0.57988235 4 No 0.9988157 0.001184329 0.62801554 5 No 0.9959768 0.004023242 0.04346935 6 No 0.9957918 0.004208244 0.02194120 Tabella di classificazione Costruiamo ora un data.frame, Default.LDA, che contiene i dati training e le previsioni della LDA. Costruiamo inoltre una tabella di classificazione Default.LDA< cbind(default, "pred.def"=lda.pred$class, "pr.def"=round(lda.pred$posterio r,digits=4)) head(default.lda) default student balance income pred.def pr.def.no pr.def.yes 1 No No 729.5265 44361.625 No 0.9968 0.0032 2 No Yes 817.1804 12106.135 No 0.9973 0.0027 3 No No 1073.5492 31767.139 No 0.9853 0.0147 4 No No 529.2506 35704.494 No 0.9988 0.0012 5 No No 785.6559 38463.496 No 0.9960 0.0040 6 No Yes 919.5885 7491.559 No 0.9958 0.0042 attach(default.lda) addmargins(table(default,pred.def)) pred.def default No Yes Sum No 9645 22 9667 Yes 254 79 333 Sum 9899 101 10000 Cambiare il criterio di classificazione Costruiamo una nuova variabile lda.pred.2 che classifica le unità come default=yes se la probabilità di default stimata dal modello di LDA è maggiore di lda.pred.2=rep("no",nrow(default)) lda.pred.2[default.lda$pr.def.yes>0.2]="yes" addmargins(table(default,lda.pred.2)) 0.2 file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 4/9
lda.pred.2 default No Yes Sum No 9435 232 9667 Yes 140 193 333 Sum 9575 425 10000 Costruire la curva ROC Per costuire la curva ROC è necessario installare la libreria ROCR. Le tre righe di istruzioni indicate sotto fanno il resto library(rocr) pred < prediction(default.lda$pr.def.yes, default) perf < performance(pred, measure = "tpr", x.measure = "fpr") plot(perf, colorize=t,lwd=3) file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 5/9
Crossvalidazione LOOCV L opzione CV=TRUE nella funzione lda() produce un LOOCV sui dati. In questo caso l output contiene la classificazione prodotta e le probailità a posteriori (per ciascuna unità esclusa dal data set), per vederne solo una parte è opportuno mettere i risultati in un data.frame lda.fit=lda(default~balance+income+student,data=default,cv=t) names(lda.fit) [1] "class" "posterior" "terms" "call" "xlevels" lda.loocv< data.frame(lda.fit$class,lda.fit$posterior) head(lda.loocv) lda.fit.class No Yes 1 No 0.9967755 0.003224456 2 No 0.9973093 0.002690741 3 No 0.9852851 0.014714856 4 No 0.9988154 0.001184632 5 No 0.9959757 0.004024296 6 No 0.9957890 0.004210951 Stima del test error rate con LOOCV Calcoliamo una tabella di classificazione ( default=yes se la probabilità di default stimata dal modello di LDA è maggiore di ) in base ai risultati della LOOCV 0.2 lda.cv.pred.2=rep("no",nrow(default)) lda.cv.pred.2[lda.loocv$yes>0.2]="yes" addmargins(table(default,lda.cv.pred.2)) lda.cv.pred.2 default No Yes Sum No 9435 232 9667 Yes 140 193 333 Sum 9575 425 10000 QDA L analisi discriminante quadratica può essere fatta utilizzando la funzione qda() qda.fit< qda(default~balance+income+student,data=default) qda.fit file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 6/9
Call: qda(default ~ balance + income + student, data = Default) Prior probabilities of groups: No Yes 0.9667 0.0333 Group means: balance income studentyes No 803.9438 33566.17 0.2914037 Yes 1747.8217 32089.15 0.3813814 LOOCV per QDA Analogamente a quanto visto per la LDA, una LOOCV può essere effettuata semplicemente inserendo l opzione CV=TRUE qda.fit< qda(default~balance+income+student,data=default,cv=true) names(qda.fit) [1] "class" "posterior" "terms" "call" "xlevels" qda.loocv< data.frame(qda.fit$class,qda.fit$posterior) head(qda.loocv) qda.fit.class No Yes 1 No 0.9993994 0.0006005886 2 No 0.9994829 0.0005170994 3 No 0.9900671 0.0099329377 4 No 0.9998886 0.0001113890 5 No 0.9989423 0.0010577454 6 No 0.9986900 0.0013100168 qda.cv.pred.2=rep("no",nrow(default)) qda.cv.pred.2[qda.loocv$yes>0.2]="yes" addmargins(table(default,qda.cv.pred.2)) qda.cv.pred.2 default No Yes Sum No 9336 331 9667 Yes 121 212 333 Sum 9457 543 10000 file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 7/9
Confronto LDA QDA Utilizzando i risultati ottenuti, confrontiamo LDA e QDA comparando le stime del test error rate ottenute dalla LOOCV LDA QDA 57.96 193/333 97.6 9435/9667 La sensitività è pari al % ( ) La specificità è pari al % ( ) 63.66 212/333 96.58 9336/9667 La sensitività è pari al % ( ) La specificità è pari al % ( ) Confronto LDA QDA con la curva ROC lda.pred < prediction(lda.loocv$yes, default) lda.perf < performance(lda.pred, measure = "tpr", x.measure = "fpr") qda.pred < prediction(qda.loocv$yes, default) qda.perf < performance(qda.pred, measure = "tpr", x.measure = "fpr") plot(lda.perf, col="blue",lwd=2) plot(qda.perf, col="red",lwd=2,add=true) legend(0.6,0.6,c('lda','qda'),col=c('blue','red'),lwd=3) file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 8/9
Riferimenti bibliografici An Introduction to Statistical Learning, with applications in R. (Springer, 2013) Alcune delle figure in questa presentazione sono tratte dal testo con il permesso degli autori: G. James, D. Witten, T. Hastie e R. Tibshirani Tobias Sing, Oliver Sander, Niko Beerenwinkel, Thomas Lengauer. ROCR: visualizing classifier performance in R. Bioinformatics 21(20):3940 3941 (2005). file:///c:/users/emanuele.taufer/dropbox/3%20sqg/labs/l4_ _LDA.html 9/9