Recherche de site Web

Comment griller les techniques de préparation des données de recherche


Les performances de la modélisation prédictive du Machine Learning dépendent de la qualité de vos données, et la qualité de vos données dépend de la façon dont vous les préparez pour la modélisation.

L'approche la plus courante en matière de préparation de données consiste à étudier un ensemble de données et à examiner les attentes d'un algorithme d'apprentissage automatique, puis à choisir soigneusement les techniques de préparation de données les plus appropriées pour transformer les données brutes afin de répondre au mieux aux attentes de l'algorithme. Cette opération est lente, coûteuse et nécessite une grande expertise.

Une approche alternative à la préparation des données consiste à rechercher sur une grille une suite de techniques de préparation de données courantes et couramment utiles pour les données brutes. Il s'agit d'une philosophie alternative pour la préparation des données qui traite les transformations de données comme un autre hyperparamètre du pipeline de modélisation à rechercher et à ajuster.

Cette approche nécessite moins d’expertise que l’approche manuelle traditionnelle de préparation des données, même si elle est coûteuse en termes de calcul. L’avantage est qu’il peut faciliter la découverte de solutions de préparation de données non intuitives qui permettent d’obtenir de bonnes ou meilleures performances pour un problème de modélisation prédictive donné.

Dans ce didacticiel, vous découvrirez comment utiliser l'approche de recherche par grille pour la préparation de données avec des données tabulaires.

Après avoir terminé ce tutoriel, vous saurez :

  • La recherche par grille offre une approche alternative à la préparation des données pour les données tabulaires, où les transformations sont essayées en tant qu'hyperparamètres du pipeline de modélisation.
  • Comment utiliser la méthode de recherche par grille pour la préparation des données afin d'améliorer les performances du modèle par rapport à une référence pour un ensemble de données de classification standard.
  • Comment griller les séquences de recherche des méthodes de préparation des données pour améliorer encore les performances du modèle.

Démarrez votre projet avec mon nouveau livre Data Preparation for Machine Learning, comprenant des tutoriels pas à pas et les fichiers code source Python pour tous les exemples.

Commençons.

Présentation du didacticiel

Ce didacticiel est divisé en trois parties : ils sont:

  1. Technique de recherche de grille pour la préparation des données
  2. Ensemble de données et référence de performances

    1. Ensemble de données de classification des vins
    2. Performances du modèle de référence
  3. Approche de recherche de grille pour la préparation des données

Technique de recherche de grille pour la préparation des données

La préparation des données peut être difficile.

L’approche la plus souvent prescrite et suivie consiste à analyser l’ensemble de données, à revoir les exigences des algorithmes et à transformer les données brutes pour répondre au mieux aux attentes des algorithmes.

Cela peut être efficace, mais est également lent et peut nécessiter une expertise approfondie en matière d’analyse de données et d’algorithmes d’apprentissage automatique.

Une approche alternative consiste à traiter la préparation des variables d'entrée comme un hyperparamètre du pipeline de modélisation et à l'ajuster en même temps que le choix de l'algorithme et des configurations de l'algorithme.

Il peut s'agir d'une transformation de données qui « ne devrait pas fonctionner » ou « ne devrait pas être appropriée pour l'algorithme » mais qui aboutit à des performances bonnes ou excellentes. Alternativement, il peut s'agir de l'absence de transformation de données pour une variable d'entrée qui est considérée comme « absolument requise » mais qui entraîne des performances bonnes ou excellentes.

Ceci peut être réalisé en concevant une recherche par grille de techniques de préparation de données et/ou des séquences de techniques de préparation de données dans des pipelines. Cela peut impliquer d’évaluer chacun d’entre eux sur un seul algorithme d’apprentissage automatique choisi ou sur une suite d’algorithmes d’apprentissage automatique.

L’avantage de cette approche est qu’elle aboutit toujours à des suggestions de modélisation de pipelines qui donnent de bons résultats relatifs. Plus important encore, il peut découvrir des solutions non évidentes et peu intuitives pour les praticiens sans avoir besoin d’une expertise approfondie.

Nous pouvons explorer cette approche de la préparation des données avec un exemple concret.

