Linux Embedded

Le blog des technologies libres et embarquées

Initiation au Machine Learning sur python avec SKlearn

Introduction:

Dans le cadre de mon stage de fin d’étude dans la majeure système embarqué, j'ai été amené à utiliser le machine learning pour la détection d’activité humaine dans un signal audio. Pour ce faire, j’ai utilisé l’outil sklearn permettant un prototypage rapide et des fonctionnalités plus poussées permettant d’optimiser les résultats.

Dans cet article, nous allons voir rapidement ce qu’est le machine learning, quels sont les choix à réaliser pour concevoir notre propre intelligence artificielle, comment évaluer sa précision et pour finir les informations relatives à la donnée. Cet article est composé de deux parties, une théorique et une pratique avec les outils sklearn et pandas.

 

Partie 1: Machine learning, modèle et data

Dans cette partie, quelques concepts clés du machine learning vous seront présentés, comment il fonctionne, quels sont les types de machine learning et les modèles qui les composent. Pour finir, nous verrons l’importance de la donnée dans le machine learning. Vous trouverez pour chaque partie quelques codes sources qui vous permettront d’aller plus loin sur ce sujet  très technique.

 

Définitions

Le machine learning est une branche de l’intelligence artificielle. Sa spécificité est son modèle d’apprentissage qui n’est pas codé explicitement de telle façon à résoudre votre problème en particulier mais plutôt une catégorie de problème. Toute la difficulté est alors de savoir dans quelle catégorie se situe notre donnée pour pouvoir ensuite choisir le meilleur modèle. Nous sommes loin du  cerveau "positronique" d'Isaac Asimov mais  plus sur un ensemble d’approches mathématiques (statistiques, optimisations, régression et bien d'autres) qui permet à la machine de s’adapter à un problème en lui appliquant son modèle d’entraînement et de prédiction. On retrouve aussi des modèles semblables au cerveau humain, les réseaux de neurones, qui sont une catégorie du machine learning appelé le Deep Learning.

Ce que la machine cherche à retrouver grâce à ses propres méthodes mathématiques, ce sont des motifs récurrents qui sont présents dans la donnée. On fait justement appel à cette technologie car nous, pauvres mortels, ne pouvons que très difficilement interpréter ce que les mathématiques peuvent voir à ce niveau là. Par exemple, seul un bon œnologue peut savoir, sans goûter, la qualité d’un vin seulement par l’étiquette, la bouteille et l’aspect de son contenu. Ces trois éléments sont les informations de notre donnée. Cet œnologue connaît les combinaisons. Il sait qu’un vin de tel aspect sera meilleur tel année plutôt qu’une autre etc. La machine fait exactement pareil ! Elle cherche des combinaisons des différentes informations présentes dans la donnée. 

Ici, notre jeu de données sont des milliers de bouteilles de vin avec leur aspect, la forme de leur bouteille et les informations présentent sur l’étiquette. On appellera une observation (ou datapoint) un ensemble de caractéristiques (ou features) sur une bouteille.

 

Fonctionnement

A présent que nous connaissons un peu plus le rôle du machine learning, appréhendons son fonctionnement afin de mieux comprendre l’étude de cas de la deuxième partie. Pour cela, il nous faut tout d’abord un jeu de données. Plus il est grand, mieux c’est mais plus il y a de features pour une observation et plus le besoin en donnée accroît exponentiellement. Le machine learning ne peut vivre sans le big data qui lui permet l’accès à une quantité de base de données gargantuesque.  

Plusieurs outils tels que Kaggle, UCI Machine Learning Repository, Google dataset search, AWS open data registry, Wikipédia ML Datasets vous permettent de trouver des datasets portant sur le sujet que vous recherchez. Imaginons que nous voulions développer un algorithme nous permettant de détecter la qualité d’un vin. Nous chercherions tout d’abord un dataset contenant les informations nécessaires à cette classification. Nous allons donc sur Kaggle et tapons “wine quality” ce qui nous conduit à https://www.kaggle.com/datasets/shelvigarg/wine-quality-dataset.

Téléchargez directement la base de données via le bouton “download” en haut à droite ou bien positionnez vous vers le bas pour avoir un aperçu de la donnée (ainsi qu’un nouveau bouton "download").

