L’objectif est de présenter de manière claire la méthode k-NN. Il ne s’agit pas d’une étude approfondie, et le travail a été réalisé en suivant un cahier des charges précis
La méthode des k plus proches voisins est une méthode d’apprentissage supervisé qui permet d’estimer la valeur d’une variable cible(variable à expliquer) à partir d’un vecteur de variables explicatives. On calcule la distance entre un “élement”et tous ces voisins du jeu de données d’apprentissage. Ainsi, la prédiction est obtenue en faisant la moyenne des valeurs correspondantes à ces voisins.
Le jeu de données que nous utilisons concerne la concentration d’ozone mesurée au cours d’une journée. La variable à expliquer correspond donc au taux d’ozone maxO3, tandis que les autres variables explicatives regroupent des mesures météorologiques, telles que la température, la nébulosité et la vitesse du vent.
L’objectif est d’appliquer une méthode de régression par les k plus proches voisins (k-NN), qui permet d’estimer la concentration d’ozone en fonction de certains variables météorologiques observées.
#knitr::opts_chunk$set(echo = false)
library("FNN")
## Warning: le package 'FNN' a été compilé avec la version R 4.4.2
#IMportation des données
ozone <- read.csv2("ozone.txt", dec = ".")
head(ozone)
## maxO3 T6 T9 T12 T15 T18 Ne6 Ne9 Ne12 Ne15 Ne18 Vdir6 Vvit6
## 19950401 47.6 10.1 11.6 13.3 13.6 12.2 8 8 8 8 8 270 2
## 19950402 56.2 9.5 9.4 13.8 17.4 16.3 8 8 7 0 0 100 2
## 19950403 61.8 3.6 8.0 16.8 21.5 20.2 4 5 2 2 3 310 2
## 19950404 50.8 9.5 10.5 11.4 12.2 11.4 8 7 7 7 8 20 3
## 19950405 59.8 9.8 10.8 13.8 14.3 13.3 8 7 8 8 7 330 2
## 19950406 53.4 8.9 10.2 12.6 13.2 12.9 8 8 8 8 7 240 1
## Vdir9 Vvit9 Vdir12 Vvit12 Vdir15 Vvit15 Vdir18 Vvit18 Vx maxO3v
## 19950401 290 4 300 4 340 4 20 4 -3.4641 62.2
## 19950402 160 2 180 3 110 1 350 2 0.0000 47.6
## 19950403 20 2 340 1 170 2 170 3 -0.3420 56.2
## 19950404 10 4 350 3 350 3 350 4 -0.5209 61.8
## 19950405 340 2 280 1 320 3 350 4 -0.9848 50.8
## 19950406 230 3 290 2 300 1 350 3 -1.8794 59.8
dim(ozone)
## [1] 1464 23
Avant de procéder à l’analyse, il est intéressant de voir au moins s’il y a des valeurs manquantes.
new_ozone <- ozone[,c("T12","Ne9","Vvit9","maxO3v","maxO3")]
summary(new_ozone)
## T12 Ne9 Vvit9 maxO3v
## Min. : 3.90 Min. :0.000 Min. : 0.000 Min. : 33.20
## 1st Qu.:16.15 1st Qu.:3.000 1st Qu.: 2.000 1st Qu.: 68.00
## Median :19.30 Median :6.000 Median : 4.000 Median : 81.00
## Mean :19.40 Mean :5.141 Mean : 3.757 Mean : 85.07
## 3rd Qu.:22.60 3rd Qu.:7.000 3rd Qu.: 5.000 3rd Qu.: 98.00
## Max. :33.50 Max. :9.000 Max. :12.000 Max. :173.00
## NA's :1 NA's :2 NA's :1 NA's :73
## maxO3
## Min. : 33.20
## 1st Qu.: 68.00
## Median : 81.00
## Mean : 85.07
## 3rd Qu.: 98.00
## Max. :173.00
## NA's :73
Nous voyons qu’il y a des valeurs manquantes qu’il faudra supprimer.
#Suppression des valeurs manquantes
ozone_wna <- na.omit(new_ozone)
summary(ozone_wna)
## T12 Ne9 Vvit9 maxO3v
## Min. : 5.70 Min. :0.000 Min. : 0.000 Min. : 33.20
## 1st Qu.:16.30 1st Qu.:3.000 1st Qu.: 2.000 1st Qu.: 68.00
## Median :19.40 Median :6.000 Median : 4.000 Median : 80.60
## Mean :19.42 Mean :5.167 Mean : 3.731 Mean : 84.96
## 3rd Qu.:22.60 3rd Qu.:7.000 3rd Qu.: 5.000 3rd Qu.: 98.00
## Max. :33.50 Max. :9.000 Max. :12.000 Max. :173.00
## maxO3
## Min. : 33.20
## 1st Qu.: 68.00
## Median : 80.60
## Mean : 84.91
## 3rd Qu.: 98.00
## Max. :166.00
Nous allons estimer un modèle pour prédire la variable maxO3 à partir des autres variables. Ainsi, la variable maxO3 jouera le rôle de variable à expliquer, tandis que les variables T12, Ne9, Vvit9, maxO3v joueront le rôle de variables explicatives.
Dans notre cas, nous faisons face à un problème de régression, car la variable à expliquer est quantitative.
# Soit n le nombre de lignes du tableau précédent
n <- nrow(ozone_wna)
# Soit p le nombre de variables explicatives
p <- ncol(ozone_wna) - 1
La première colonne du tableau indique les dates des prélèvements, comprises entre avril et décembre. Nous allons donc supposer que les lignes du tableau constituent un échantillon i.i.d. (indépendant et identiquement distribué).
L’exercice nous impose de procéder comme suit :
Mélanger les données en utilisant une graine aléatoire 123.
Placer 60 % des lignes dans l’ensemble d’apprentissage et 40 % dans l’ensemble de test.
Estimer le modèle de prévision pour les valeurs dek∈{1,5,10,20,30,50,100,150,200}
# Fixer une graine aléatoire pour éviter de changer le résultat après chaque exécution
set.seed(123)
# On va récupérer les indices mélangés
ind <- sample(n)
# On divise les données (apprentissage et test) selon les indices mélangés
ind.app <- ind[1:floor(n * 0.6)]
ind.test <- ind[(floor(n * 0.6) + 1):n]
app <- ozone_wna[ind.app, ]
test <- ozone_wna[ind.test, ]
# Valeurs de k à tester
k <- c(1, 5, 10, 20, 30, 50, 100, 150, 200)
# Vecteurs pour stocker les erreurs d'apprentissage et de test
err.test <- err.app <- numeric(length(k))
# Boucle pour calculer l'erreur de test
for (i in seq_along(k)) {
m1 <- knn.reg(train = app[, 1:p], test = test[, 1:p], y = app[[p+1]], k = k[i])
err.test[i] <- mean((m1$pred - test[[p+1]])^2)
}
# Boucle pour calculer l'erreur d'apprentissage
for (i in seq_along(k)) {
m2 <- knn.reg(train = app[, 1:p], test = app[, 1:p], y = app[[p+1]], k = k[i])
err.app[i] <- mean((m2$pred - app[[p+1]])^2)
}
# Affichage des résultats
err.test
## [1] 362.4756 200.0528 181.4653 179.3883 187.4859 202.6514 233.5478 254.6941
## [9] 272.1234
err.app
## [1] 0.0000 150.4419 171.4230 194.4863 209.7030 230.1001 262.8207 282.4452
## [9] 297.5459
# Le bon k correspond à la plus petite erreur de test
posi.err <- which.min(err.test)
bon.k <- k[posi.err] # le meilleur k,
# Tracé des erreurs
plot(k, err.test, type = "b", col = "red", ylim = c(0, 400),
xlab = "k", ylab = "Erreur quadratique", main = "Erreur d'apprentissage et de test")
points(k, err.app, type = "b", col = "blue")
# un point au k optimal
points(bon.k, err.test[posi.err], col = "darkgreen", pch = 10, cex = 2)
La courbe rouge (erreur de test) commence à un niveau maximal pour k=1, puis diminue progressivement jusqu’à un minimum global, avant de se stabiliser.
La courbe bleu (erreur d’apprentissage) augmente petit à petit et tend également à se stabiliser.
Pour k=1, on observe que : L’erreur d’apprentissage est minimale (le modèle a “mémorisé” les données d’apprentissage), le modèle s’ajuste trop aux données d’apprentissage et ne capture pas la structure générale.
L’erreur de test est maximale, ce qui signifie que le modèle ne généralise pas bien à de nouvelles données.
La Variance : mesure la sensibilité du modèle aux fluctuations des données.
Le Biais : mesure l’écart entre le vrai modèle et le modèle estimé.
Dans le cas du k-NN :
Petit k : le modèle est simple, colle fortement aux données (biais faible), mais est très sensible aux variations (variance élevée).
Grand k : le modèle est plus flexible, fait la moyenne sur beaucoup de voisins donc il perd de la précision sur les vrais voisins, la variance est faible donc il ne capte pas la vraie structure des données, donc biais élevé.
Le meilleur k correspond à un compromis entre biais et variance :
Les erreurs d’apprentissage et de test sont modérées et proches,
Le modèle généralise correctement sur de nouvelles données.
Sous-apprentissage : lorsque k est très grand, biais élevé, variance faible, le modèle est trop simple pour capturer les tendances des données, L’erreur d’apprentissage et l’erreur de test sont alors toutes deux élevées..
Sur-apprentissage : k très petit, biais faible, variance élevée, le modèle est trop complexe et s’adapte trop aux données d’apprentissage, ne généralise pas sur des nouvelles données, l’erreur d’apprentissage est très faible.
Ajustement optimal : biais et variance modérés, erreurs faibles et proches sur apprentissage et test, bonne capacité de généralisation.