Comment créer des transformations de données personnalisées pour Scikit-Learn
La bibliothèque Python scikit-learn pour l'apprentissage automatique propose une suite de transformations de données pour modifier l'échelle et la distribution des données d'entrée, ainsi que pour supprimer les fonctionnalités d'entrée (colonnes).
Il existe de nombreuses opérations simples de nettoyage des données, telles que la suppression des valeurs aberrantes et la suppression des colonnes contenant peu d'observations, qui sont souvent effectuées manuellement sur les données, nécessitant un code personnalisé.
La bibliothèque scikit-learn fournit un moyen d'encapsuler ces transformations de données personnalisées de manière standard afin qu'elles puissent être utilisées comme n'importe quelle autre transformation, soit sur des données directement, soit dans le cadre d'un pipeline de modélisation.
Dans ce didacticiel, vous découvrirez comment définir et utiliser des transformations de données personnalisées pour scikit-learn.
Après avoir terminé ce tutoriel, vous saurez :
- Ces transformations de données personnalisées peuvent être créées pour scikit-learn à l'aide de la classe FunctionTransformer.
- Comment développer et appliquer une transformation personnalisée pour supprimer les colonnes avec peu de valeurs uniques.
- Comment développer et appliquer une transformation personnalisée qui remplace les valeurs aberrantes pour chaque colonne.
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 quatre parties ; ils sont:
- Transformations de données personnalisées dans Scikit-Learn
- Ensemble de données sur les marées noires
- Transformation personnalisée pour supprimer des colonnes
- Transformation personnalisée pour remplacer les valeurs aberrantes
Transformations de données personnalisées dans Scikit-Learn
La préparation des données fait référence à la modification des données brutes d'une manière qui les rend plus appropriées pour la modélisation prédictive avec des algorithmes d'apprentissage automatique.
La bibliothèque d'apprentissage automatique Python scikit-learn propose directement de nombreuses techniques de préparation de données différentes, telles que des techniques de mise à l'échelle des variables d'entrée numériques et de modification de la distribution de probabilité des variables.
Ces transformations peuvent être ajustées puis appliquées sur un ensemble de données ou utilisées dans le cadre d'un pipeline de modélisation prédictive, permettant d'appliquer correctement une séquence de transformations sans fuite de données lors de l'évaluation des performances du modèle avec des techniques d'échantillonnage de données, telles que la validation croisée k fois. .
Bien que les techniques de préparation des données disponibles dans scikit-learn soient étendues, des étapes de préparation des données supplémentaires peuvent être nécessaires.
En règle générale, ces étapes supplémentaires sont effectuées manuellement avant la modélisation et nécessitent l'écriture de code personnalisé. Le risque est que ces étapes de préparation des données soient effectuées de manière incohérente.
La solution consiste à créer une transformation de données personnalisée dans scikit-learn à l'aide de la classe FunctionTransformer.
Cette classe vous permet de spécifier une fonction appelée pour transformer les données. Vous pouvez définir la fonction et effectuer toute modification valide, telle que modifier des valeurs ou supprimer des colonnes de données (sans supprimer de lignes).
La classe peut ensuite être utilisée comme n'importe quelle autre transformation de données dans scikit-learn, par ex. pour transformer les données directement, ou utilisé dans un pipeline de modélisation.
Le problème est que la transformation est sans état, ce qui signifie qu'aucun état ne peut être conservé.
Cela signifie que la transformation ne peut pas être utilisée pour calculer des statistiques sur l'ensemble de données d'entraînement qui sont ensuite utilisées pour transformer les ensembles de données d'entraînement et de test.
En plus des opérations de mise à l'échelle personnalisées, cela peut être utile pour les opérations de nettoyage de données standard, telles que l'identification et la suppression des colonnes avec peu de valeurs uniques et l'identification et la suppression des valeurs aberrantes relatives.
Nous explorerons ces deux cas, mais commençons par définir un ensemble de données que nous pouvons utiliser comme base d’exploration.
Ensemble de données sur les marées noires
L’ensemble de données dit « marée noire » est un ensemble de données d’apprentissage automatique standard.
La tâche consiste à prédire si une zone contient ou non une marée noire, par ex. du déversement illégal ou accidentel de pétrole dans l’océan, à partir d’un vecteur qui décrit le contenu d’une parcelle d’image satellite.
Il y a 937 cas. Chaque cas est composé de 48 fonctionnalités numériques dérivées de la vision par ordinateur, d'un numéro de patch et d'une étiquette de classe.
Le cas normal est qu'aucun déversement d'hydrocarbures ne reçoit l'étiquette de classe 0, alors qu'un déversement d'hydrocarbures est indiqué par une étiquette de classe de 1. Il existe 896 cas d'absence de déversement d'hydrocarbures et 41 cas de déversement d'hydrocarbures.
Vous pouvez accéder à l’intégralité de l’ensemble de données ici :
- Ensemble de données sur les déversements d'hydrocarbures (oil-spill.csv)
- Description de l'ensemble de données sur les déversements d'hydrocarbures (oil-spill.names)
Vérifiez le contenu du fichier.
Les premières lignes du fichier devraient ressembler à ceci :
1,2558,1506.09,456.63,90,6395000,40.88,7.89,29780,0.19,214.7,0.21,0.26,0.49,0.1,0.4,99.59,32.19,1.84,0.16,0.2,87.65,0,0.47,132.78,-0.01,3.78,0.22,3.2,-3.71,-0.18,2.19,0,2.19,310,16110,0,138.68,89,69,2850,1000,763.16,135.46,3.73,0,33243.19,65.74,7.95,1
2,22325,79.11,841.03,180,55812500,51.11,1.21,61900,0.02,901.7,0.02,0.03,0.11,0.01,0.11,6058.23,4061.15,2.3,0.02,0.02,87.65,0,0.58,132.78,-0.01,3.78,0.84,7.09,-2.21,0,0,0,0,704,40140,0,68.65,89,69,5750,11500,9593.48,1648.8,0.6,0,51572.04,65.73,6.26,0
3,115,1449.85,608.43,88,287500,40.42,7.34,3340,0.18,86.1,0.21,0.32,0.5,0.17,0.34,71.2,16.73,1.82,0.19,0.29,87.65,0,0.46,132.78,-0.01,3.78,0.7,4.79,-3.36,-0.23,1.95,0,1.95,29,1530,0.01,38.8,89,69,1400,250,150,45.13,9.33,1,31692.84,65.81,7.84,1
4,1201,1562.53,295.65,66,3002500,42.4,7.97,18030,0.19,166.5,0.21,0.26,0.48,0.1,0.38,120.22,33.47,1.91,0.16,0.21,87.65,0,0.48,132.78,-0.01,3.78,0.84,6.78,-3.54,-0.33,2.2,0,2.2,183,10080,0,108.27,89,69,6041.52,761.58,453.21,144.97,13.33,1,37696.21,65.67,8.07,1
5,312,950.27,440.86,37,780000,41.43,7.03,3350,0.17,232.8,0.15,0.19,0.35,0.09,0.26,289.19,48.68,1.86,0.13,0.16,87.65,0,0.47,132.78,-0.01,3.78,0.02,2.28,-3.44,-0.44,2.19,0,2.19,45,2340,0,14.39,89,69,1320.04,710.63,512.54,109.16,2.58,0,29038.17,65.66,7.35,0
...
Nous pouvons voir que la première colonne contient des entiers pour le numéro de patch. Nous pouvons également voir que les caractéristiques dérivées de la vision par ordinateur ont une valeur réelle avec différentes échelles, telles que des milliers dans la deuxième colonne et des fractions dans d'autres colonnes.
Cet ensemble de données contient des colonnes avec très peu de valeurs uniques et des colonnes avec des valeurs aberrantes qui constituent une bonne base pour le nettoyage des données.
L'exemple ci-dessous télécharge l'ensemble de données et le charge sous forme de tableau numPy et résume le nombre de lignes et de colonnes.
# load the oil dataset
from pandas import read_csv
# define the location of the dataset
path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/oil-spill.csv'
# load the dataset
df = read_csv(path, header=None)
# split data into inputs and outputs
data = df.values
X = data[:, :-1]
y = data[:, -1]
print(X.shape, y.shape)
L'exécution de l'exemple charge l'ensemble de données et confirme le nombre attendu de lignes et de colonnes.
(937, 49) (937,)
Maintenant que nous disposons d'un ensemble de données que nous pouvons utiliser comme base pour les transformations de données, voyons comment définir des transformations de nettoyage de données personnalisées à l'aide de la classe FunctionTransformer.
Transformation personnalisée pour supprimer des colonnes
Les colonnes qui ont peu de valeurs uniques ne contribuent probablement pas à prédire la valeur cible.
Ce n'est pas absolument vrai, mais c'est suffisamment vrai pour que vous testiez les performances de l'ajustement de votre modèle sur un ensemble de données sans colonnes de ce type.
Il s'agit d'un type de nettoyage des données, et il existe une transformation de données fournie dans scikit-learn appelée VarianceThreshold qui tente de résoudre ce problème en utilisant la variance de chaque colonne.
Une autre approche consiste à supprimer les colonnes qui contiennent moins d'un nombre spécifié de valeurs uniques, telles que 1.
Nous pouvons développer une fonction qui applique cette transformation et utiliser le nombre minimum de valeurs uniques comme argument par défaut configurable. Nous ajouterons également du débogage pour confirmer qu'il fonctionne comme prévu.
Tout d'abord, le nombre de valeurs uniques pour chaque colonne peut être calculé. Dix colonnes avec un nombre égal ou inférieur au nombre minimum de valeurs uniques peuvent être identifiées. Enfin, ces colonnes identifiées peuvent être supprimées de l'ensemble de données.
La fonction cust_transform() ci-dessous implémente cela.
# remove columns with few unique values
def cust_transform(X, min_values=1, verbose=True):
# get number of unique values for each column
counts = [len(unique(X[:, i])) for i in range(X.shape[1])]
if verbose:
print('Unique Values: %s' % counts)
# select columns to delete
to_del = [i for i,v in enumerate(counts) if v <= min_values]
if verbose:
print('Deleting: %s' % to_del)
if len(to_del) is 0:
return X
# select all but the columns that are being removed
ix = [i for i in range(X.shape[1]) if i not in to_del]
result = X[:, ix]
return result
Nous pouvons ensuite utiliser cette fonction dans le FunctionTransformer.
Une limitation de cette transformation est qu'elle sélectionne les colonnes à supprimer en fonction des données fournies. Cela signifie que si un ensemble de données d'entraînement et de test diffèrent grandement, il est alors possible que différentes colonnes soient supprimées de chacun, ce qui rend l'évaluation du modèle difficile (instable !?). Il est donc préférable de limiter le nombre minimum de valeurs uniques, par exemple 1.
Nous pouvons utiliser cette transformation sur l’ensemble de données sur les marées noires. L’exemple complet est répertorié ci-dessous.
# custom data transform for removing columns with few unique values
from numpy import unique
from pandas import read_csv
from sklearn.preprocessing import FunctionTransformer
from sklearn.preprocessing import LabelEncoder
# load a dataset
def load_dataset(path):
# load the dataset
df = read_csv(path, header=None)
data = df.values
# split data into inputs and outputs
X, y = data[:, :-1], data[:, -1]
# minimally prepare dataset
X = X.astype('float')
y = LabelEncoder().fit_transform(y.astype('str'))
return X, y
# remove columns with few unique values
def cust_transform(X, min_values=1, verbose=True):
# get number of unique values for each column
counts = [len(unique(X[:, i])) for i in range(X.shape[1])]
if verbose:
print('Unique Values: %s' % counts)
# select columns to delete
to_del = [i for i,v in enumerate(counts) if v <= min_values]
if verbose:
print('Deleting: %s' % to_del)
if len(to_del) is 0:
return X
# select all but the columns that are being removed
ix = [i for i in range(X.shape[1]) if i not in to_del]
result = X[:, ix]
return result
# define the location of the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/oil-spill.csv'
# load the dataset
X, y = load_dataset(url)
print(X.shape, y.shape)
# define the transformer
trans = FunctionTransformer(cust_transform)
# apply the transform
X = trans.fit_transform(X)
# summarize new shape
print(X.shape)
L’exécution de l’exemple indique d’abord le nombre de lignes et de colonnes dans l’ensemble de données brutes.
Ensuite, une liste est imprimée qui montre le nombre de valeurs uniques observées pour chaque colonne de l'ensemble de données. Nous pouvons voir que de nombreuses colonnes ont très peu de valeurs uniques.
Les colonnes avec une (ou plusieurs) valeurs uniques sont ensuite identifiées et signalées. Dans ce cas, l'index de colonne 22. Cette colonne est supprimée de l'ensemble de données.
Enfin, la forme de l'ensemble de données transformé est signalée, affichant 48 colonnes au lieu de 49, confirmant que la colonne avec une seule valeur unique a été supprimée.
(937, 49) (937,)
Unique Values: [238, 297, 927, 933, 179, 375, 820, 618, 561, 57, 577, 59, 73, 107, 53, 91, 893, 810, 170, 53, 68, 9, 1, 92, 9, 8, 9, 308, 447, 392, 107, 42, 4, 45, 141, 110, 3, 758, 9, 9, 388, 220, 644, 649, 499, 2, 937, 169, 286]
Deleting: [22]
(937, 48)
Il existe de nombreuses extensions que vous pouvez explorer pour cette transformation, telles que :
- Assurez-vous qu'il s'applique uniquement aux variables d'entrée numériques.
- Expérimentez avec un nombre minimum différent de valeurs uniques.
- Utilisez un pourcentage plutôt qu'un nombre absolu de valeurs uniques.
Si vous explorez l'une de ces extensions, faites-le moi savoir dans les commentaires ci-dessous.
Examinons ensuite une transformation qui remplace les valeurs dans l'ensemble de données.
Transformation personnalisée pour remplacer les valeurs aberrantes
Les valeurs aberrantes sont des observations différentes ou différentes des autres observations.
Si nous considérons une variable à la fois, une valeur aberrante serait une valeur éloignée du centre de masse (le reste des valeurs), ce qui signifie qu'elle est rare ou a une faible probabilité d'être observée.
Il existe des méthodes standard pour identifier les valeurs aberrantes pour les distributions de probabilité courantes. Pour les données gaussiennes, nous pouvons identifier les valeurs aberrantes comme des observations qui se situent à trois écarts types ou plus de la moyenne.
Cela peut être ou non un moyen souhaitable d'identifier les valeurs aberrantes pour les données comportant de nombreuses variables d'entrée, mais cela peut être efficace dans certains cas.
Nous pouvons ainsi identifier les valeurs aberrantes et remplacer leur valeur par une correction, telle que la moyenne.
Chaque colonne est considérée une à la fois et les statistiques de moyenne et d'écart type sont calculées. À l'aide de ces statistiques, les limites supérieure et inférieure des valeurs « normales » sont définies, puis toutes les valeurs qui se situent en dehors de ces limites peuvent être identifiées. Si une ou plusieurs valeurs aberrantes sont identifiées, leurs valeurs sont alors remplacées par la valeur moyenne déjà calculée.
La fonction cust_transform() ci-dessous implémente cela en tant que fonction appliquée à l'ensemble de données, où nous paramétrons le nombre d'écarts types par rapport à la moyenne et si les informations de débogage seront affichées ou non.
# replace outliers
def cust_transform(X, n_stdev=3, verbose=True):
# copy the array
result = X.copy()
# enumerate each column
for i in range(result.shape[1]):
# retrieve values for column
col = X[:, i]
# calculate statistics
mu, sigma = mean(col), std(col)
# define bounds
lower, upper = mu-(sigma*n_stdev), mu+(sigma*n_stdev)
# select indexes that are out of bounds
ix = where(logical_or(col < lower, col > upper))[0]
if verbose and len(ix) > 0:
print('>col=%d, outliers=%d' % (i, len(ix)))
# replace values
result[ix, i] = mu
return result
Nous pouvons ensuite utiliser cette fonction dans le FunctionTransformer.
La méthode de détection des valeurs aberrantes suppose une distribution de probabilité gaussienne et s'applique à chaque variable indépendamment, ce qui constitue toutes deux des hypothèses fortes.
Une limitation supplémentaire de cette implémentation est que les statistiques de moyenne et d'écart type sont calculées sur l'ensemble de données fourni, ce qui signifie que la définition d'une valeur aberrante et sa valeur de remplacement sont toutes deux relatives à l'ensemble de données. Cela signifie que différentes définitions de valeurs aberrantes et différentes valeurs de remplacement pourraient être utilisées si la transformation est utilisée sur les ensembles d'entraînement et de test.
Nous pouvons utiliser cette transformation sur l’ensemble de données sur les marées noires. L’exemple complet est répertorié ci-dessous.
# custom data transform for replacing outliers
from numpy import mean
from numpy import std
from numpy import where
from numpy import logical_or
from pandas import read_csv
from sklearn.preprocessing import FunctionTransformer
from sklearn.preprocessing import LabelEncoder
# load a dataset
def load_dataset(path):
# load the dataset
df = read_csv(path, header=None)
data = df.values
# split data into inputs and outputs
X, y = data[:, :-1], data[:, -1]
# minimally prepare dataset
X = X.astype('float')
y = LabelEncoder().fit_transform(y.astype('str'))
return X, y
# replace outliers
def cust_transform(X, n_stdev=3, verbose=True):
# copy the array
result = X.copy()
# enumerate each column
for i in range(result.shape[1]):
# retrieve values for column
col = X[:, i]
# calculate statistics
mu, sigma = mean(col), std(col)
# define bounds
lower, upper = mu-(sigma*n_stdev), mu+(sigma*n_stdev)
# select indexes that are out of bounds
ix = where(logical_or(col < lower, col > upper))[0]
if verbose and len(ix) > 0:
print('>col=%d, outliers=%d' % (i, len(ix)))
# replace values
result[ix, i] = mu
return result
# define the location of the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/oil-spill.csv'
# load the dataset
X, y = load_dataset(url)
print(X.shape, y.shape)
# define the transformer
trans = FunctionTransformer(cust_transform)
# apply the transform
X = trans.fit_transform(X)
# summarize new shape
print(X.shape)
L’exécution de l’exemple signale d’abord la forme de l’ensemble de données avant toute modification.
Ensuite, le nombre de valeurs aberrantes pour chaque colonne est calculé et seules les colonnes comportant une ou plusieurs valeurs aberrantes sont signalées dans le résultat. Nous pouvons voir qu'un total de 32 colonnes de l'ensemble de données comportent une ou plusieurs valeurs aberrantes.
Les valeurs aberrantes sont ensuite supprimées et la forme de l'ensemble de données résultant est signalée, confirmant l'absence de changement dans le nombre de lignes ou de colonnes.
(937, 49) (937,)
>col=0, outliers=10
>col=1, outliers=8
>col=3, outliers=8
>col=5, outliers=7
>col=6, outliers=1
>col=7, outliers=12
>col=8, outliers=15
>col=9, outliers=14
>col=10, outliers=19
>col=11, outliers=17
>col=12, outliers=22
>col=13, outliers=2
>col=14, outliers=16
>col=15, outliers=8
>col=16, outliers=8
>col=17, outliers=6
>col=19, outliers=12
>col=20, outliers=20
>col=27, outliers=14
>col=28, outliers=18
>col=29, outliers=2
>col=30, outliers=13
>col=32, outliers=3
>col=34, outliers=14
>col=35, outliers=15
>col=37, outliers=13
>col=40, outliers=18
>col=41, outliers=13
>col=42, outliers=12
>col=43, outliers=12
>col=44, outliers=19
>col=46, outliers=21
(937, 49)
Il existe de nombreuses extensions que vous pouvez explorer pour cette transformation, telles que :
- Assurez-vous qu'il s'applique uniquement aux variables d'entrée numériques.
- Expérimentez avec un nombre différent d'écarts types par rapport à la moyenne, par exemple 2 ou 4.
- Utilisez une définition différente de la valeur aberrante, telle que l'IQR ou un modèle.
Si vous explorez l'une de ces extensions, faites-le moi savoir dans les commentaires ci-dessous.
Lectures complémentaires
Cette section fournit plus de ressources sur le sujet si vous souhaitez approfondir.
Tutoriels connexes
- Comment supprimer les valeurs aberrantes pour l'apprentissage automatique
- Comment effectuer un nettoyage des données pour l'apprentissage automatique avec Python
Apis
- Transformateurs personnalisés, Guide de l'utilisateur Scikit-Learn.
- API sklearn.preprocessing.FunctionTransformer.
Résumé
Dans ce didacticiel, vous avez découvert comment définir et utiliser des transformations de données personnalisées pour scikit-learn.
Concrètement, vous avez appris :
- Ces transformations de données personnalisées peuvent être créées pour scikit-learn à l'aide de la classe FunctionTransformer.
- Comment développer et appliquer une transformation personnalisée pour supprimer les colonnes avec peu de valeurs uniques.
- Comment développer et appliquer une transformation personnalisée qui remplace les valeurs aberrantes pour chaque colonne.
Avez-vous des questions ?
Posez vos questions dans les commentaires ci-dessous et je ferai de mon mieux pour y répondre.