Avant de plonger dans un exemple concret, sélectionnons d’abord un ensemble de données standard et développons une référence en matière de performances.

Ensemble de données et référence de performances

Dans cette section, nous sélectionnerons d’abord un ensemble de données d’apprentissage automatique standard et établirons une référence en matière de performances sur cet ensemble de données. Cela fournira le contexte pour explorer la méthode de recherche par grille de préparation des données dans la section suivante.

Ensemble de données de classification des vins

Nous utiliserons le jeu de données de classification des vins.

Cet ensemble de données comporte 13 variables d'entrée qui décrivent la composition chimique des échantillons de vin et nécessitent que le vin soit classé dans l'un des trois types.

Vous pouvez en savoir plus sur l'ensemble de données ici :

  • Ensemble de données sur le vin (wine.csv)
  • Description de l'ensemble de données sur le vin (wine.names)

Pas besoin de télécharger l'ensemble de données car nous le téléchargerons automatiquement dans le cadre de nos exemples concrets.

Ouvrez l'ensemble de données et examinez les données brutes. Les premières lignes de données sont répertoriées ci-dessous.

Nous pouvons voir qu’il s’agit d’un problème de modélisation prédictive de classification multi-classes avec des variables d’entrée numériques, chacune ayant des échelles différentes.

14.23,1.71,2.43,15.6,127,2.8,3.06,.28,2.29,5.64,1.04,3.92,1065,1
13.2,1.78,2.14,11.2,100,2.65,2.76,.26,1.28,4.38,1.05,3.4,1050,1
13.16,2.36,2.67,18.6,101,2.8,3.24,.3,2.81,5.68,1.03,3.17,1185,1
14.37,1.95,2.5,16.8,113,3.85,3.49,.24,2.18,7.8,.86,3.45,1480,1
13.24,2.59,2.87,21,118,2.8,2.69,.39,1.82,4.32,1.04,2.93,735,1
...

L'exemple ci-dessous charge l'ensemble de données et le divise en colonnes d'entrée et de sortie, puis résume les tableaux de données.

# example of loading and summarizing the wine dataset
from pandas import read_csv
# define the location of the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
# load the dataset as a data frame
df = read_csv(url, header=None)
# retrieve the numpy array
data = df.values
# split the columns into input and output variables
X, y = data[:, :-1], data[:, -1]
# summarize the shape of the loaded data
print(X.shape, y.shape)

En exécutant l'exemple, nous pouvons voir que l'ensemble de données a été chargé correctement et qu'il y a 179 lignes de données avec 13 variables d'entrée et une seule variable cible.

(178, 13) (178,)

Ensuite, évaluons un modèle sur cet ensemble de données et établissons une référence en matière de performances.

Performances du modèle de référence

Nous pouvons établir une référence de performance pour la tâche de classification des vins en évaluant un modèle sur les données brutes d'entrée.

Dans ce cas, nous évaluerons un modèle de régression logistique.

Tout d'abord, nous pouvons définir une fonction pour charger l'ensemble de données et effectuer une préparation minimale des données pour garantir que les entrées sont numériques et que la cible est codée en étiquettes.

# prepare the dataset
def load_dataset():
	# load the dataset
	url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
	df = read_csv(url, header=None)
	data = df.values
	X, y = data[:, :-1], data[:, -1]
	# minimally prepare dataset
	X = X.astype('float')
	y = LabelEncoder().fit_transform(y.astype('str'))
	return X, y

Nous évaluerons le modèle en utilisant l'étalon-or de la validation croisée stratifiée répétée k fois avec 10 fois et trois répétitions.

# evaluate a model
def evaluate_model(X, y, model):
	# define the cross-validation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

Nous pouvons ensuite appeler la fonction pour charger l'ensemble de données, définir notre modèle, puis l'évaluer, en rapportant la précision de la moyenne et de l'écart type.

...
# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# evaluate the model
scores = evaluate_model(X, y, model)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

En reliant cela ensemble, l'exemple complet d'évaluation d'un modèle de régression logistique sur l'ensemble de données de classification des vins bruts est répertorié ci-dessous.

# baseline model performance on the wine dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression

