Codificación de etiquetas en varias columnas en scikit-learn

Resuelto Bryan asked hace 10 años • 0 respuestas

Estoy intentando usar scikit-learn LabelEncoderpara codificar pandas DataFramede etiquetas de cadenas. Como el marco de datos tiene muchas (50+) columnas, quiero evitar crear un LabelEncoderobjeto para cada columna; Prefiero tener un LabelEncoderobjeto grande que funcione en todas mis columnas de datos.

DataFrameLanzar todo LabelEncodercrea el siguiente error. Tenga en cuenta que aquí estoy usando datos ficticios; en realidad estoy tratando con alrededor de 50 columnas de datos etiquetados con cadenas, por lo que necesito una solución que no haga referencia a ninguna columna por su nombre.

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)

Rastreo (última llamada más reciente): Archivo "", línea 1, en Archivo "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py", línea 103, en forma y = column_or_1d(y, warn=True) Archivo "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", línea 306, en column_or_1d rise ValueError("forma de entrada incorrecta { 0}".format(shape)) ValueError: forma de entrada incorrecta (6, 3)

¿Alguna idea sobre cómo solucionar este problema?

Bryan avatar Jun 28 '14 01:06 Bryan
Aceptado

Aunque puedes hacer esto fácilmente,

df.apply(LabelEncoder().fit_transform)

EDITAR2:

En scikit-learn 0.20, la forma recomendada es

OneHotEncoder().fit_transform(df)

ya que OneHotEncoder ahora admite la entrada de cadenas. Es posible aplicar OneHotEncoder solo a ciertas columnas con ColumnTransformer.

EDITAR:

Dado que esta respuesta original fue hace más de un año y generó muchos votos a favor (incluida una recompensa), probablemente debería extenderla más.

Para inverse_transform y transform, tienes que hacer un pequeño truco.

from collections import defaultdict
d = defaultdict(LabelEncoder)

Con esto, ahora conservas todas las columnas LabelEncodercomo diccionario.

# 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))

EDICIÓN DE MOAR:

Usando el paso de Neuraxle FlattenForEach, también es posible hacer esto para usar el mismo LabelEncoderen todos los datos aplanados a la vez:

FlattenForEach(LabelEncoder(), then_unflatten=True).fit_transform(df)

Para usar LabelEncoders separados dependiendo de sus columnas de datos, o si solo algunas de sus columnas de datos necesitan estar codificadas con etiquetas y otras no, entonces usar a es ColumnTransformeruna solución que permite un mayor control sobre su selección de columnas y sus instancias de LabelEncoder.

Napitupulu Jon avatar Aug 11 '2015 10:08 Napitupulu Jon

Como lo mencionó Larsmans, LabelEncoder() solo toma una matriz unidimensional como argumento . Dicho esto, es bastante fácil crear su propio codificador de etiquetas que opere en varias columnas de su elección y devuelva un marco de datos transformado. Mi código aquí se basa en parte en la excelente publicación del blog de Zac Stewart que se encuentra aquí .

Crear un codificador personalizado implica simplemente crear una clase que responda a los métodos fit(), transform()y fit_transform(). En tu caso, un buen comienzo podría ser algo como esto:

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)

Supongamos que queremos codificar nuestros dos atributos categóricos ( fruity color), dejando weightsolo el atributo numérico. Podríamos hacer esto de la siguiente manera:

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

Lo que transforma nuestro fruit_dataconjunto de datos de

ingrese la descripción de la imagen aquía

ingrese la descripción de la imagen aquí

Pasarle un marco de datos que consta enteramente de variables categóricas y omitir el columnsparámetro dará como resultado que se codifiquen todas las columnas (que creo que es lo que estaba buscando originalmente):

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

Esto transforma

ingrese la descripción de la imagen aquía

ingrese la descripción de la imagen aquí.

Tenga en cuenta que probablemente se bloqueará cuando intente codificar atributos que ya son numéricos (agregue algo de código para manejar esto si lo desea).

Otra característica interesante de esto es que podemos usar este transformador personalizado en una tubería:

encoding_pipeline = Pipeline([
    ('encoding',MultiColumnLabelEncoder(columns=['fruit','color']))
    # add more pipeline steps as needed
])
encoding_pipeline.fit_transform(fruit_data)
PriceHardman avatar May 15 '2015 19:05 PriceHardman

Desde scikit-learn 0.20 puedes usar sklearn.compose.ColumnTransformery sklearn.preprocessing.OneHotEncoder:

Si solo tienes variables categóricas, OneHotEncoderdirectamente:

from sklearn.preprocessing import OneHotEncoder

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

Si tiene funciones escritas de forma heterogénea:

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)

Más opciones en la documentación: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data

ogrisel avatar Oct 14 '2018 08:10 ogrisel