Sur Kaggle vous trouverez aussi les codes d'autres utilisateurs qui manipulent ce dataset dans la partie “Code”. Il s’agit souvent de travaux d’étudiants bien commentés et décrits malgré parfois un manque de documentation.

Une fois la base de données récupérée, nous avons un jeu de données qui peut être "labellisé". Le label peut être arbitraire puisqu’il est l’information que vous cherchez à prédire. Par exemple, dans le cas du vin, nous cherchons à prédire sa qualité. Nous aurons donc des labels comme “mauvais”, “médiocre”, “bon”, “excellent”. Ici les labels sont dits catégoriques. Ce ne sont pas des nombres mais des classes dans lesquelles se répartissent les données. Ces labels catégoriques seront par la suite encodés numériquement pour avoir 0, 1, 2 ou 3.

Pour une machine devant deviner le coût d’une infrastructure, ce label sera sous la forme d’une valeur continue dont la machine doit le plus possible se rapprocher.

Voici une source vous permettant de mieux comprendre le principe de valeur discrète ou continue

Avec cette donnée labellisée ou non, on va tout d’abord nourrir notre modèle avec de la donnée pour l’entraîner et le tester par la suite. On va séparer notre jeu de bouteilles de vins en deux jeux, un d’entraînement et un autre de validation. On sépare les deux caisses de vin car nous voulons connaître la précision de la machine sur des bouteilles de vin qu’elle n’a jamais vues auparavant.

 

Types de Machine Learning

 

Il existe plusieurs types de machine learning ou devrais-je dire, de modèles. Un modèle en machine learning est un fichier qui a été (ou va être) entraîné afin de reconnaître certains types de motifs. 

En apprentissage supervisé, deux types de modèles existent. La classification et la régression. Le jeu de données est labellisé (on connaît la bonne réponse pour chaque donnée) et ces labels sont utilisés lors de l’apprentissage du modèle. 

  • On utilise les modèles de régression lorsque nos données d’entrées sont numériques (les valeurs catégoriques sont encodées numériquement) et que la sortie recherchée est continue. Dans la deuxième partie de cette article, nous verrons un exemple avec la détection du prix des appartements à Paris.
  • Au contraire, on utilise les modèles de classification lorsque la sortie est catégorique. Comme notre exemple avec la qualité du vin ! 

En apprentissage non supervisé, la machine ne connaît pas le résultat à prédire pour chaque donnée du jeu d'entraînement. Elle va chercher des motifs récurrents qui ne sont pas forcément liés au résultat.

  • Le clustering divise le jeu de données en suffisamment  de groupes tel que les informations contenues dans les données ne présentent pas les mêmes motifs d’un groupe à l’autre.
  • L’association permet de découvrir des relations entre les informations d’une donnée et créer des nouvelles informations qui ne sont que des associations d’autres variables de la donnée.
  • La réduction de la dimension de la donnée permet de réduire le nombre d’informations  en supprimant les moins fiables ou bien en remplaçant deux ou trois features par leur association. Cette méthode est pratiquée en machine learning car plus la dimension de la donnée est faible, plus il est facile de modéliser ces informations. 

Cette sélection des features et l'association sont aussi utilisées dans les autres modèles et nous verrons leurs utilisation dans notre étude de cas en partie 2. Elle permet d’éviter un effet connu en machine learning, le fléau de la dimension (curse of dimensionality). 

Il pourrait sembler intéressant que plus nous avons d’informations sur nos observations (donc plus la dimension de la donnée est grande), plus notre machine sera précise et fiable. Ca n'est pas forcément le cas, car l’ordinateur va avoir accès à une quantité nouvelle de possibles motifs mais les observations seront soumises à un effet d’éparpillement. 

 

Si nous devions placer 10 points de manière homogène sur le carré de l’image à gauche. Nous aurions une surface de H*L pour les placer alors que sur et dans le cube, nous avons un volume cette fois ci de B*L*H. Les 10 points seront donc plus éparpillés qu’avec le carré.  

 Réduction de dimension + Fléau de la dimension:

Modèle :

Dans cette partie, voyons de plus près les deux modèles en apprentissage supervisé, la régression et la classification.

  • Régression :

