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

0.1 Défintion:

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.

0.2 Présentation des données:

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.

0.3 Importation et exploration initiale des donné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

0.4 Division des données en apprentissage et test

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)      

0.5 Interprétation des courbes d’erreur

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.

0.6 Compromis biais-variance

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.

0.6.1 Notions de sous-apprentissage et sur-apprentissage

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.