# prepare the dataset
def load_dataset():
	# load the dataset
	url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
	df = read_csv(url, header=None)
	data = df.values
	X, y = data[:, :-1], data[:, -1]
	# minimally prepare dataset
	X = X.astype('float')
	y = LabelEncoder().fit_transform(y.astype('str'))
	return X, y

# evaluate a model
def evaluate_model(X, y, model):
	# define the cross-validation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# evaluate the model
scores = evaluate_model(X, y, model)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

L’exécution de l’exemple évalue les performances du modèle et rapporte la précision de la classification de la moyenne et de l’écart type.

Remarque : Vos résultats peuvent varier en raison de la nature stochastique de l'algorithme ou de la procédure d'évaluation, ou des différences de précision numérique. Pensez à exécuter l’exemple plusieurs fois et comparez le résultat moyen.

Dans ce cas, nous pouvons voir que l’ajustement du modèle de régression logistique sur les données d’entrée brutes a atteint une précision de classification moyenne d’environ 95,3 %, fournissant ainsi une référence en matière de performances.

Accuracy: 0.953 (0.048)

Voyons ensuite si nous pouvons améliorer les performances en utilisant l'approche de préparation des données basée sur la recherche par grille.

Approche de recherche de grille pour la préparation des données

Dans cette section, nous pouvons explorer si nous pouvons améliorer les performances en utilisant l'approche de recherche par grille pour la préparation des données.

La première étape consiste à définir une série de pipelines de modélisation à évaluer, où chaque pipeline définit une (ou plusieurs) techniques de préparation de données et se termine par un modèle qui prend les données transformées en entrée.

Nous définirons une fonction pour créer ces pipelines sous la forme d'une liste de tuples, où chaque tuple définit le nom court du pipeline et du pipeline lui-même. Nous évaluerons une gamme de différentes méthodes de mise à l'échelle des données (par exemple MinMaxScaler et StandardScaler), des transformations de distribution (QuantileTransformer et KBinsDiscretizer), ainsi que des transformations de réduction de dimensionnalité (PCA et SVD).