Dans les modèles de régression, le résultat que la machine doit prédire est une valeur continue. Cette régression peut être linéaire, sous forme d'un arbre de décision ou encore, dans le cadre du Deep learning sous la forme d'un réseau de neurones.

 

  • Classification :

Dans les modèles de classification, la machine doit, pour une donnée, déterminer le groupe auquel elle appartient. La sortie à prédire est discrète. 

Il existe le modèle de régression logistique, des machines à vecteur de support ou encore Naive Bayes.

 

 

Ce schéma ne représente que très peu de cas d’usage car nous avons rarement 2 dimensions pour nos observations. Il devient difficile de se représenter un espace à 12 ou 30 dimensions, c’est aussi pour cela  que la machine nous est utile.

Pour une implémentation de régression linéaire, je vous conseille de vous tourner vers ce repo github avec les formules mathématiques clairement expliquées.

 

La donnée

La donnée est l’un des éléments les plus importants dans le machine learning, autant si ce n’est plus que le modèle utilisé. Même si l’ordinateur va chercher des motifs et des relations que nous ne pouvons pas remarquer, il est crucial de bien maîtriser la donnée que nous possédons. 

Nous avions vu que les features de nos observations pouvaient être répartis en 3 catégories, continues (la température ou bien un prix), catégoriques (une couleur, une famille animale ou la qualité d’un produit) et numériques. Les valeurs numériques sont les valeurs continues et les valeurs discrètes sont encodées en valeur numérique.

Si vous connaissez bien votre donnée, vous allez tout de suite savoir quoi en faire. Faut-il la modifier à l’aide de pré-traitement (comme la normalisation ou la standardisation) ? Y a-t-il des features superficielles pouvant être supprimées ?

Je me rappelle d’une expérience professionnelle où nous recevions un signal sous la forme d’un ensemble de complexes. Ces différents signaux ne nous arrivaient pas tous en même temps et ce décalage de phase n’était pas utile lors de la prédiction. Nous avions donc utilisé un pré-traitement qui permettait d’annuler la phase moyenne des signaux et donc supprimer une information elle même encodée dans une autre afin d’alléger la donnée et rendre plus précise la prédiction. Connaissez votre donnée !

Si vous commencez un petit projet en machine learning, renseignez vous plus sur les pré-traitements à appliquer à la donnée avant l’entraînement et la prédiction. Voici plus d’informations sur la normalisation et la standardisation et une deuxième sur un plus grand choix de pré-traitement.

 

Partie 2: Mise en pratique

Outils et base de données

Après avoir effleuré la surface théorique du machine learning, essayons nous à un processus assez basique : récupérer un jeu de données, choisir un modèle, entraîner un modèle, prédire des résultats, analyser la donnée et réduire sa dimension en supprimant certaines informations tout en gardant un résultat fiable.

Dans ce petit projet, nous allons entraîner un modèle pour prédire le prix des appartements à Paris. Pour s’aider durant ce processus, nous utiliserons la bibliothèque sklearn (scikit-learn) qui regroupe une grande quantité d’outils en rapport avec le machine learning.

Pour se repérer dans cette documentation, vous trouverez 6 catégories principales. Trois catégories représentant des modèles comme la Classification, la Régression ou le Clustering. Ce sont eux que nous entraînons afin d’effectuer des prédictions et il en existe plusieurs sortes dans chaque catégorie. Vous trouverez aussi des outils vous permettant de traiter la donnée en amont de l’entraînement avec Preprocessing ou encore sélectionner les features les plus intéressantes avec la catégorie Dimensionality Reduction. Quant à Model Selection, il vous permet d’entraîner plusieurs modèles différents afin de déterminer le plus précis. Vous trouverez beaucoup d’exemples sous forme de projets utilisant matplotlib pour afficher les résultats.

Lien: https://scikit-learn.org/stable/

Le deuxième outil majeur que nous allons utiliser s’appelle pandas. Il consiste en un ensemble de fonctionnalités qui permettent la manipulation, un traitement plus simple et un affichage plus compréhensible de différents types de données. Nous utiliserons cet outil pour convertir des fichiers CSV en dataframe, une sorte de table SQL sous forme d’objet Python. 

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html

