web-dev-qa-db-fra.com

Encodage d'étiquettes sur plusieurs colonnes dans scikit-learn

J'essaie d'utiliser la variable LabelEncoder de scikit-learn pour coder un pandas DataFrame d'étiquettes de chaîne. Étant donné que la structure de données comporte de nombreuses colonnes (plus de 50), je souhaite éviter de créer un objet LabelEncoder pour chaque colonne; Je préférerais simplement avoir un seul gros objet LabelEncoder qui fonctionne dans tout mes colonnes de données. 

Le fait de placer DataFrame entier dans LabelEncoder crée l'erreur ci-dessous. Veuillez garder à l'esprit que j'utilise des données factices ici; En réalité, je traite avec environ 50 colonnes de données étiquetées sous forme de chaîne. Il faut donc 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 passé): Fichier "", ligne 1, dans Fichier "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py", ligne 103, bien adapté 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 raise ValueError ("forme d'entrée incorrecte {0}". format (forme)) ValueError: mauvaise forme d'entrée (6, 3)

Des idées sur la façon de contourner ce problème? 

155
Bryan

Vous pouvez facilement le faire si,

df.apply(LabelEncoder().fit_transform)

MODIFIER:

Cette réponse datant de plus d'un an et ayant généré de nombreux votes positifs (y compris une prime), je devrais probablement étendre cela davantage.

Pour inverse_transform et transform, vous devez faire un peu de piratage.

from collections import defaultdict
d = defaultdict(LabelEncoder)

Avec cela, vous conservez maintenant toutes les colonnes LabelEncoder en tant que dictionnaire.

# Encoding the variable
fit = df.apply(lambda x: d[x.name].fit_transform(x))

# Inverse the encoded
fit.apply(lambda x: d[x.name].inverse_transform(x))

# Using the dictionary to label future data
df.apply(lambda x: d[x.name].transform(x))
319
Napitupulu Jon

Comme mentionné par larsmans, LabelEncoder () ne prend comme argument qu'un tableau à une seule fois . Cela dit, il est assez facile de lancer votre propre encodeur d'étiquettes qui fonctionne sur plusieurs colonnes de votre choix et renvoie une image transformée. Mon code ici est basé en partie sur l'excellent article de blog de Zac Stewart trouvé ici .

La création d'un encodeur personnalisé implique simplement la création d'une classe qui répond aux méthodes fit(), transform() et fit_transform(). Dans votre cas, un bon début pourrait être quelque chose comme ceci:

import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.pipeline import Pipeline

# Create some toy data in a Pandas dataframe
fruit_data = pd.DataFrame({
    'fruit':  ['Apple','orange','pear','orange'],
    'color':  ['red','orange','green','green'],
    'weight': [5,6,3,4]
})

class MultiColumnLabelEncoder:
    def __init__(self,columns = None):
        self.columns = columns # array of column names to encode

    def fit(self,X,y=None):
        return self # not relevant here

    def transform(self,X):
        '''
        Transforms columns of X specified in self.columns using
        LabelEncoder(). If no columns specified, transforms all
        columns in X.
        '''
        output = X.copy()
        if self.columns is not None:
            for col in self.columns:
                output[col] = LabelEncoder().fit_transform(output[col])
        else:
            for colname,col in output.iteritems():
                output[colname] = LabelEncoder().fit_transform(col)
        return output

    def fit_transform(self,X,y=None):
        return self.fit(X,y).transform(X)

Supposons que nous voulions encoder nos deux attributs catégoriques (fruit et color), tout en laissant l'attribut numérique weight seul. Nous pourrions faire ceci comme suit:

MultiColumnLabelEncoder(columns = ['fruit','color']).fit_transform(fruit_data)

Ce qui transforme notre ensemble de données fruit_data à partir de

enter image description here à 

enter image description here

