Devoir #3 Philippe St-Aubin 4 novembre 2017
Question no.1 a) Prenons la décomposition de Cholesky de la matrice des covariances puisque celle-ci est symétrique et définie positive, ainsi: C = DDT Alors C −1 = D−1 (D−1 )T Posons A = DT Ainsi C = AT A Multiplions le système par A Ay = AXβ + Aϵ On obtient donc une régression linéaire dans l’espace de la base de A: y ′ = X ′ β + ϵ′ On reprend donc la solution pour β :
β = (X ′T X ′ )−1 X ′T y ′ β = ((AX)T AX)−1 (AX)T Ay β = (X T AT AX)−1 X T AT Ay
On obtient donc finalement:
β = (X T CX)−1 X T Cy
b) La loi asymptotique de βˆ est donc :
βˆ ∼ N (β, σ 2 (X T CX)−1 )
Question no.2 \subsection{a) KNN \subsubsection{1. LOOCV library(class) # On normalise les données pour appliquer KNN default.norm = data.frame(apply(default[,c(1,2)], 2, function(x) x/max(x))) default.norm$default = default$default D’après le graphique on peut garder trois nombres de voisins qui donnent la même erreur. Gardons le plus petit (k = 11) Estimons l’erreur sur la classification en utilisant la méthode de validation croisée LOOCV 1
e3 = data.frame() knn.loocv = data.frame() # Boucle k for(j in seq(from = 1, to = 20, by = 2)){ e2 = data.frame() # Boucle LOOCV for(i in c(1:nrow(default.norm))){ # On entraîne le modèle sur toutes les observations sauf une default.knn = knn(default.norm[-i,c(1:2)], default.norm[i,c(1:2)], cl = default.norm[-i, 3], k = j) # On calcul l'erreur de classifiation pour un k donné e = data.frame(pred = default.knn, reel = default.norm[i,3]) e2 = rbind(e2, e) } # On calcul le taux d'erreur pour un k donné e3 = data.frame(k = j, error = mean(e2$pred != e2$reel)) knn.loocv = rbind(knn.loocv, e3) }
0.19 0.17 0.15
taux d'error
0.21
# Graphique du nombre optimal de voisins (k) plot(knn.loocv$k, knn.loocv$error, type = "l", xlab = "k", ylab = "taux d'error")
5
10
15
k D’après le graphique 3 ou 17 voisins seraient le nombre de voisins qui minimise l’erreur estimée par LOOCV avec un taux de 15% d’erreur. \subsubsection*{2. 5-Fold CV On doit construire au hasard 5 échantillons tests library(caret)
2
## Loading required package: lattice ## Loading required package: ggplot2 set.seed(1204876) folds = createFolds(c(1:300), k = 5) e3 = data.frame() knn.kfolds = data.frame() # Boucle de k for(j in seq(1, 20, 2)){ error.fold = data.frame() # Boucle de CV for(i in c(1:5)){ # On entraîne le modèle sur tous les folds sauf un default.knn = knn(default.norm[-folds[[i]],c(1:2)], default.norm[folds[[i]],c(1:2)], cl = default.norm[-folds[[i]], 3], k = j) # On calcul l'erreur de classification e = data.frame(fold = i, error = mean(default.knn != default.norm[folds[[i]],3])) error.fold = rbind(error.fold, e) } # On calcul le taux d'erreur moyen pour les 5 folds e3 = data.frame(k = j, error = mean(error.fold$error)) knn.kfolds = rbind(knn.kfolds, e3) }
0.17 0.15 0.13
taux d'error
plot(knn.kfolds$k, knn.kfolds$error, type = "l", xlab = "k", ylab = "taux d'error")
5
10
15
k En utilisant la méthode des k-folds avec k=5, on trouve que le nombre optimal de voisins est de 19 avec une estimation du taux d’erreur à 13%. \subsubsection*{3. Choix du k La méthode LOOCV permet d’obtenir le biais le plus faible sur l’erreur puisqu’on entraîne le modèle avec n-1 observations. Par contre la variance sur le résultat est plus élevée. Comme on cherche à trouver le k optimal minimisant l’erreur, il serait judicieux de se baser sur le résultat 3
du LOOCV. Donc on conserve k = 17.
b) Régression Logistique 1. LOOCV default$default = as.character(levels(default$default))[default$default] default$default[default$default == "Yes"] = 1 default$default[default$default == "No"] = 0 default$default = as.numeric(default$default) library(boot) ## ## Attaching package: 'boot' ## The following object is masked from 'package:lattice': ## ## melanoma # Modèle 1 d.glm1 = glm(default ~ income + balance, data = default) # LOOCV glm1.loocv = cv.glm(default, d.glm1) glm1.loocv$delta[1] ## [1] 0.1044673 # Modèle 2 d.glm2 = glm(default ~ income + balance + income:balance, data=default) # LOOCV glm2.loocv = cv.glm(default, d.glm2) glm2.loocv$delta[1] ## [1] 0.1043897 ## methode modèle erreur ## 1 LOOCV 1 0.1044673 ## 2 LOOCV 2 0.1043897 On remarque que l’estimation de l’erreur sur les deux modèles est très proche l’une de l’autre. Par contre, le modèle 2 donne une erreur plus basse. 2. K-Folds CV # K-folds glm1.kfolds = cv.glm(default, d.glm1, K = 5) glm1.kfolds$delta[1] ## [1] 0.1041416 # K-folds glm2.kfolds = cv.glm(default, d.glm2, K = 5) glm2.kfolds$delta[1] ## [1] 0.106043 4
## methode modèle erreur ## 1 K-folds 1 0.1041416 ## 2 K-folds 2 0.1060430 Le modèle 1 obtient cette fois un résultat légèrement meilleur. 3. Choix du modèle summary(d.glm1) ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
Call: glm(formula = default ~ income + balance, data = default) Deviance Residuals: Min 1Q -0.87551 -0.20109
Median 0.03664
3Q 0.22483
Max 0.85042
Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -3.069e-01 6.083e-02 -5.045 7.92e-07 *** income 1.466e-06 1.413e-06 1.037 0.3 balance 5.960e-04 2.892e-05 20.610 < 2e-16 *** --Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 (Dispersion parameter for gaussian family taken to be 0.1038968) Null deviance: 75.000 Residual deviance: 30.857 AIC: 177.04
on 299 on 297
degrees of freedom degrees of freedom
Number of Fisher Scoring iterations: 2
On remarque que la variable income n’est pas significative dans le modèle, car sa p-value est très grande. summary(d.glm2) ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
Call: glm(formula = default ~ income + balance + income:balance, data = default) Deviance Residuals: Min 1Q -0.86069 -0.21023
Median 0.04809
3Q 0.21411
Max 0.82670
Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -4.025e-01 1.149e-01 -3.505 0.000528 *** income 4.533e-06 3.429e-06 1.322 0.187201 balance 6.655e-04 7.650e-05 8.700 2.35e-16 *** income:balance -2.243e-09 2.285e-09 -0.982 0.327041 --Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
5
## ## ## ## ## ## ##
(Dispersion parameter for gaussian family taken to be 0.1039095) Null deviance: 75.000 Residual deviance: 30.757 AIC: 178.07
on 299 on 296
degrees of freedom degrees of freedom
Number of Fisher Scoring iterations: 2
On remarque que le terme d’interaction n’est pas non plus significatif. Son ajout ne contribue donc pas au modèle. Au final choisir un modèle ou l’autre ne devrait pas modifier grandement le résultat. Toutefois comme le modèle 2 semble donner une erreur légèrement inférieure avec la méthode LOOCV, on va poursuivre avec celui-ci.
c) LDA, QDA 1. LOOCV default$default[default$default == 1] = "Yes" default$default[default$default == 0] = "No" default$default = as.factor(default$default) library(MASS) #LDA e2 = data.frame() for(i in c(1:nrow(default))){ d.lda = lda(default[-i,c(1,2)], default$default[-i]) # On calcul l'erreur de classifiation pred.lda = predict(d.lda, default[i,c(1,2)]) e = data.frame(pred = pred.lda$class, reel = default.norm$default[i]) e2 = rbind(e2, e) } lda.loocv = mean(e2$pred != e2$reel) #QDA e2 = data.frame() for(i in c(1:nrow(default))){ d.qda = qda(default[-i,c(1,2)], default$default[-i]) # On calcul l'erreur de classifiation pred.qda = predict(d.qda, default[i,c(1,2)]) e = data.frame(pred = pred.qda$class, reel = default.norm$default[i]) e2 = rbind(e2, e) } qda.loocv = mean(e2$pred != e2$reel) data.frame(méthode = c("LOOCV","LOOCV"), modèle = c("LDA", "QDA"), erreur = c(lda.loocv, qda.loocv)) ## méthode modèle erreur ## 1 LOOCV LDA 0.1300000 ## 2 LOOCV QDA 0.1333333 On remarque que les deux taux d’erreurs sont très similaires avec 0,13 pour lda et 0,133333 pour qda.
6
2. K-Folds CV set.seed(1204876) folds = createFolds(c(1:300), k = 5) # LDA lda.kfolds = data.frame() # Boucle de CV for(i in c(1:5)){ # On entraîne le modèle sur tous les folds sauf un d.lda = lda(default[-folds[[i]],c(1:2)], default$default[-folds[[i]]]) pred.lda = predict(d.lda, default[folds[[i]], c(1,2)]) # On calcul l'erreur de classifiation e = data.frame(fold = i, erreur_moy = mean(pred.lda$class != default$default[folds[[i]]])) lda.kfolds = rbind(lda.kfolds, e) } # QDA qda.kfolds = data.frame() # Boucle de CV for(i in c(1:5)){ # On entraîne le modèle sur tous les folds sauf un d.qda = qda(default[-folds[[i]],c(1:2)], default$default[-folds[[i]]]) pred.qda = predict(d.qda, default[folds[[i]], c(1,2)]) # On calcul l'erreur de classifiation e = data.frame(fold = i, erreur_moy = mean(pred.qda$class != default$default[folds[[i]]])) qda.kfolds = rbind(qda.kfolds, e) }
# On calcul le taux d'erreur moyen pour les 5 folds data.frame(méthode = c("K-folds", "K-folds"), modèle = c("LDA", "QDA"), erreur = c(mean(lda.kfolds$err ## méthode modèle erreur ## 1 K-folds LDA 0.1266667 ## 2 K-folds QDA 0.1266667 En utilisant la méthode de validation croisée, on trouve encore une fois que les erreurs sont très similaires entre les deux méthodes. 3. Choix de la méthode ## ## ## ## ##
méthode modèle erreur 1 LOOCV LDA 0.1300000 3 K-folds LDA 0.1266667 2 LOOCV QDA 0.1333333 4 K-folds QDA 0.1266667
On remarque que les deux méthodes donnent à peu près les mêmes résultats pour les deux méthodes de validation croisée. Toutefois, on remarque que les résultats de LDA donnent une erreure très légèrement
7
inférieur que QDA avec la méthode LOOCV. Comme c’est la méthode de validation croisée avec le biais le plus faible, on prendre ce résultat pour appuyer notre choix de modèle. On choisit donc le modèle LDA
D. Choix du modèle 1. Comparaison graphique ## Grille normalisée r.norm = sapply(default.norm[,c(1:2)], range) # On construit les points en x xs.n = seq(r.norm[1,1], r.norm[2,1], length.out = 100) # On construit les points en y ys.n = seq(r.norm[1,2], r.norm[2,2], length.out = 100) ## # On construit la structure pour la prédiction des points de la grille g.n = expand.grid(income = xs.n, balance = ys.n) ## Grille r = sapply(default[,c(1:2)], range) # On construit les points en x xs = seq(r[1,1], r[2,1], length.out = 100) # On construit les points en y ys = seq(r[1,2], r[2,2], length.out = 100) ## # On construit la structure pour la prédiction des points de la grille g = expand.grid(income = xs, balance = ys) # KNN comp.knn = knn(default.norm[,c(1,2)], g.n, cl = default.norm$default, k = 17) # Regression Logistique comp.glm = predict(d.glm2, g) comp.glm = ifelse(comp.glm > 0.5, 1, 0) # LDA comp.lda = predict(d.lda, g) # On affiche la frontière du KNN z.knn = matrix(as.numeric(comp.knn), nrow = 100, byrow = TRUE) # On affiche la frontière de la Régression logistique z.glm = matrix(as.numeric(comp.glm), nrow = 100, byrow = TRUE) # On affiche la frontière de LDA z.lda = matrix(as.numeric(comp.lda$class), nrow = 100, byrow = TRUE) # On affiche les données plot(default$income, default$balance, col = default$default, pch = as.integer(default$default), xlab = "income", ylab = "balance", main = "Frontière du défaut de paiement") legend("topright", c("KNN", "GLM", "LDA"), lwd = 2, col = c("orange", "blue", "red")) # Contour KNN
8
contour(xs, ys, t(z.knn), add = TRUE, drawlabels = FALSE, lwd = 2, levels = (1:2), col = "orange") # Contour GLM contour(xs, ys, t(z.glm), add = TRUE, drawlabels = FALSE, lwd = 2, levels = (1:2), col = "blue") # Contour LDA contour(xs, ys, t(z.lda), add = TRUE, drawlabels = FALSE, lwd = 2, levels = (1:2), col = "red")
Frontière du défaut de paiement
500 1000 0
balance
2000
KNN GLM LDA
10000
20000
30000
40000
50000
60000
income L’équation de la frontière de décision de la courbe LDA est donnée par l’expression suivante : δy − δn = 0 où 1 δy = xt Σ−1 µy − µty Σ−1 µy + ln(πy ) 2 et 1 δn = xt Σ−1 µn − µtn Σ−1 µn + ln(πn ) 2 avec Σ−1 = d.lda$scaling^-1 ## LD1 ## income 1212599.4023 ## balance 407.5182 et µtn (première ligne de la matrice) et µty (deuxième ligne de la matrice) : d.lda$means ## ## No
income 31351.59
balance 781.8979 9
## Yes 31030.88 1760.5056 Finalement les probabilité à priori (πn , πy ) sont données par : d.lda$prior ## No Yes ## 0.5125 0.4875 La courbe tracée est donc celle où les x annulent la différence δy − δn . 2. K-folds CV set.seed(1204876) folds = createFolds(c(1:300), k = 10) # KNN for(i in c(1:10)){ # On entraîne le modèle sur tous les folds sauf un default.knn = knn(default.norm[-folds[[i]],c(1:2)], default.norm[folds[[i]],c(1:2)], cl = default.norm[-folds[[i]], 3], k = 17) # On calcul l'erreur de classification e = data.frame(fold = i, error = mean(default.knn != default.norm[folds[[i]],3])) error.fold = rbind(error.fold, e) } # On calcul le taux d'erreur moyen pour les 10 folds knn.test = data.frame(modèle = "KNN", erreur = mean(error.fold$error))
# Régression Logistique default.num = default default.num$default = ifelse(default$default == "Yes", 1, 0) glm2.kfolds = cv.glm(default.num, d.glm2, K = 10) glm.test = data.frame(modèle = "RegLog", erreur = glm2.kfolds$delta[1]) # LDA error.fold = data.frame() for(i in c(1:10)){ # On entraîne le modèle sur tous les folds sauf un d.lda = lda(default[-folds[[i]],c(1:2)], default$default[-folds[[i]]]) pred.lda = predict(d.lda, default[folds[[i]], c(1,2)]) # On calcul l'erreur de classifiation e = data.frame(fold = i, error = mean(pred.lda$class != default$default[folds[[i]]])) error.fold = rbind(error.fold, e) } lda.test = data.frame(modèle = "LDA", erreur = mean(error.fold$error)) # Tableau de comparaison rbind(knn.test, glm.test, lda.test) ## modèle erreur ## 1 KNN 0.1457975 ## 2 RegLog 0.1047641 10
## 3
LDA 0.1340913
Avec la validation croisée sur les trois modèles, on constate que l’erreur moyenne est plus faible pour la régression logistique. On choisit donc de conserver le modèle de régression logistique 2.
Question no.3 A. Expression d’un estimateur On doit donner une estimation du paramètre θ donné par l’expression suivante: θ = E(min(|X1 X3 |, X1 2 ln X2 + X3 , X2 X3 )) On dispose de n observations pour estimer θ. On peut donc l’estimer par l’expression suivante : 1∑ θˆ = min(|Xi1 − Xi3 |, Xi1 − 2 ln Xi2 + Xi3 , Xi2 − Xi3 ) n i=1 n
B. Bootstrap 1. Estimation ponctuelle, biais et écart-type :
library(boot) # Statistique set.seed(192348) thet = function(x, ind){ y = data.frame(X1 = abs(x$Girth[ind] - x$Volume[ind]), X2 = x$Girth[ind] - 2*log(x$Height[ind]) + x$Vo mean(apply(y,1,min)) } # Bootstrap b_t = boot(trees, thet, R = 1500) b_t ## ## ## ## ## ## ## ## ## ## ##
ORDINARY NONPARAMETRIC BOOTSTRAP
Call: boot(data = trees, statistic = thet, R = 1500)
Bootstrap Statistics : original bias t1* 13.74516 -0.004582796
std. error 1.420574
2. Intervalle de confiance:
11
plot(b_t)
16 12
t*
14
0.20 0.00
10
0.10
Density
0.30
18
Histogram of t
8
10 12 14 16 18
−3
t*
−1 0
2
3
Quantiles of Standard Normal
constate une distribution normale des résultats de l’estimateur. confiance en considérant une distribution normale des résultats.
On On peut donc estimer l’intervalle de
boot.ci(b_t, conf = 0.95, type = c("norm")) ## ## ## ## ## ## ## ## ## ##
1
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS Based on 1500 bootstrap replicates CALL : boot.ci(boot.out = b_t, conf = 0.95, type = c("norm")) Intervals : Level Normal 95% (10.97, 16.53 ) Calculations and Intervals on Original Scale
ˆ On obtient donc un intervalle de confiance de (10.93, 16.63) pour l’estimateur θ.
12