La première étape consiste à trouver un jeu de données d'appartements parisiens avec diverses informations sur chacun . Comme nous ne savons pas encore si votre apprentissage sera supervisé ou non, nous allons aussi vouloir récupérer le prix des logements. 

Lien vers la base de donnée: https://www.kaggle.com/datasets/mssmartypants/paris-housing-price-prediction

Vous pourrez télécharger le fichier CSV grâce au bouton “download” en haut à droite ou bien en descendant un peu, vous aurez un accès visuel sur la base de données ainsi qu’un autre bouton "download".

Le site possède quelques petits projets sur la manipulation des features de ce jeu de données qui ont aidé à la conception de cet article. Je vous conseille d’aller y jeter un coup d'œil pour examiner ce cas d’étude d’un autre angle.

  • Les imports:
import matplotlib.pyplot as plt
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

import numpy as np
import pandas as pd

 

Voici les fonctionnalités et librairies que nous utiliserons dans la suite de cet article.

On retrouve sklearn et pandas mais aussi matplotlib qui nous permet d’afficher des données (et bien plus) ainsi que numpy.

Installation et découverte de pandas

Voyons dans cette partie comment installer sklearn et pandas mais aussi comment en apprendre le plus possible sur notre donnée grâce plus particulièrement à pandas. Vous saurez tout de votre donnée, que ça soit sa dimension, les différentes informations disponibles, le type de valeur pour chaque features et bien d’autres infos sur votre jeu de données avant la prochaine partie.

Sklearn est une librairie python, installez le module et importez le dans un fichier .py .

pip3 install --user sklearn
pip3 install --user pandas

 

ParisHousing.csv vient du lien vers la base de données fourni plus haut.

>>> import pandas as pd
>>> df = pd.read_csv("ParisHousing.csv")
>>> df.head()

  squareMeters  numberOfRooms  hasYard  hasPool  floors  cityCode  cityPartRange  ...  hasStormProtector  basement  attic  garage  hasStorageRoom  hasGuestRoom      price
0         75523              3        0        1      63      9373              3  ...                  1      4313   9005     956               0             7  7559081.5
1         80771             39        1        1      98     39381              8  ...                  0      3653   2436     128               1             2  8085989.5
2         55712             58        0        1      19     34457              6  ...                  0      2937   8852     135               1             9  5574642.1
3         32316             47        0        0       6     27939             10  ...                  1       659   7141     359               0             3  3232561.2
4         70429             19        1        1      90     38045              3  ...                  0      8435   2429     292               1             4  7055052.0

[5 rows x 17 columns]

 

.head(n=5) nous indique :

  • Les n premières lignes de la dataframe avec n égal à 5 par défaut.
  • Les caractéristiques (si affichable) sont des colonnes avec chaque ligne une observation 
>>> df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000 entries, 0 to 9999
Data columns (total 17 columns):
#   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
0   squareMeters       10000 non-null  int64  
1   numberOfRooms      10000 non-null  int64  
2   hasYard            10000 non-null  int64  
3   hasPool            10000 non-null  int64  
4   floors             10000 non-null  int64  
5   cityCode           10000 non-null  int64  
6   cityPartRange      10000 non-null  int64  
7   numPrevOwners      10000 non-null  int64  
8   made               10000 non-null  int64  
9   isNewBuilt         10000 non-null  int64  
10  hasStormProtector  10000 non-null  int64  
11  basement           10000 non-null  int64  
12  attic              10000 non-null  int64  
13  garage             10000 non-null  int64  
14  hasStorageRoom     10000 non-null  int64  
15  hasGuestRoom       10000 non-null  int64  
16  price              10000 non-null  float64
dtypes: float64(1), int64(16)
memory usage: 1.3 MB

 

.info() nous indique : 

  • Le nom de chaque colonne "Column" et leur id "#"
  • Combien d'éléments non null sont présents dans cette colonne avec "Non-Null"
  • Si la colonne peut présenter des valeurs nulle à certains moment dans "Count" (qui est inversé ici avec "Non-Null")
  • Le type de la colonne, ici seulement int ou float sur 8 octets