# get modeling pipelines to evaluate
def get_pipelines(model):
	pipelines = list()
	# normalize
	p = Pipeline([('s',MinMaxScaler()), ('m',model)])
	pipelines.append(('norm', p))
	# standardize
	p = Pipeline([('s',StandardScaler()), ('m',model)])
	pipelines.append(('std', p))
	# quantile
	p = Pipeline([('s',QuantileTransformer(n_quantiles=100, output_distribution='normal')), ('m',model)])
	pipelines.append(('quan', p))
	# discretize
	p = Pipeline([('s',KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')), ('m',model)])
	pipelines.append(('kbins', p))
	# pca
	p = Pipeline([('s',PCA(n_components=7)), ('m',model)])
	pipelines.append(('pca', p))
	# svd
	p = Pipeline([('s',TruncatedSVD(n_components=7)), ('m',model)])
	pipelines.append(('svd', p))
	return pipelines

Nous pouvons ensuite appeler cette fonction pour obtenir la liste des transformations, puis les énumérer, les évaluer et rapporter les performances en cours de route.

...
# get the modeling pipelines
pipelines = get_pipelines(model)
# evaluate each pipeline
results, names = list(), list()
for name, pipeline in pipelines:
	# evaluate
	scores = evaluate_model(X, y, pipeline)
	# summarize
	print('>%s: %.3f (%.3f)' % (name, mean(scores), std(scores)))
	# store
	results.append(scores)
	names.append(name)

À la fin de l’analyse, nous pouvons créer un diagramme en boîte et moustaches pour chaque ensemble de scores et comparer visuellement les distributions des résultats.

...
# plot the result
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

En reliant cela ensemble, l'exemple complet de techniques de préparation de données de recherche de grille sur l'ensemble de données de classification des vins est répertorié ci-dessous.

# compare data preparation methods for the wine classification dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import QuantileTransformer
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.decomposition import PCA
from sklearn.decomposition import TruncatedSVD
from matplotlib import pyplot

# prepare the dataset
def load_dataset():
	# load the dataset
	url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
	df = read_csv(url, header=None)
	data = df.values
	X, y = data[:, :-1], data[:, -1]
	# minimally prepare dataset
	X = X.astype('float')
	y = LabelEncoder().fit_transform(y.astype('str'))
	return X, y

# evaluate a model
def evaluate_model(X, y, model):
	# define the cross-validation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# get modeling pipelines to evaluate
def get_pipelines(model):
	pipelines = list()
	# normalize
	p = Pipeline([('s',MinMaxScaler()), ('m',model)])
	pipelines.append(('norm', p))
	# standardize
	p = Pipeline([('s',StandardScaler()), ('m',model)])
	pipelines.append(('std', p))
	# quantile
	p = Pipeline([('s',QuantileTransformer(n_quantiles=100, output_distribution='normal')), ('m',model)])
	pipelines.append(('quan', p))
	# discretize
	p = Pipeline([('s',KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')), ('m',model)])
	pipelines.append(('kbins', p))
	# pca
	p = Pipeline([('s',PCA(n_components=7)), ('m',model)])
	pipelines.append(('pca', p))
	# svd
	p = Pipeline([('s',TruncatedSVD(n_components=7)), ('m',model)])
	pipelines.append(('svd', p))
	return pipelines

# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# get the modeling pipelines
pipelines = get_pipelines(model)
# evaluate each pipeline
results, names = list(), list()
for name, pipeline in pipelines:
	# evaluate
	scores = evaluate_model(X, y, pipeline)
	# summarize
	print('>%s: %.3f (%.3f)' % (name, mean(scores), std(scores)))
	# store
	results.append(scores)
	names.append(name)
# plot the result
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

L’exécution de l’exemple évalue les performances de chaque pipeline et signale la précision de la classification de la moyenne et de l’écart type.

Remarque : Vos résultats peuvent varier en raison de la nature stochastique de l'algorithme ou de la procédure d'évaluation, ou des différences de précision numérique. Pensez à exécuter l’exemple plusieurs fois et comparez le résultat moyen.

Dans ce cas, nous pouvons constater que la normalisation des variables d'entrée et l'utilisation d'une transformation quantile permettent d'obtenir le meilleur résultat avec une précision de classification d'environ 98,7 pour cent, une amélioration par rapport à la ligne de base sans préparation de données qui a permis d'obtenir une précision de classification de 95,3 pour cent.

Vous pouvez ajouter vos propres pipelines de modélisation à la fonction get_pipelines() et comparer leur résultat.

Pouvez-vous obtenir de meilleurs résultats ?
Faites-le moi savoir dans les commentaires ci-dessous.

>norm: 0.976 (0.031)
>std: 0.987 (0.023)
>quan: 0.987 (0.023)
>kbins: 0.968 (0.045)
>pca: 0.963 (0.039)
>svd: 0.953 (0.048)

Une figure est créée montrant des diagrammes en boîte et en moustaches qui résument la distribution des scores d'exactitude de classification pour chaque technique de préparation des données. Nous pouvons voir que la distribution des scores pour la standardisation et les transformations quantiles est compacte et très similaire et présente une valeur aberrante. Nous pouvons voir que l’écart des scores pour les autres transformations est plus large et asymétrique.

Les résultats peuvent suggérer que la standardisation de l'ensemble de données est probablement une étape importante dans la préparation des données et les transformations associées, telles que la transformation quantile, et peut-être même que la transformation de puissance peut offrir des avantages si elle est combinée à la standardisation en rendant une ou plusieurs variables d'entrée plus gaussiennes.

Nous pouvons également explorer des séquences de transformations pour voir si elles peuvent améliorer les performances.

Par exemple, nous pourrions vouloir appliquer la sélection de fonctionnalités RFE après la transformation de standardisation pour voir si des résultats identiques ou meilleurs peuvent être utilisés avec moins de variables d'entrée (par exemple, moins de complexité).

Nous pourrions également vouloir voir si une transformation de puissance précédée d'une transformation de mise à l'échelle des données peut obtenir de bonnes performances sur l'ensemble de données, comme nous le pensons, étant donné le succès de la transformation quantile.

La fonction get_pipelines() mise à jour avec des séquences de transformations est fournie ci-dessous.

# get modeling pipelines to evaluate
def get_pipelines(model):
	pipelines = list()
	# standardize
	p = Pipeline([('s',StandardScaler()), ('r', RFE(estimator=LogisticRegression(solver='liblinear'), n_features_to_select=10)), ('m',model)])
	pipelines.append(('std', p))
	# scale and power
	p = Pipeline([('s',MinMaxScaler((1,2))), ('p', PowerTransformer()), ('m',model)])
	pipelines.append(('power', p))
	return pipelines

En reliant cela ensemble, l’exemple complet est répertorié ci-dessous.

# compare sequences of data preparation methods for the wine classification dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import QuantileTransformer
from sklearn.preprocessing import PowerTransformer
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.decomposition import PCA
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_selection import RFE
from matplotlib import pyplot

# prepare the dataset
def load_dataset():
	# load the dataset
	url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
	df = read_csv(url, header=None)
	data = df.values
	X, y = data[:, :-1], data[:, -1]
	# minimally prepare dataset
	X = X.astype('float')
	y = LabelEncoder().fit_transform(y.astype('str'))
	return X, y

# evaluate a model
def evaluate_model(X, y, model):
	# define the cross-validation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# get modeling pipelines to evaluate
def get_pipelines(model):
	pipelines = list()
	# standardize
	p = Pipeline([('s',StandardScaler()), ('r', RFE(estimator=LogisticRegression(solver='liblinear'), n_features_to_select=10)), ('m',model)])
	pipelines.append(('std', p))
	# scale and power
	p = Pipeline([('s',MinMaxScaler((1,2))), ('p', PowerTransformer()), ('m',model)])
	pipelines.append(('power', p))
	return pipelines

# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# get the modeling pipelines
pipelines = get_pipelines(model)
# evaluate each pipeline
results, names = list(), list()
for name, pipeline in pipelines:
	# evaluate
	scores = evaluate_model(X, y, pipeline)
	# summarize
	print('>%s: %.3f (%.3f)' % (name, mean(scores), std(scores)))
	# store
	results.append(scores)
	names.append(name)
# plot the result
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

L’exécution de l’exemple évalue les performances de chaque pipeline et signale la précision de la classification de la moyenne et de l’écart type.

Remarque : Vos résultats peuvent varier en raison de la nature stochastique de l'algorithme ou de la procédure d'évaluation, ou des différences de précision numérique. Pensez à exécuter l’exemple plusieurs fois et comparez le résultat moyen.

Dans ce cas, nous pouvons constater que la standardisation avec sélection de fonctionnalités offre une augmentation supplémentaire de la précision de 98,7 % à 98,9 %, bien que la mise à l'échelle des données et la transformation de puissance n'offrent aucun avantage supplémentaire par rapport à la transformation quantile.

>std: 0.989 (0.022)
>power: 0.987 (0.023)

Une figure est créée montrant des diagrammes en boîte et en moustaches qui résument la distribution des scores d'exactitude de classification pour chaque technique de préparation des données.

Nous pouvons voir que la distribution des résultats pour les deux pipelines de transformations est compacte avec très peu de dispersion autre que les valeurs aberrantes.

Lectures complémentaires

Cette section fournit plus de ressources sur le sujet si vous souhaitez approfondir.

Livres

  • Ingénierie et sélection des fonctionnalités, 2019.
  • Ingénierie des fonctionnalités pour l'apprentissage automatique, 2018.

Apis

  • API sklearn.pipeline.Pipeline.

Résumé

Dans ce didacticiel, vous avez découvert comment utiliser une approche de recherche par grille pour la préparation de données avec des données tabulaires.

Concrètement, vous avez appris :

  • La recherche par grille offre une approche alternative à la préparation des données pour les données tabulaires, où les transformations sont essayées en tant qu'hyperparamètres du pipeline de modélisation.
  • Comment utiliser la méthode de recherche par grille pour la préparation des données afin d'améliorer les performances du modèle par rapport à une référence pour un ensemble de données de classification standard.
  • Comment griller les séquences de recherche des méthodes de préparation des données pour améliorer encore les performances du modèle.

Avez-vous des questions ?
Posez vos questions dans les commentaires ci-dessous et je ferai de mon mieux pour y répondre.

Articles connexes