L'apprentissage supervisé est une méthode statistique pour modéliser la relation entre une variable `y` et une liste de variables `vec x = (x_1,x_2,x_3,...x_n)`. Elle ajuste une listes de paramètres `vec p = (p_1,p_2,p_3,...,p_d)` afin que le calcul `F(vec x,vec p)` produise une prédiction la plus proche de `y`. L'équation générale du modèle est donnée par :
`y = F(vec x,vec p) - epsilon`
où `F` est une fonction librement choisie permettant de définir toutes sortes d'apprentissages supervisés spécifiques, et où `epsilon` représente l'erreur de prédiction. La prédiction moins l'erreur de prédiction donne la valeur réelle.
La donnée d'entrée du modèle est appelée une observation. C'est la liste de `n` valeurs : `vec x = (x_1,x_2,x_3,...,x_n)`.
La donnée de sortie du modèle est appelée une observation cible. C'est la valeur `y`.
La mémoire d'apprentissage du modèle est une liste de paramètres qui s'ajustent : `vec p = (p_1,p_2,p_3,...,p_d)`
La fonction `F(vec x, vec p)` calcule la prédiction de `y` que l'on note `hat y= F(vec x, vec p)`
L'apprentissage automatique supervisé s'opère sur un jeux de `N` observations. Délors, lorsque l'on parle des variables `vecx` et `y`, on désigne en fait les `n` composantes `x_(i,1),x_(i,2),...,x_(i,n)` et la valeur cible `y_i`, pour un `i` donnée entre `1` et `N`. L'ensemble des données forme les matrices `X` et le vecteur `Y`. On note ainsi parfois simplement en majuscule les matrices et vecteurs.
Par convention on utilise l'indice `i` pour parcourir les `N` observations, et on utilise l'indice `j` pour parcourir les `n` composantes d'une observation. Chaque observation est un vecteur `vec(x_i) = (x_(i,1),x_(i,2),x_(i,3),...,x_(i,n))` et chaque observation cible est une valeur `y_i`. La valeur `x_(i,j)` représente la `j`ième composante de la `i`ième observation. La valeur `y_i` représente la `i`ième observation cible. La valeur `hat y_i` représente la `i`ième prédiction. L'erreur de prédiction `epsilon_i` représente l'écart entre la prédiction et la valeur réelle `epsilon_i = haty_i-y_i` pour la `i`ième observation. La prédiction à laquel on enlève l'erreur de prédiction donne la valeur réelle.
On représente la liste des observations par la matrice `X`, et la liste des observations cibles par le vecteur `Y`, et la liste des prédictions par le vecteur `hat Y` , et la liste des erreurs de prédiction par le vecteur `E`
`X= ((x_(1,1),x_(1,2),...,x_(1,n)),(x_(2,1),x_(2,2),...,x_(2,n)),(⫶,⫶,⋱,⫶),(x_(N,1),x_(N,2),...,x_(N,n)))` `Y=((y_1),(y_2),(⫶),(y_N))` `hat Y=((hat y_1),(hat y_2),(⫶),(hat y_N))` `E=hatY - Y`
L'apprentissage automatique supervisé va, à partir du jeu de données `X, Y`, ajuster les paramètres `vec p` pour obtenir une erreur `E` minimale. Mais, il faut définir ce qu'on entend par vecteur d'erreur minimal. Cela se fait en définissant une métrique, telle que par exemple la norme classique d'un vecteur. L'apprentissage va ajuster les paramètres `vec p``=``(p_1,p_2,...,p_d)` afin que le vecteur `E``=``(epsilon_1,epsilon_2,...,epsilon_N)` définit par l'équation du modèle suivante, possède une métrique qui soit minimale :
` AAi, y_i = F(x_(i,1),x_(i,2),...,x_(i,n),p_1,p_2,...,p_d)-epsilon_i`
Pour maitriser facilement cette technique il faut avoir une bonne représentation quasi-géométrique de la façon dont sont rangées les données, sous forme de tableaux ou de matrices ou de vecteurs, puis donner des noms porteurs de sens intuitifs. Récapitulons cette disposition :
`x` Variable d'entrée, observation. `y` Variable de sortie, observation cible.
On considère `n` variables d'entrée comme autant de composantes de `x`. On ajoute donc une dimension représenté par l'indice `j` :
`n` Nombre de variables d'entrée. `j in {1,2,3,...,n}` Indice désignant la variable d'entrée. `x_1,x_2,x_3,...,x_n` Les `n` variables d'entrée. `vec(x)=(x_1,x_2,...x_n)` Forme vectorielle des variables d'entrée.
On considère `N` observations. On ajoute donc une dimension représenté par l'indice `i` :
`N` Nombre d'observations. `i in {1,2,3,...,N}` Indice désignant les observations. `vec(x_i) = (x_(i,1),x_(i,2),x_(i,3),...,x_(i,n))` `i`ième observation Les `N"×"n` données d'entrée. Le premier indice indique le numéro de l'observation.
Le second indice indique la variable d'entrée :
`(x_(1,1),x_(1,2),...,x_(1,n)),(x_(2,1),x_(2,2),...,x_(2,n)),...,(x_(N,1),x_(N,2),...,x_(N,n))``y_1,y_2,...,y_N` Les `N` données de sortie. Les observations cibles.
L'ensemble des données se mettent sous forme matricielle comme suit :
`X=[(x_(1,1),x_(1,2),...,x_(1,n)),(x_(2,1),x_(2,2),...,x_(2,n)),(⫶,⫶,⋱,⫶),(x_(N,1),x_(N,2),...,x_(N,n))]` `Y = [(y_1),(y_2),(⫶),(y_N)]`
Notez que la disposition géométrique des matrices et vecteurs, transposées ou non, en lignes ou en colonnes, n'est qu'une convention. Ce qui compte dans la composition des matrices, c'est l'ordre des indices et le type de produit définit à l'aide de ces indices. D'une manière générale, à chaque fois que l'on ajoute une dimension en dézoomant l'échelle, on ajoute l'indice correspondant comme premier indice.
Les données de test servent à mesurer le taux d'erreur auquel on peut s'attendre en production sur les futures observations. Elles ne doivent pas faire parties des données d'entrainement. C'est un principe issu du principe de séparation des pouvoirs assez simple à comprendre. Sans cela, le test perd sa valeur de test.
Un modèle est en situation de surapprentissage lorsque ses performances sont très satisfaisantes sur les données d'entrainements, mais médiocre sur les données de test.
La validation croisée tente de mesurer ce niveau de surapprentissage. La méthode de base "Hold Out" sépare les données d'entrainements et les données de test, et compare les performances sur les deux groupes. La méthode "k-fold" consiste à partitionner les données en k jeux de données, puis à entrainer le modèle sur tous les jeux de données sauf un et de mesurer la performance des prédictions sur ce jeu de données, puis de refaire toute l'opération ainsi pour chaque jeux de données et de faire la moyenne des performances. La méthode "Leave One" consiste à entrainer le modèle sur toutes les données sauf une et de mesurer la performance de la prédiction sur cette donnée, puis de refaire toute l'opération ainsi pour chaque données et de faire la moyenne des performances.
Les hyperparamètres sont fixes lors d'un apprentissage et représente des paramètres globaux du modèle tandis que les paramètres constituent la mémoire d'apprentissage évoluant au cours de l'apprentissage en enmagasinant de l'information statistique. Si on souhaite ajuster les hyperparamètres, alors selon un même principe de séparation des pouvoirs, il faut prévoir 3 jeux séparés de données; un jeux de données d'entrainement, un jeux de données de validation, et un jeux de données de test. Les données d'entrainement permettent l'ajustement des paramètres du modèle, les données de validation permettent l'ajustement les hyperparamètres du modèle et enfin les paramètres de test servent a mesurer la performance sur les données de production.
Selon que la variable d'entrée ou de sortie est une valeur discrète désignant une classe dans un ensemble de classes, ou une valeur continue ordonnée, l'algorithme change de forme. Il y a donc 4 types d'algorithmes.
...
Lorsque la valeur pronostiquée `y` est une valeur continue, on parlera d'algorithme de regression.
Lorsque la valeur pronostiquée `y` est discrète et désigne une classe, on parlera d'algorithme de classification.
Le pronostique est noté avec un chapeau `hat y_i "=" F(vec x_i, vec p)`. La performance est totale si `AAi, hat y_i "=" y_i`.
Par convention, la somme en `i` désigne la somme pour chaque donnée d'observation : `sum_i = sum_(i=1)^(i=N)`
Voici les 5 mesures courantes de la performance du pronostic pour les algorithmes de regression :
Dans le cas simple d'une classification binaire `y "∈" {0,1}`, on utilise la matrice de confusion binaire définie comme suit :
`((V0,F1),(F0,V1)) = ( ( sum_i (y_i "=" 0 "et" hat y_i "=" 0), sum_i (y_i "=" 0 "et" hat y_i "=" 1)),(sum_i (y_i "=" 1 "et" hat y_i "=" 0),sum_i (y_i "=" 1 "et" hat y_i "=" 1))) `
où les proposition valent `0` si elle sont fausse, et valent `1` si elles sont vraies, d'où les appellations courantes suivantes :
Vrais négatifs V0 Vrais positifs V1 Faux négatifs F0 Faux positifs F1
Voici quelques mesures de la performance de la prédiction pour les algorithmes de classification binaire :
Dans le cas générale d'une classification `y "∈" {1,2,3,...,c}`, on utilise la matrice de confusion de dimension `c` définie comme suit :
où `Q_(a,b)` est le nombre d'observations ou `y"="a` et `hat y "="b` :`( (Q_(1,1),Q_(1,2),Q_(1,3),...,Q_(1,c)), (Q_(2,1),Q_(2,2),Q_(2,3),...,Q_(2,c)), (Q_(3,1),Q_(3,2),Q_(3,3),...,Q_(3,c)),(...,...,...,...,...),(Q_(c,1),Q_(c,2),Q_(c,3),...,Q_(c,c)))`
`Q_(a,b) = sum_i (y_i "=" a "et" hat y_i "=" b)`
Voici quelques mesures de la performance de la prédiction pour les algorithmes de classification multiple :
Le taux de réussite du modèle est définie par `(Q_(1,1)"+"Q_(2,2)"+"..."+"Q_(c,c))/N`. C'est la probabilité de réussite, notée `sf"P"(hat y"="y)`.
`sf"P"(hat y"="y) = 1/N sum_i (hat y_i"="y_i) = (Q_(1,1)"+"Q_(2,2)"+"..."+"Q_(c,c))/n`
Le Recall de la classe `a`. C'est la probabilité conditionnelle de réussite sachant `y"="a`, notée `sf"P"(hat y"="y | y"="a)`
`sf"P"(hat y"="y | y"="a) = (sum_i (hat y_i"="y_i "et" y_i"="a))/(sum_i y_i"="a) = (Q_(a,a))/(Q_(a,1)"+"Q_(a,2)"+"..."+"Q_(a,c))`
La regression linéaire est une méthode statistique pour modéliser la relation entre une variable `y` appelée observation cible et une liste de variables `x_1,x_2,...,x_n` appelée observation. L'équation du modèle est une combinaison linéaire avec un terme constant `a_0` :
`y = a_0"+"a_1x_1"+"a_2x_2"+"..."+"a_nx_n - epsilon`
`hat y = a_0"+"a_1x_1"+"a_2x_2"+"..."+"a_nx_n`
En notation matricielle, cela peut s'écrire comme suit, où on ajoute à toutes les observations la composante `x_0"="1` :
`Y = XA+E`
`hatY = XA`
`X= ((1,x_(1,1),x_(1,2),...,x_(1,n)),(1, x_(2,1),x_(2,2),...,x_(2,n)),(1,⫶,⫶,⋱,⫶),(1, x_(m,1),x_(m,2),...,x_(m,n)))` `A=((a_0),(a_1),(a_2),(...),(a_n))` `Y=((y_1),(y_2),(⫶),(y_m))` `hat Y=((hat y_1),(hat y_2),(⫶),(hat y_m))` `E=hatY - Y`
`Y` est le vecteur des observations cibles,
`X` est la matrice des observations avec comme première colone la constante `1`,
`A` est le vecteur des paramètres,
`hatY` est le vecteur des prédictions,
`E` est le vecteur des erreurs de prédictions.
L'estimation des paramètres `a_0, a_1, a_2 ,..., a_n` dans la regression linéaire se fait souvent par la méthode des moindres carrés ordinaires (MCO), qui consiste à minimiser la somme des carrés des erreurs noté `J` :
`J = sum_i(haty_i - y_i)^2 = sum_i(a_0x_(i,0)+a_1x_(i,1)+a_2x_(i,2)+...+a_nx_(i,n)-y_i)^2`
`XA = hatY`
`((1,x_(1,1),x_(1,2),...,x_(1,n)),(1, x_(2,1),x_(2,2),...,x_(2,n)),(1,⫶,⫶,⋱,⫶),(1, x_(m,1),x_(m,2),...,x_(m,n)))((a_0),(a_1),(a_2),(...),(a_n)) = ( (a_0+a_1x_(1,1)+a_2x_(1,2)+...+a_nx_(i,n)),(a_0+a_1x_(2,1)+a_2x_(2,2)+...+a_nx_(2,n)),(⫶),(a_0+a_1x_(N,1)+a_2x_(N,2)+...+a_nx_(N,n)) ) = ((hat y_1),(hat y_2),(⫶),(hat y_N))`
La valeur de `J` se met sous forme de composition matricielle, où `"·"` désigne l'opération de produit scalaire et où l'exposant `""^t` désigne l'opération de transposition :
`J = (XA-Y)"·"(XA-Y)`
`J = (XA-Y)^t(XA-Y)`
La solution au problème de minimisation est obtenue en dérivant la fonction de coût par rapport au vecteur `A` puis en résolvant pour zéro :
`(delJ)/(delA) = (del(XA-Y))/(delA) = vec0`
Le calcul matriciel sait développer cette équation en :
`X^tXA=X^t`
La solution lorsque `X^tX` est inversible , est :
`A = (X^tX)^-1X^tY`
L'évaluation de la performance d'un modèle de regression linéaire est souvent exprimé à l'aide du coefficient de détermination `R` :
`R^2=1- (sum_i (hat y_i - y_i)^2)/(sum_i (bar y - y_i)^2)`
Une variable statistique centrée réduite est la variable transformée par une application affine (combinaison linéaire avec un terme constant), de telle sorte que sa moyenne soit nulle et que son écart type soit égal à un. Si on centre et si on réduit chaque variables préalablement, la régression linéaire n'a plus besoin du teme constant, et la résolution matriciel réduit les erreurs de calcul dû à la manipulation de valeurs d'ordre de grandeur différents.
On note souvant la moyenne de `x` par `bar x`, et l'écart type de `x` par `sigma_x` :
`bar x = 1/N sum_i x_i`
`sigma_x = sqrt(1/Nsum_i (barx-x_i)^2)`
La variable `x` centrée réduite est : `(x-barx)/(sigma_x)`
On propose un exemple en simulant des données. On utilise ChatGPT pour programmer. Il convient préalablement de créer un environement python (voir python), d'activer cet environnement et d'installer les bibliothèques utilisées à l'aide des commandes suivantes (une fois pour toute pour cet environnement) :
pip install math
pip install random
pip install numpy
pip install scikit-learn
Vous copier le programme python dans un fichier prog.py, et pour exécuter le programe, il suffit d'exécuter la commande suivante :
python prog.py
Ou bien, si vous voulez ouvrir l'interpréteur python en lançant le programme, il suffit d'exécuter la commande suivante :
python -i prog.py
Vous :
Programme en python le calcul des `100` premières valeurs (`i"="0` à `99`) des fonctions `f(i),g(i),h(i),c(i)` suivantes que tu mettra dans des listes portant le nom de la fonction : `f(i) = sin(i) + "rand"()`
où `"rand"()` est un nombre à chaque fois au hasard compris entre `0` et `1`
`g(i) = 2"*"sin(i"*"0.3) + "rand"()`
`h(i) = sin(i"*"0.03) + 2"*""rand"()`
`c(i) = 7"*"sin(i)-3*sin(i"*"0.3)+5"*"sin(i"*"0.03)+"rand"()`
ChapGPT :
Voici un programme Python qui calcule les 100 premières valeurs des fonctions demandées et les stocke dans des listes distinctes : import math import random# Initialisation des listes f = [] g = [] h = [] c = []
# Boucle de calcul pour i = 0 à 99 for i in range(100): rand_val = random.random() # nombre aléatoire dans [0,1)f_val = math.sin(i) + random.random() g_val = 2 * math.sin(i * 0.3) + random.random() h_val = math.sin(i * 0.03) + 2 * random.random() c_val = (7 * math.sin(i) - 3 * math.sin(i * 0.3) + 5 * math.sin(i * 0.03) + random.random())f.append(f_val) g.append(g_val) h.append(h_val) c.append(c_val)# Exemple d'affichage des 10 premières valeurs print("f[:10] =", f[:10]) print("g[:10] =", g[:10]) print("h[:10] =", h[:10]) print("c[:10] =", c[:10])
Vous :
Programme la régression linéaire pour prédire `c` à partir de `f,g,h`. Utilise pour cela la bibliothèque sklearn. Puis calcule le coefficient de détermination.
ChatGPT :
Parfait
On va utiliser scikit-learn (sklearn.linear_model.LinearRegression) pour entraîner un modèle qui prédit `c(i)` à partir de `f(i),g(i),h(i)`. Ensuite on calcule le coefficient de détermination `R^2`Voici un script complet :
import math import random import numpy as np from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score# Initialisation des listes f, g, h, c = [], [], [], []
# Calcul des données pour i = 0 à 99 for i in range(100): f_val = math.sin(i) + random.random() g_val = 2 * math.sin(i * 0.3) + random.random() h_val = math.sin(i * 0.03) + 2 * random.random() c_val = (7 * math.sin(i) - 3 * math.sin(i * 0.3) + 5 * math.sin(i * 0.03) + random.random()) f.append(f_val) g.append(g_val) h.append(h_val) c.append(c_val)
# Conversion en arrays numpy X = np.column_stack([f, g, h]) # variables explicatives y = np.array(c) # variable cible# Création et entraînement du modèle model = LinearRegression() model.fit(X, y)
# Prédiction y_pred = model.predict(X)
# Coefficient de détermination R^2 r2 = r2_score(y, y_pred)
print("Coefficients :", model.coef_) print("Intercept :", model.intercept_) print("Coefficient de détermination R^2 :", r2)
On exécute le programme et cela affiche :
(env1) dmabboux@bb:~/A$ python -i r.py
Coefficients : [ 6.19383379 -1.24577475 0.78220824]
Intercept : 0.14654725339310204
Coefficient de détermination R^2 : 0.8445136460729791
L'intersept est la prédiction de `c(i)` lorsque toutes les composantes sont nulles c'est à dire lorsque `f(i)=g(i)=h(i)=0`. Le modèle appris est :
`hat c(i) = "Coefficients"[0]"*"f(i)+"Coefficients"[1]*g(i)+"Coefficients"[2]*h(i)+"Intersept"`
ChatGPT peut montrer les données d'entraînement :
ChatGPT peut comparer les prédictions et les valeurs réels :
On calcul les coefficients `vec p` correspondant au minimum de `sum_i(haty_i-y)^2+alpha sum_i |p_i|`
Le lasso peut fonctionner dans les cas où le nombre d'observations est inférieur au nombre de variables (`N < n`). Le lasso permet de sélectionner un sous-ensemble restreint de variables (dépendant du paramètre `alpha`) ayant un réel apport sur l'observation cible.
Reprogramme la régression linéaire pour prédire `c` à partir de `f,g,h`, mais en utilisant la méthode Lasso.
Parfait
On peut remplacer la régression linéaire classique par la régression Lasso de scikit-learn (sklearn.linear_model.Lasso).
Cette méthode ajoute une pénalisation `L_1` qui favorise la sélection de variables (certains coefficients peuvent devenir exactement `0`).Voici le code :
import math
import random
import numpy as np
from sklearn.linear_model import Lasso
from sklearn.metrics import r2_score# --- Génération des données --- f, g, h, c = [], [], [], []
for i in range(100): f_val = math.sin(i) + random.random() g_val = 2 * math.sin(i * 0.3) + random.random() h_val = math.sin(i * 0.03) + 2 * random.random() c_val = (7 * math.sin(i) - 3 * math.sin(i * 0.3) + 5 * math.sin(i * 0.03) + random.random()) f.append(f_val) g.append(g_val) h.append(h_val) c.append(c_val)# Conversion en arrays numpy X = np.column_stack([f, g, h]) y = np.array(c)
# --- Régression Lasso --- # alpha contrôle la force de régularisation (par défaut ici 0.1) model = Lasso(alpha=0.1) model.fit(X, y)# Prédictions y_pred = model.predict(X)
# Coefficient de détermination R^2 r2 = r2_score(y, y_pred)
print("Coefficients :", model.coef_) print("Intercept :", model.intercept_) print("Coefficient de détermination R^2 :", r2)Ici :
- alpha=0.1 règle la pénalisation (plus grand = coefficients plus "rabotés").
- coef_ donne les coefficients associés à `f,g,h`
- intercept_ est la constante.
- r2 mesure la qualité de l’ajustement.
On calcul les coefficients `vec p` correspondant au minimum de `sum_i(haty_i-y)^2+alpha sum_i p_i^2`
Le Ridge permet de réduire le risque de surapprentissage
Reprogramme la régression linéaire pour prédire `c` à partir de `f,g,h`, mais en utilisant la méthode Ridge.
Très bien
On peut utiliser la régression Ridge (sklearn.linear_model.Ridge) qui applique une régularisation `L_2`.
Contrairement à Lasso, elle réduit les coefficients mais sans les annuler complètement.Voici le code :
import math
import random
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.metrics import r2_score# --- Génération des données --- f, g, h, c = [], [], [], []
for i in range(100): f_val = math.sin(i) + random.random() g_val = 2 * math.sin(i * 0.3) + random.random() h_val = math.sin(i * 0.03) + 2 * random.random() c_val = (7 * math.sin(i) - 3 * math.sin(i * 0.3) + 5 * math.sin(i * 0.03) + random.random()) f.append(f_val) g.append(g_val) h.append(h_val) c.append(c_val)# Conversion en arrays numpy X = np.column_stack([f, g, h]) y = np.array(c)
# --- Régression Ridge --- # alpha contrôle la régularisation (plus grand = coefficients plus petits) model = Ridge(alpha=1.0) model.fit(X, y)# Prédictions y_pred = model.predict(X)
# Coefficient de détermination R^2 r2 = r2_score(y, y_pred)
print("Coefficients :", model.coef_) print("Intercept :", model.intercept_) print("Coefficient de détermination R^2 :", r2)alpha=1.0 est le paramètre de régularisation (tu peux l’augmenter ou le diminuer pour voir l’effet).
L'utilisation de la méthode des moindres carrés, seule où avec les variantes Lasso et Ridge, devient trop consommatrice en temps de calcul lorsque le nombre de variables `n` devient grand. On utilise alors une autre méthode qu'est la descente de gradient.