Nous pouvons voir que nous avons 16 informations sur chaque appartement. Toutes nos données sont numériques même si certaines comme hasYard n’ont que deux possibilités alors que squareMeters est continu.

>>> df.describe()      

            squareMeters     numberOfRooms       hasYard       hasPool     

count   10000.00000   10000.000000     10000.000000    10000.000000  
mean    49870.13120      50.358400      0.508700      0.496800    
std     28774.37535      28.816696      0.499949      0.500015
min        89.00000       1.000000      0.000000      0.000000      
25%     25098.50000      25.000000      0.000000      0.000000     
50%     50105.50000      50.000000      1.000000      0.000000     
75%     74609.75000      75.000000      1.000000      1.000000     
max     99999.00000     100.000000      1.000000      1.000000    

[8 rows x 17 columns]

 

.describe() nous donne de nouvelles informations sur :

  • Le total de ligne pour chaque feature.
  • La moyenne des valeurs d'une feature.
  • La variance des valeurs d'une feature.
  • Le minimum et le maximum.
  • Les quartiles.

En temps normal, .describe() affiche ces différentes informations pour chaque feature. La sortie a été modifiée par souci de clarté.

Certaines de nos valeurs sont discrètes mais dans notre cas, elles sont déjà encodées. En d'autres termes, pour "has Pool", la valeur n'est pas "oui "ou "non" mais 1 ou 0 . Pour les modèles de régression, il est impératif de n'avoir que des valeurs numériques.

La régression linéaire

Nous avons donc récupéré des informations concernant notre base de données. Voyons si celles-ci nous permettent déjà d’établir un mode d’apprentissage (supervisé ou non) et peut-être un modèle candidat pour notre problème.

Nous savons que chacune de nos features sont des nombres, sans aucune valeur nulle. Nous cherchons à déterminer le prix, qui lui aussi est un nombre.

Quand on cherche à déterminer une valeur, on peut se diriger vers les modèles de régression, dans notre cas une régression linéaire est suffisante. Nous sommes donc en apprentissage supervisé.

Avant de s'occuper du modèle, mettons en forme la donnée pour la  rendre compatible avec les fonctionnalités de sklearn. Comme dit dans l'introduction, il faut fractionner la totalité de nos observations en deux jeux de données. Un pour entraîner le modèle et un autre pour tester l'efficacité de cet entraînement.

Pour convertir notre dataframe pandas, nous devons convertir chaque ligne du tableau en une liste avec n élément, “n” étant notre nombre de features. Toutes ces lignes seront stockées dans une liste nommée "X". On appelle la "dimension" de X, le nombre de features que contient la donnée.

De même, on garde le prix de chaque appartement dans une liste à part nommée "y".

 

  • On récupère le nom des features et le nom de la variable à prédire

""" -1 -> len() - 1 """
feature_names = list(df.columns[:-1])
target_name = df.column[-1]

 

On veut que les 16 premières colonnes soit utilisées comme features. On récupère sous  forme de liste toutes les colonnes sauf la dernière pour feature_names et seulement la dernière colonne pour target_name.

 

  • On récupère X et y

X = df.reindex(columns = feature_names); X = values.tolist();
y = df.reindex(columns = target_name);   y = values.tolist();

 

On filtre la dataframe avec seulement les features choisies et on récupère ses valeurs dans une liste. 

 

  • On sépare la donnée en deux jeux, validation et entraînement

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
reg = LinearRegression()
reg.fit(X_train, y_train)

 

Ici, train_test_split est une fonction de sklearn permettant de diviser en deux le jeu X et y en un jeu d’entraînement (X_train, y_train) et un jeu de test (X_test, t_test). La variable test_size nous permet de donner la taille du jeu de test. Ici la valeur 0.3 indique 30% de la taille de X/y.

Pour rappel, on sépare en deux X et y afin d’entraîner la machine avec le premier jeu et de la valider avec un deuxième. Cette manœuvre nécessite deux jeux car nous ne voulons pas valider la précision de la prédiction avec le même jeu qui aurait servi à l’entraînement. La machine risque de nous fournir un résultat avec une très forte précision mais qui n’est pas représentatif d’une situation où la machine ne connaît pas les échantillons à analyser.

