J'essaie d'utiliser scikit-learn LabelEncoder
pour encoder un pandas DataFrame
d'étiquettes de chaîne. Comme la trame de données contient de nombreuses (50+) colonnes, je veux éviter de créer un LabelEncoder
objet pour chaque colonne; Je préfère simplement avoir un gros LabelEncoder
objet qui fonctionne dans toutes mes colonnes de données.
Lancer le tout DataFrame
dans LabelEncoder
crée l'erreur ci-dessous. Veuillez garder à l'esprit que j'utilise ici des données factices; en réalité, je traite environ 50 colonnes de données étiquetées sous forme de chaîne, donc j'ai besoin d'une solution qui ne référence aucune colonne par son nom.
import pandas
from sklearn import preprocessing
df = pandas.DataFrame({
'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'],
'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'],
'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego',
'New_York']
})
le = preprocessing.LabelEncoder()
le.fit(df)
Traceback (dernier appel le plus récent): Fichier "", ligne 1, dans le fichier "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py", ligne 103, en forme y = column_or_1d (y, warn = True) Fichier "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", ligne 306, dans column_or_1d, augmenter ValueError ("mauvaise forme d'entrée { 0} ". Format (forme)) ValueError: mauvaise forme d'entrée (6, 3)
Avez-vous des idées sur la façon de contourner ce problème?
dataframe
de données de chaîne. Je piclque le (s) objet (s) d'encodage, donc je veux éviter d'avoir à décaper / décaper 50 objets séparés. De plus, je me demande s'il existe un moyen de faire en sorte que l'encodeur simplifie les données, c'est-à-dire en renvoyant simplement une ligne avec un identifiant pour chaque combinaison unique de variables dans chaque colonne.replace
méthode. Voir cette réponse ciRéponses:
Mais vous pouvez facilement le faire,
EDIT2:
Dans scikit-learn 0.20, la méthode recommandée est
car OneHotEncoder prend désormais en charge la saisie de chaîne. L'application de OneHotEncoder uniquement à certaines colonnes est possible avec ColumnTransformer.
ÉDITER:
Étant donné que cette réponse remonte à plus d'un an et qu'elle a généré de nombreux votes positifs (y compris une prime), je devrais probablement prolonger cela.
Pour inverse_transform et transform, vous devez faire un peu de hack.
Avec cela, vous conservez maintenant toutes les colonnes en
LabelEncoder
tant que dictionnaire.la source
df.apply(LabelEncoder().fit_transform)
?LabelBinarizer
place et réutiliser le dictionnaire pour un ensemble de tests? J'ai essayéd = defaultdict(LabelBinarizer)
puis ,fit = df.apply(lambda x: d[x.name].fit_transform(x))
mais une exception est soulevée:Exception: Data must be 1-dimensional
. Je ne sais pas à quoi je pense que le DataFrame résultant ressemblera ... peut-être que chaque colonne devrait contenir les vecteurs binarisés.Comme mentionné par larsmans, LabelEncoder () prend uniquement un tableau 1-d comme argument . Cela dit, il est assez facile de faire rouler votre propre encodeur d'étiquette qui fonctionne sur plusieurs colonnes de votre choix et renvoie une trame de données transformée. Mon code ici est basé en partie sur l'excellent article de blog de Zac Stewart trouvé ici .
Création d' un encodeur personnalisé consiste à créer simplement une classe qui répond aux
fit()
,transform()
et desfit_transform()
méthodes. Dans votre cas, un bon début pourrait être quelque chose comme ceci:Supposons que nous voulons encoder nos deux attributs catégoriels (
fruit
etcolor
), tout en laissant l'attribut numériqueweight
seul. Nous pourrions le faire comme suit:Qui transforme notre
fruit_data
ensemble de données deà
En lui passant une trame de données composée entièrement de variables catégorielles et en omettant le
columns
paramètre, chaque colonne sera codée (ce qui, je crois, est ce que vous cherchiez à l'origine):Cela transforme
à
.
Notez qu'il s'étouffe probablement quand il essaie d'encoder des attributs qui sont déjà numériques (ajoutez du code pour gérer cela si vous le souhaitez).
Une autre fonctionnalité intéressante à ce sujet est que nous pouvons utiliser ce transformateur personnalisé dans un pipeline:
la source
Depuis scikit-learn 0.20, vous pouvez utiliser
sklearn.compose.ColumnTransformer
etsklearn.preprocessing.OneHotEncoder
:Si vous ne disposez que de variables catégorielles,
OneHotEncoder
directement:Si vous avez des fonctionnalités typées de manière hétérogène:
Plus d'options dans la documentation: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data
la source
inverse_transform()
n'est cependant pas pris en charge sur ColumnTransformer. Du moins, pas pour le moment: github.com/scikit-learn/scikit-learn/issues/11463 . C'est un gros inconvénient pour ma candidature, et le sera probablement aussi pour d'autres.Nous n'avons pas besoin d'un LabelEncoder.
Vous pouvez convertir les colonnes en catégories, puis obtenir leurs codes. J'ai utilisé une compréhension de dictionnaire ci-dessous pour appliquer ce processus à chaque colonne et envelopper le résultat dans une trame de données de la même forme avec des indices et des noms de colonne identiques.
Pour créer un dictionnaire de cartographie, vous pouvez simplement énumérer les catégories à l'aide d'une compréhension de dictionnaire:
la source
cela ne répond pas directement à votre question (pour laquelle Naputipulu Jon et PriceHardman ont des réponses fantastiques)
Cependant, aux fins de quelques tâches de classification, etc., vous pouvez utiliser
cela peut entrer un cadre de données avec des données catégorielles et retourner un cadre de données avec des valeurs binaires. les valeurs des variables sont codées en noms de colonnes dans la trame de données résultante. plus
la source
En supposant que vous essayez simplement d'obtenir un
sklearn.preprocessing.LabelEncoder()
objet pouvant être utilisé pour représenter vos colonnes, tout ce que vous avez à faire est de:Dans le code ci-dessus, vous aurez un numéro unique correspondant à chaque colonne. Plus précisément, vous aurez un mappage 1: 1 de
df.columns
tole.transform(df.columns.get_values())
. Pour obtenir le codage d'une colonne, passez-le simplement àle.transform(...)
. À titre d'exemple, les éléments suivants obtiendront le codage pour chaque colonne:En supposant que vous souhaitez créer un
sklearn.preprocessing.LabelEncoder()
objet pour toutes vos étiquettes de ligne, vous pouvez effectuer les opérations suivantes:Dans ce cas, vous avez très probablement des étiquettes de ligne non uniques (comme indiqué dans votre question). Pour voir quelles classes le codeur a créé, vous pouvez le faire
le.classes_
. Vous remarquerez que cela devrait avoir les mêmes éléments que dansset(y for x in df.get_values() for y in x)
. Encore une fois pour convertir une étiquette de ligne en une utilisation d'étiquette codéele.transform(...)
. Par exemple, si vous souhaitez récupérer l'étiquette de la première colonne dudf.columns
tableau et de la première ligne, vous pouvez procéder comme suit:La question que vous vous posiez dans votre commentaire est un peu plus compliquée, mais peut toujours être accomplie:
Le code ci-dessus fait ce qui suit:
LabelEncoder
classe ne prenant pas en charge les tuples en tant que nom de classe.LabelEncoder
.Maintenant, pour utiliser ce nouveau modèle, c'est un peu plus compliqué. En supposant que nous voulons extraire la représentation pour le même élément que nous avons recherché dans l'exemple précédent (la première colonne dans df.columns et la première ligne), nous pouvons le faire:
N'oubliez pas que chaque recherche est maintenant une représentation sous forme de chaîne d'un tuple qui contient la (colonne, ligne).
la source
Non,
LabelEncoder
ne fait pas ça. Il prend des tableaux 1D d'étiquettes de classe et produit des tableaux 1D. Il est conçu pour gérer les étiquettes de classe dans les problèmes de classification, et non les données arbitraires, et toute tentative de le forcer à d'autres utilisations nécessitera du code pour transformer le problème réel en problème qu'il résout (et la solution dans l'espace d'origine).la source
DataFrame
à la fois?LabelEncoder
code et adaptez-le. Je n'utilise pas les Pandas moi-même, donc je ne sais pas à quel point ce sera difficile.pandas
personnes tenter de répondre à cette question également - je suis sûr que je ne suis pas la seule personne à relever ce défi, alors j'espère qu'il pourrait y avoir une solution préconfigurée.C'est un an et demi après le fait, mais moi aussi, je devais être capable de
.transform()
plusieurs colonnes de trames de données pandas à la fois (et de pouvoir les utiliser.inverse_transform()
également). Cela développe l'excellente suggestion de @PriceHardman ci-dessus:Exemple:
Si
df
etdf_copy()
sont despandas
cadres de données de type mixte, vous pouvez appliquer leMultiColumnLabelEncoder()
auxdtype=object
colonnes de la manière suivante:Vous pouvez accéder aux classes de colonnes individuelles, aux étiquettes de colonnes et aux encodeurs de colonnes utilisés pour ajuster chaque colonne via l'indexation:
mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_
la source
fit
méthode ci-dessus qui ne produira pas d'étiquettes avant de l'appliquer (transform
/fit_transform
) à les données.Dans le prolongement des commentaires soulevés sur la solution de @PriceHardman, je proposerais la version suivante de la classe:
Cette classe s'adapte à l'encodeur sur l'ensemble d'entraînement et utilise la version adaptée lors de la transformation. La version initiale du code peut être trouvée ici .
la source
Un court chemin vers
LabelEncoder()
plusieurs colonnes avec undict()
:et vous pouvez l'utiliser
le_dict
pour étiqueterEncode toute autre colonne:la source
Il est possible de faire tout cela directement chez les pandas et est bien adapté à une capacité unique de la
replace
méthode.Commençons par créer un dictionnaire de dictionnaires mappant les colonnes et leurs valeurs à leurs nouvelles valeurs de remplacement.
Comme ce sera toujours un mappage un à un, nous pouvons inverser le dictionnaire interne pour obtenir un mappage des nouvelles valeurs à l'original.
Maintenant, nous pouvons utiliser la capacité unique de la
replace
méthode de prendre une liste imbriquée de dictionnaires et d'utiliser les clés externes comme colonnes et les clés internes comme valeurs que nous aimerions remplacer.On peut facilement revenir à l'original en enchaînant à nouveau la
replace
méthodela source
Après beaucoup de recherches et d'expérimentation avec quelques réponses ici et ailleurs, je pense que votre réponse est ici :
Cela préservera les noms des catégories dans les colonnes:
la source
J'ai vérifié le code source ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.py ) de LabelEncoder. Il était basé sur un ensemble de transformations numpy, dont l'une est np.unique (). Et cette fonction ne prend qu'une entrée de tableau 1-d. (Corrigez-moi si je me trompe).
Idées très approximatives ... identifiez d'abord les colonnes qui nécessitent LabelEncoder, puis parcourez chaque colonne.
Le rendu df serait celui après le codage, et label_list vous montrera ce que toutes ces valeurs signifient dans la colonne correspondante. Ceci est un extrait d'un script de traitement des données que j'ai écrit pour le travail. Faites-moi savoir si vous pensez qu'il pourrait y avoir d'autres améliorations.
EDIT: Je veux juste mentionner ici que les méthodes ci-dessus fonctionnent avec une trame de données sans manquer le meilleur. Je ne sais pas comment cela fonctionne vers le bloc de données contient des données manquantes. (J'ai eu un accord avec la procédure manquante avant d'exécuter les méthodes ci-dessus)
la source
si nous avons une seule colonne pour faire l'encodage des étiquettes et sa transformation inverse, il est facile de le faire quand il y a plusieurs colonnes en python
la source
Si vous avez les deux types de données numériques et catégoriques dans la trame de données Vous pouvez utiliser: ici X est ma trame de données ayant les deux variables catégorielles et numériques
Remarque: Cette technique est bonne si vous n'êtes pas intéressé à les reconvertir.
la source
Utilisation de Neuraxle
Avec cette méthode, votre encodeur d'étiquette pourra s'adapter et se transformer au sein d'un Pipeline Scikit-Learn régulier . Importons simplement:
Même encodeur partagé pour les colonnes:
Voici comment un LabelEncoder partagé sera appliqué à toutes les données pour le coder:
Résultat:
Encodeurs différents par colonne:
Et voici comment un premier LabelEncoder autonome sera appliqué sur les animaux de compagnie, et un second sera partagé pour le propriétaire et l'emplacement des colonnes. Donc, pour être précis, nous avons ici un mélange d'encodeurs d'étiquettes différents et partagés:
Résultat:
la source
Principalement utilisé la réponse @Alexander mais a dû faire quelques changements -
Ensuite, pour réutiliser à l'avenir, vous pouvez simplement enregistrer la sortie dans un document json et lorsque vous en avez besoin, vous le lisez et utilisez la
.map()
fonction comme je l'ai fait ci-dessus.la source
Le problème est la forme des données (trame de données pd) que vous transmettez à la fonction d'ajustement. Vous devez passer la liste 1d.
la source
Ici, je lis un csv de l'emplacement et en fonction je passe la liste des colonnes que je veux étiqueter et le dataframe que je veux appliquer.
la source
Que dis-tu de ça?
Ce n'est pas le plus efficace, mais ça marche et c'est super simple.
la source