Si vous transmettez une trame de données composée entièrement de variables catégorielles et omettez le paramètre columns, chaque colonne sera codée (ce qui, je crois, correspond à ce que vous recherchiez à l'origine):

MultiColumnLabelEncoder().fit_transform(fruit_data.drop('weight',axis=1))

Cela transforme

enter image description here à

enter image description here.

Notez que cela va probablement s’étouffer lorsqu’il essaiera de coder des attributs déjà numériques (ajoutez du code pour gérer cela si vous le souhaitez).

Une autre caractéristique intéressante de cette fonction est que nous pouvons utiliser ce transformateur personnalisé dans un pipeline:

encoding_pipeline = Pipeline([
    ('encoding',MultiColumnLabelEncoder(columns=['fruit','color']))
    # add more pipeline steps as needed
])
encoding_pipeline.fit_transform(fruit_data)
71
PriceHardman

Nous n'avons pas besoin d'un LabelEncoder.

Vous pouvez convertir les colonnes en catégories, puis obtenir leurs codes. J'ai utilisé un dictionnaire de compréhension ci-dessous pour appliquer ce processus à chaque colonne et pour envelopper le résultat dans une trame de données de même forme avec des index et des noms de colonne identiques.

>>> pd.DataFrame({col: df[col].astype('category').cat.codes for col in df}, index=df.index)
   location  owner  pets
0         1      1     0
1         0      2     1
2         0      0     0
3         1      1     2
4         1      3     1
5         0      2     1

Pour créer un dictionnaire de cartographie, vous pouvez simplement énumérer les catégories à l'aide d'une compréhension du dictionnaire:

>>> {col: {n: cat for n, cat in enumerate(df[col].astype('category').cat.categories)} 
     for col in df}

{'location': {0: 'New_York', 1: 'San_Diego'},
 'owner': {0: 'Brick', 1: 'Champ', 2: 'Ron', 3: 'Veronica'},
 'pets': {0: 'cat', 1: 'dog', 2: 'monkey'}}
11
Alexander

cela ne répond pas directement à votre question (pour laquelle Naputipulu Jon et PriceHardman ont des réponses fantastiques)

Cependant, pour quelques tâches de classification, etc., vous pouvez utiliser

pandas.get_dummies(input_df) 

cela peut entrer dataframe avec des données catégorielles et renvoyer une dataframe avec des valeurs binaires. les valeurs de variables sont codées dans les noms de colonne dans la base de données résultante. plus

6
Anurag Priyadarshi

Cela fait un an et demi après les faits, mais moi aussi, je devais être capable de .transform() plusieurs colonnes du cadre de données du pandas à la fois (et de pouvoir aussi .inverse_transform()). Ceci développe l'excellente suggestion de @PriceHardman ci-dessus:

class MultiColumnLabelEncoder(LabelEncoder):
    """
    Wraps sklearn LabelEncoder functionality for use on multiple columns of a
    pandas dataframe.

    """
    def __init__(self, columns=None):
        self.columns = columns

    def fit(self, dframe):
        """
        Fit label encoder to pandas columns.

        Access individual column classes via indexig `self.all_classes_`

        Access individual column encoders via indexing
        `self.all_encoders_`
        """
        # if columns are provided, iterate through and get `classes_`
        if self.columns is not None:
            # ndarray to hold LabelEncoder().classes_ for each
            # column; should match the shape of specified `columns`
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            self.all_encoders_ = np.ndarray(shape=self.columns.shape,
                                            dtype=object)
            for idx, column in enumerate(self.columns):
                # fit LabelEncoder to get `classes_` for the column
                le = LabelEncoder()
                le.fit(dframe.loc[:, column].values)
                # append the `classes_` to our ndarray container
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                # append this column's encoder
                self.all_encoders_[idx] = le
        else:
            # no columns specified; assume all are to be encoded
            self.columns = dframe.iloc[:, :].columns
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            for idx, column in enumerate(self.columns):
                le = LabelEncoder()
                le.fit(dframe.loc[:, column].values)
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                self.all_encoders_[idx] = le
        return self

    def fit_transform(self, dframe):
        """
        Fit label encoder and return encoded labels.

        Access individual column classes via indexing
        `self.all_classes_`

        Access individual column encoders via indexing
        `self.all_encoders_`

        Access individual column encoded labels via indexing
        `self.all_labels_`
        """
        # if columns are provided, iterate through and get `classes_`
        if self.columns is not None:
            # ndarray to hold LabelEncoder().classes_ for each
            # column; should match the shape of specified `columns`
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            self.all_encoders_ = np.ndarray(shape=self.columns.shape,
                                            dtype=object)
            self.all_labels_ = np.ndarray(shape=self.columns.shape,
                                          dtype=object)
            for idx, column in enumerate(self.columns):
                # instantiate LabelEncoder
                le = LabelEncoder()
                # fit and transform labels in the column
                dframe.loc[:, column] =\
                    le.fit_transform(dframe.loc[:, column].values)
                # append the `classes_` to our ndarray container
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                self.all_encoders_[idx] = le
                self.all_labels_[idx] = le
        else:
            # no columns specified; assume all are to be encoded
            self.columns = dframe.iloc[:, :].columns
            self.all_classes_ = np.ndarray(shape=self.columns.shape,
                                           dtype=object)
            for idx, column in enumerate(self.columns):
                le = LabelEncoder()
                dframe.loc[:, column] = le.fit_transform(
                        dframe.loc[:, column].values)
                self.all_classes_[idx] = (column,
                                          np.array(le.classes_.tolist(),
                                                  dtype=object))
                self.all_encoders_[idx] = le
        return dframe

    def transform(self, dframe):
        """
        Transform labels to normalized encoding.
        """
        if self.columns is not None:
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[
                    idx].transform(dframe.loc[:, column].values)
        else:
            self.columns = dframe.iloc[:, :].columns
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[idx]\
                    .transform(dframe.loc[:, column].values)
        return dframe.loc[:, self.columns].values

    def inverse_transform(self, dframe):
        """
        Transform labels back to original encoding.
        """
        if self.columns is not None:
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[idx]\
                    .inverse_transform(dframe.loc[:, column].values)
        else:
            self.columns = dframe.iloc[:, :].columns
            for idx, column in enumerate(self.columns):
                dframe.loc[:, column] = self.all_encoders_[idx]\
                    .inverse_transform(dframe.loc[:, column].values)
        return dframe

Exemple:

Si df et df_copy() sont des types de données pandas de type mixte, vous pouvez appliquer le MultiColumnLabelEncoder() aux colonnes dtype=object de la manière suivante:

# get `object` columns
df_object_columns = df.iloc[:, :].select_dtypes(include=['object']).columns
df_copy_object_columns = df_copy.iloc[:, :].select_dtypes(include=['object'].columns

# instantiate `MultiColumnLabelEncoder`
mcle = MultiColumnLabelEncoder(columns=object_columns)

# fit to `df` data
mcle.fit(df)

# transform the `df` data
mcle.transform(df)

# returns output like below
array([[1, 0, 0, ..., 1, 1, 0],
       [0, 5, 1, ..., 1, 1, 2],
       [1, 1, 1, ..., 1, 1, 2],
       ..., 
       [3, 5, 1, ..., 1, 1, 2],

# transform `df_copy` data
mcle.transform(df_copy)

# returns output like below (assuming the respective columns 
# of `df_copy` contain the same unique values as that particular 
# column in `df`
array([[1, 0, 0, ..., 1, 1, 0],
       [0, 5, 1, ..., 1, 1, 2],
       [1, 1, 1, ..., 1, 1, 2],
       ..., 
       [3, 5, 1, ..., 1, 1, 2],

# inverse `df` data
mcle.inverse_transform(df)

# outputs data like below
array([['August', 'Friday', '2013', ..., 'N', 'N', 'CA'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['August', 'Monday', '2014', ..., 'N', 'N', 'NJ'],
       ..., 
       ['February', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['March', 'Tuesday', '2013', ..., 'N', 'N', 'NJ']], dtype=object)

# inverse `df_copy` data
mcle.inverse_transform(df_copy)

# outputs data like below
array([['August', 'Friday', '2013', ..., 'N', 'N', 'CA'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['August', 'Monday', '2014', ..., 'N', 'N', 'NJ'],
       ..., 
       ['February', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
       ['March', 'Tuesday', '2013', ..., 'N', 'N', 'NJ']], dtype=object)

Vous pouvez accéder à des classes de colonne, des étiquettes de colonne et des encodeurs de colonne individuels permettant d'adapter chaque colonne via l'indexation:

mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_

4
Jason Wolosonovich

En supposant que vous essayiez simplement d'obtenir un objet sklearn.preprocessing.LabelEncoder() pouvant être utilisé pour représenter vos colonnes, tout ce que vous avez à faire est:

le.fit(df.columns)

Dans le code ci-dessus, vous aurez un numéro unique correspondant à chaque colonne . Plus précisément, vous aurez une correspondance 1: 1 de df.columns à le.transform(df.columns.get_values()). Pour obtenir le codage d'une colonne, il suffit de le transmettre à le.transform(...). Par exemple, ce qui suit va obtenir le codage pour chaque colonne:

le.transform(df.columns.get_values())

En supposant que vous souhaitiez créer un objet sklearn.preprocessing.LabelEncoder() pour toutes vos étiquettes de ligne, vous pouvez effectuer les opérations suivantes:

le.fit([y for x in df.get_values() for y in x])

Dans ce cas, vous avez probablement des étiquettes de lignes non uniques (comme le montre votre question). Pour voir les classes créées par l'encodeur, vous pouvez effectuer le.classes_. Vous noterez que cela devrait avoir les mêmes éléments que dans set(y for x in df.get_values() for y in x). Une fois encore, pour convertir une étiquette de ligne en une étiquette codée, utilisez le.transform(...). Par exemple, si vous souhaitez récupérer le libellé de la première colonne du tableau df.columns et de la première ligne, procédez comme suit:

le.transform([df.get_value(0, df.columns[0])])

La question que vous avez posée dans votre commentaire est un peu plus compliquée, mais peut encore.

le.fit([str(z) for z in set((x[0], y) for x in df.iteritems() for y in x[1])])

Le code ci-dessus fait ce qui suit:

  1. Faites une combinaison unique de toutes les paires de (colonne, rangée)
  2. Représentez chaque paire en tant que version de chaîne du tuple. Il s'agit d'une solution de contournement pour surmonter la classe LabelEncoder ne prenant pas en charge les n-uplets en tant que nom de classe.
  3. Adapte les nouveaux éléments à la LabelEncoder.

Maintenant, utiliser ce nouveau modèle est un peu plus compliqué. En supposant que nous voulions extraire la représentation du même élément que celui que nous avons recherché dans l'exemple précédent (la première colonne de df.columns et la première ligne), nous pouvons procéder ainsi:

le.transform([str((df.columns[0], df.get_value(0, df.columns[0])))])

Rappelez-vous que chaque recherche est maintenant une représentation sous forme de chaîne d'un tuple contenant Le (colonne, ligne).

4
TehTechGuy

Depuis scikit-learn 0.20, vous pouvez utiliser sklearn.compose.ColumnTransformer et sklearn.preprocessing.OneHotEncoder:

Si vous n’avez que des variables catégorielles, OneHotEncoder directement:

from sklearn.preprocessing import OneHotEncoder

OneHotEncoder(handle_unknown='ignore').fit_transform(df)

Si vous avez des fonctionnalités de type hétérogène:

from sklearn.compose import make_column_transformer
from sklearn.preprocessing import RobustScaler
from sklearn.preprocessing import OneHotEncoder

categorical_columns = ['pets', 'owner', 'location']
numerical_columns = ['age', 'weigth', 'height']
column_trans = make_column_transformer(
    (categorical_columns, OneHotEncoder(handle_unknown='ignore'),
    (numerical_columns, RobustScaler())
column_trans.fit_transform(df)

Plus d'options dans la documentation: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogen-data

3
ogrisel

Non, LabelEncoder ne le fait pas. Il prend des tableaux 1-D d'étiquettes de classe et produit des tableaux 1-D. Il est conçu pour gérer les étiquettes de classe dans les problèmes de classification, et non les données arbitraires. Toute tentative de le forcer dans d'autres utilisations nécessitera du code pour transformer le problème actuel en problème qu'il résout (et la solution pour revenir à l'espace d'origine).

2
Fred Foo

Suite aux commentaires soulevés sur la solution de @PriceHardman Je proposerais la version suivante de la classe:

class LabelEncodingColoumns(BaseEstimator, TransformerMixin):
def __init__(self, cols=None):
    pdu._is_cols_input_valid(cols)
    self.cols = cols
    self.les = {col: LabelEncoder() for col in cols}
    self._is_fitted = False

def transform(self, df, **transform_params):
    """
    Scaling ``cols`` of ``df`` using the fitting

    Parameters
    ----------
    df : DataFrame
        DataFrame to be preprocessed
    """
    if not self._is_fitted:
        raise NotFittedError("Fitting was not preformed")
    pdu._is_cols_subset_of_df_cols(self.cols, df)

    df = df.copy()

    label_enc_dict = {}
    for col in self.cols:
        label_enc_dict[col] = self.les[col].transform(df[col])

    labelenc_cols = pd.DataFrame(label_enc_dict,
        # The index of the resulting DataFrame should be assigned and
        # equal to the one of the original DataFrame. Otherwise, upon
        # concatenation NaNs will be introduced.
        index=df.index
    )

    for col in self.cols:
        df[col] = labelenc_cols[col]
    return df

def fit(self, df, y=None, **fit_params):
    """
    Fitting the preprocessing

    Parameters
    ----------
    df : DataFrame
        Data to use for fitting.
        In many cases, should be ``X_train``.
    """
    pdu._is_cols_subset_of_df_cols(self.cols, df)
    for col in self.cols:
        self.les[col].fit(df[col])
    self._is_fitted = True
    return self

Cette classe adapte l'encodeur au kit d'apprentissage et utilise la version ajustée lors de la transformation. La version initiale du code peut être trouvée ici .

1
Dror

si nous avons une seule colonne pour faire le codage d'étiquette et son inverse transformer sa facile comment le faire quand il y a plusieurs colonnes en python 

def stringtocategory(dataset):
    '''
    @author puja.sharma
    @see The function label encodes the object type columns and gives label      encoded and inverse tranform of the label encoded data
    @param dataset dataframe on whoes column the label encoding has to be done
    @return label encoded and inverse tranform of the label encoded data.
   ''' 
   data_original = dataset[:]
   data_tranformed = dataset[:]
   for y in dataset.columns:
       #check the dtype of the column object type contains strings or chars
       if (dataset[y].dtype == object):
          print("The string type features are  : " + y)
          le = preprocessing.LabelEncoder()
          le.fit(dataset[y].unique())
          #label encoded data
          data_tranformed[y] = le.transform(dataset[y])
          #inverse label transform  data
          data_original[y] = le.inverse_transform(data_tranformed[y])
   return data_tranformed,data_original
1
Puja Sharma

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 np.unique (). Et cette fonction prend seulement une entrée de tableau 1-d. (Corrigez-moi si je me trompe). 

Very Rough ideas ... Identifiez d’abord les colonnes qui ont besoin de LabelEncoder, puis parcourez chaque colonne en boucle.

def cat_var(df): 
    """Identify categorical features. 

    Parameters
    ----------
    df: original df after missing operations 

    Returns
    -------
    cat_var_df: summary df with col index and col name for all categorical vars
    """
    col_type = df.dtypes
    col_names = list(df)

    cat_var_index = [i for i, x in enumerate(col_type) if x=='object']
    cat_var_name = [x for i, x in enumerate(col_names) if i in cat_var_index]

    cat_var_df = pd.DataFrame({'cat_ind': cat_var_index, 
                               'cat_name': cat_var_name})

    return cat_var_df



from sklearn.preprocessing import LabelEncoder 

def column_encoder(df, cat_var_list):
    """Encoding categorical feature in the dataframe

    Parameters
    ----------
    df: input dataframe 
    cat_var_list: categorical feature index and name, from cat_var function

    Return
    ------
    df: new dataframe where categorical features are encoded
    label_list: classes_ attribute for all encoded features 
    """

    label_list = []
    cat_var_df = cat_var(df)
    cat_list = cat_var_df.loc[:, 'cat_name']

    for index, cat_feature in enumerate(cat_list): 

        le = LabelEncoder()

        le.fit(df.loc[:, cat_feature])    
        label_list.append(list(le.classes_))

        df.loc[:, cat_feature] = le.transform(df.loc[:, cat_feature])

    return df, label_list

Le retourné df serait celui après l'encodage, et label_list vous montrera ce que toutes ces valeurs signifient dans la colonne correspondante. Ceci est un extrait d’un script de traitement de 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 des trames de données sans manquer le meilleur. Vous ne savez pas comment cela fonctionne pour que le cadre de données contienne des données manquantes (J'ai eu un accord avec la procédure manquante avant d'exécuter les méthodes ci-dessus)

1
willaccc

Si vous avez les deux types de données numériques et catégoriques dans le cadre de données Vous pouvez utiliser: ici, X est mon cadre de données ayant les deux variables numériques et catégoriques.

from sklearn import preprocessing
le = preprocessing.LabelEncoder()

for i in range(0,X.shape[1]):
    if X.dtypes[i]=='object':
        X[X.columns[i]] = le.fit_transform(X[X.columns[i]])

Remarque: cette technique est utile si vous ne souhaitez pas les reconvertir.

1
Vikas Gupta
import pandas as pd
from sklearn.preprocessing import LabelEncoder

train=pd.read_csv('.../train.csv')

#X=train.loc[:,['waterpoint_type_group','status','waterpoint_type','source_class']].values
# Create a label encoder object 
def MultiLabelEncoder(columnlist,dataframe):
    for i in columnlist:

        labelencoder_X=LabelEncoder()
        dataframe[i]=labelencoder_X.fit_transform(dataframe[i])
columnlist=['waterpoint_type_group','status','waterpoint_type','source_class','source_type']
MultiLabelEncoder(columnlist,train)

Ici, je lis un csv d’emplacement et, en fonction, je passe la liste des colonnes que je veux étiqueter et le cadre de données que je veux appliquer.

0
Rinki Nag

Principalement utilisé @Alexander answer mais dû faire quelques changements - 

cols_need_mapped = ['col1', 'col2']

mapper = {col: {cat: n for n, cat in enumerate(df[col].astype('category').cat.categories)} 
     for col in df[cols_need_mapped]}

for c in cols_need_mapped :
    df[c] = df[c].map(mapper[c])

Ensuite, pour réutiliser ultérieurement, vous pouvez simplement enregistrer la sortie dans un document json. Lorsque vous en aurez besoin, vous pourrez la lire et utiliser la fonction .map() comme je l’ai fait ci-dessus.

0
bbennett36

Il est possible de faire tout cela directement dans les pandas et convient parfaitement à une capacité unique de la méthode replace.

Commençons par créer un dictionnaire de dictionnaires associant les colonnes et leurs valeurs à leurs nouvelles valeurs de remplacement.

transform_dict = {}
for col in df.columns:
    cats = pd.Categorical(df[col]).categories
    d = {}
    for i, cat in enumerate(cats):
        d[cat] = i
    transform_dict[col] = d

transform_dict
{'location': {'New_York': 0, 'San_Diego': 1},
 'owner': {'Brick': 0, 'Champ': 1, 'Ron': 2, 'Veronica': 3},
 'pets': {'cat': 0, 'dog': 1, 'monkey': 2}}

Comme il s'agira toujours d'un mappage un à un, nous pouvons inverser le dictionnaire interne pour obtenir un mappage des nouvelles valeurs sur l'original.

inverse_transform_dict = {}
for col, d in transform_dict.items():
    inverse_transform_dict[col] = {v:k for k, v in d.items()}

inverse_transform_dict
{'location': {0: 'New_York', 1: 'San_Diego'},
 'owner': {0: 'Brick', 1: 'Champ', 2: 'Ron', 3: 'Veronica'},
 'pets': {0: 'cat', 1: 'dog', 2: 'monkey'}}

Maintenant, nous pouvons utiliser la capacité unique de la méthode replace pour prendre une liste imbriquée de dictionnaires et utiliser les clés externes comme colonnes et les clés internes comme valeurs à remplacer.

df.replace(transform_dict)
   location  owner  pets
0         1      1     0
1         0      2     1
2         0      0     0
3         1      1     2
4         1      3     1
5         0      2     1

Nous pouvons facilement revenir à l'original en reliant à nouveau la méthode replace

df.replace(transform_dict).replace(inverse_transform_dict)
    location     owner    pets
0  San_Diego     Champ     cat
1   New_York       Ron     dog
2   New_York     Brick     cat
3  San_Diego     Champ  monkey
4  San_Diego  Veronica     dog
5   New_York       Ron     dog
0
Ted Petrou

Après beaucoup de recherches et d’expérimentation de réponses ici et ailleurs, je pense que votre réponse est ici :

pd.DataFrame (colonnes = df.colonnes, data = LabelEncoder (). fit_transform (df.values.flatten ()). reshape (df.shape))

Cela préservera les noms de catégorie dans les colonnes:

import pandas as pd
from sklearn.preprocessing import LabelEncoder

df = pd.DataFrame([['A','B','C','D','E','F','G','I','K','H'],
                   ['A','E','H','F','G','I','K','','',''],
                   ['A','C','I','F','H','G','','','','']], 
                  columns=['A1', 'A2', 'A3','A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10'])

pd.DataFrame(columns=df.columns, data=LabelEncoder().fit_transform(df.values.flatten()).reshape(df.shape))

    A1  A2  A3  A4  A5  A6  A7  A8  A9  A10
0   1   2   3   4   5   6   7   9   10  8
1   1   5   8   6   7   9   10  0   0   0
2   1   3   9   6   8   7   0   0   0   0
0
Christopher

Un chemin court pour LabelEncoder() plusieurs colonnes avec un dict():

from sklearn.preprocessing import LabelEncoder
le_dict = {col: LabelEncoder() for col in columns }
for col in columns:
    le_dict[col].fit_transform(df[col])

et vous pouvez utiliser ce le_dict pour labelEncode toute autre colonne:

le_dict[col].transform(df_another[col])
0
Tom

Le problème est la forme des données (pd dataframe) que vous transmettez à la fonction fit . Vous devez passer 1d list.

0
ali sadr