On crée un objet LinearRegression() de la bibliothèque sklearn et on l’entraîne avec le jeu d’entraînement. 

LinearRegression() est décrit sur  https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html 

Il est possible d’activer l’argument “random_state” qui vous permet de créer un mélange avant la séparation en deux jeux. Cette technique peut être utilisée pour les problèmes de sur et sous-entraînement.

Voici quelques sources pour plus d’informations sur l’underfitting et l’overfitting :

En français sur https://mrmint.fr/overfitting-et-underfitting-quand-vos-algorithmes-de-machine-learning-derapen

En anglais sur https://ezako.com/en/overfitting-and-underfitting-concepts-in-machine-learning/

Prédiction

Nous avons entraîné un modèle de régression linéaire, il est temps de voir si nos choix pour le modèle d’apprentissage sont bons et si la prédiction est satisfaisante. 

  • On prédit à partir du jeu de test notre modèle

y_pred = reg.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
mean_y = sum(y_test)/len(y_test)
mae_percent = (mae/mae_percent)*100
print(f"mean absolute error: {mae}\naverage apartement price: {mean_y}\nmae in percent: {mae_percent}) 

 

La méthode .predict(X) d’un modèle permet de renvoyer un tableau de chaque prédiction évaluée pour chaque donnée de la liste X reçue en paramètre. 

Pour avoir une idée de la précision de notre algorithme, nous allons récupérer la moyenne de l’erreur absolue entre les prédictions et les prix véritables des appartements.

Le résultat est le suivant :

mean absolute error : 1489.1219709592976
average appartement price: 5068168.49387975
mae in percent: 0.02938

 

Qualification et sélection des features

On se retrouve avec une erreur moyenne absolue de 1489 euros. Si on compare cette erreur moyenne au prix moyen des appartements, on se retrouve avec une erreur de 0.02938% ce qui est assez faible et montre le bon fonctionnement de notre modèle. On peut expliquer cette marge d'erreur par des facteurs impactant le prix de l'appartement comme la négociation, le bruit aux alentours ou encore le niveau du vis-à-vis. Il manquera toujours certaines informations qui ne sont soit pas intuitives à trouver ou encore des informations difficiles à mesurer.  

Voyons à présent quel impact a eu chaque features sur la prédiction. 

  • On affiche le coefficient d'importance de chaque caractéristiques dans la régression

fs = SelectKBest(score_func = f_regression, k = 'all')
fs.fit(X_train, y_train)
# Affichage des coefficients des features
for i in range(len(fs.scores_)):
    print(f"{feature_names[i]}: {fs.scores_[i]}")

plt.bar([i for i in range(len(fs.scores_)], fs.scores_)
# Cette limitation s'explique par la différence importante entre les features et squareMeters
plt.ylim([0, 10])
plt.show()

 

Pour réaliser cette sélection des meilleures features, on utilise SelectKBest() qui nous retourne une analyse des différentes features.

SelectKBest() est décrit sur https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.SelectKBest.html

Le résultat est le suivant :

squareMeters: 5420268608.660389
numberOfRooms: 0.0017953926586377232
hasYard: 0.00826146553092818
hasPool: 0.008046202277706142
floors: 0.02056926167093336
cityCode: 0.07501140356602772
cityPartRange: 4.010648051552513
numPrevOwners: 1.700909578921672
made: 1.9207490130742455
isNewBuilt: 0.23080621111882668
hasStormProtector: 1.0500063608242194
basement: 0.035296821308313873
attic: 0.018345545748999353
garage: 7.08447504024301
hasStorageRoom: 0.22931275818321975
hasGuestRoom: 0.1272706730421559

 

Sans grande surprise, squareMeters est de loin la feature ayant le plus d'impact sur la prédiction. Il serait intéressant de voir si notre prédiction serait tout aussi précise sans les features au coefficient d’impact faible.

Nous sommes obligés de limiter l’axe y à 10. Sans cela, nous ne verrions pas les fluctuations à l’échelle des autres features.

  • On supprime les features les moins importantes

To_remove = []
for i in range(len(fs.scores_)):
if fs.scores_[i] < 0.23:
to_remove.append(feature_names[i])
# Copier feature_names sans les éléments aussi présent dans to_remove
filtered_features = [feature for feature in feature_names if not feature in to_remove]
X = df.reindex(columns = filtered_features); X = X.values.tolist();
print(f"nouvelle dimension de X: {len(X[0])}")

X_train, y_train, X_test, y_test = train_test_split(X,y, test_size=0.3)
reg = LinearRegression()
reg.fit(X_train, y_train)
Y_pred = reg.predict(X_test)
mae = mean_absolute_error(y_test, y_pred) 
printf"resultat avec réduction de features: {mae}")

On crée une liste des features dont le coefficient ne dépasse pas 0.23.

Au prochain entraînement, la donnée se verra retirer les features de cette liste.

Le résultat est le suivant :

nouvelle dimension de X: 8
Features choisies: ['squareMeters', 'numberOfRooms', 'hasYard', 'hasPool', 'cityPartRange', 'numPrevOwners', 'isNewBuilt',  'garage']
résultat avec réduction de features: 1463.7986964710797

On remarque qu’avoir réduit  à 8 features n’impacte pas le résultat de la prédiction.

 

  • Exemple d’une régression récursive :

 

Dans ce programme, j’ai supprimé (de manière récursive) un à un les features avec le plus petit coefficient d’impact. Sur l’axe des x on retrouve le nombre de features utilisé pour l’entraînement et sur l’axe des y la moyenne de l’erreur absolue de la prédiction.

 

  •  Exemple RFE

1   2866534.3274604944
2   2866504.4870068114
3   2866489.2277425188
4   2467.924863847536
5   2467.606577594451
6   1897.7176433131492
7   1891.8832761486944
8   1891.6572638648468
9   1891.5932794259388
10   1891.5917868954098
11   1891.2351172887622
12   1891.2283006189048
13   1890.793181102233
14   1890.7825887523204
15   1890.5280056395843
16   1890.5272258509212

Ce procédé s’appelle RFE (Recursive Feature Elimination). Il supprime une à une les features de manière aléatoire et plusieurs fois afin d’estimer un nombre de features optimal, soit ici 6.

https://machinelearningmastery.com/rfe-feature-selection-in-python/

Conclusion:

Réaliser et entraîner un modèle de machine learning fiable ne vous demande pas une connaissance parfaite du fonctionnement interne. Il est important de partir de quelque chose de simple et au fur et à mesure d'ajouter de nouveaux mécanismes comme les pré-traitements, la validation croisée et la sélection de features. Assurez-vous de bien comprendre votre donnée, la relation des différentes entrées et la de la sortie et ce que vous fournissez à votre modèle pour l’entraînement.

Sklearn peut sembler simple à l’utilisation mais la personnalisation des modèles possibles en fait un outil très complet. Beaucoup de sujets différents n’ont pu être abordés dans cet article comme la validation croisée, la sélection du modèle, les pré-traitements, la création de features, les métriques et bien d’autres.

Pour les réseaux de neurones, je vous conseille plutôt de vous tourner vers Keras ou TensorFlow même si pour des cas assez simple il est possible d’utiliser sklearn. Keras est une API de haut niveau qui simplifie l’utilisation de TensorFlow.

Si vous souhaitez utiliser les fonctionnalités de sklearn pour un système embarqué, il existe l’outil Emlearn capable d'entraîner des modèles en Python et convertir le code pour la cible en langage C. Cela permet d'éviter les problèmes de performances de python en temps réel. De plus cette bibliothèque ne déclare rien en dynamique. Scikit-learn peut rester difficile à packager dans Buildroot notamment où les paquets comme Python, NumPy, SciPy, joblib et threadpoolctl sont nécessaires en amont.  

Cependant, Sklearn n'a pas pour vocation à être embarqué. Il ne s'agit que de prototypage afin de récupérer le meilleur modèle et un ensemble de features fiable. Pour embarquer votre solution ensuite, il ne suffit que d'implémenter l'algorithme du modèle avec les paramètres que vous aurez déterminé. En C, vous retrouverez "libonnx" et "cONNXr" qui ne possède aucune dépendance.

Vous pouvez retrouver le code source commenté à l'adresse https://github.com/Openwide-Ingenierie/article_ml/blob/main/article_ml.py


 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.