Saltar al contenido

Codificar variables categóricas One-Hot-Encode y escalar las continuas simultáneamente

Te doy la bienvenida a nuestra página, en este lugar vas a encontrar la respuesta a lo que andabas buscando.

Solución:

Cosa segura. Simplemente escale por separado y codifique en caliente las columnas separadas según sea necesario:

# Import libraries and download example data
from sklearn.preprocessing import StandardScaler, OneHotEncoder

dataset = pd.read_csv("https://stats.idre.ucla.edu/stat/data/binary.csv")
print(dataset.head(5))

# Define which columns should be encoded vs scaled
columns_to_encode = ['rank']
columns_to_scale  = ['gre', 'gpa']

# Instantiate encoder/scaler
scaler = StandardScaler()
ohe    = OneHotEncoder(sparse=False)

# Scale and Encode Separate Columns
scaled_columns  = scaler.fit_transform(dataset[columns_to_scale]) 
encoded_columns =    ohe.fit_transform(dataset[columns_to_encode])

# Concatenate (Column-Bind) Processed Columns Back Together
processed_data = np.concatenate([scaled_columns, encoded_columns], axis=1)

Scikit-learn de la versión 0.20 proporciona sklearn.compose.ColumnTransformer que hacer Transformador de columna con tipos mixtos. Puede escalar las características numéricas y codificar en caliente las categóricas juntas. A continuación se muestra el ejemplo oficial (puede encontrar el código aquí):

# Author: Pedro Morales <[email protected]>
#
# License: BSD 3 clause

from __future__ import print_function

import pandas as pd
import numpy as np

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split, GridSearchCV

np.random.seed(0)

# Read data from Titanic dataset.
titanic_url = ('https://raw.githubusercontent.com/amueller/'
               'scipy-2017-sklearn/091d371/notebooks/datasets/titanic3.csv')
data = pd.read_csv(titanic_url)

# We will train our classifier with the following features:
# Numeric Features:
# - age: float.
# - fare: float.
# Categorical Features:
# - embarked: categories encoded as strings 'C', 'S', 'Q'.
# - sex: categories encoded as strings 'female', 'male'.
# - pclass: ordinal integers 1, 2, 3.

# We create the preprocessing pipelines for both numeric and categorical data.
numeric_features = ['age', 'fare']
numeric_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())])

categorical_features = ['embarked', 'sex', 'pclass']
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))])

preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, numeric_features),
        ('cat', categorical_transformer, categorical_features)])

# Append classifier to preprocessing pipeline.
# Now we have a full prediction pipeline.
clf = Pipeline(steps=[('preprocessor', preprocessor),
                      ('classifier', LogisticRegression(solver='lbfgs'))])

X = data.drop('survived', axis=1)
y = data['survived']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

clf.fit(X_train, y_train)
print("model score: %.3f" % clf.score(X_test, y_test))

Precaución: este método es EXPERIMENTAL, algunos comportamientos pueden cambiar entre lanzamientos sin desaprobación.

Actualmente existen numerosos métodos para lograr el resultado requerido por el OP. 3 maneras de hacer esto son

  1. np.concatenate() – vea esta respuesta a la pregunta del OP, ya publicada

  2. scikit-learn‘s ColumnTransformer

    • originalmente sugerido en esta respuesta SO a la pregunta del OP
  3. scikit-learn‘s FeatureUnion

    • también se muestra en esta respuesta SO

Usando el ejemplo publicado por @Max Power aquí, a continuación se muestra un fragmento de trabajo mínimo que hace lo que busca el OP y reúne las columnas transformadas en un solo marco de datos de Pandas. Se muestra el resultado de los 3 enfoques.

El código común para los 3 métodos es

import numpy as np
import pandas as pd

# Import libraries and download example data
from sklearn.preprocessing import StandardScaler, OneHotEncoder

dataset = pd.read_csv("https://stats.idre.ucla.edu/stat/data/binary.csv")

# Define which columns should be encoded vs scaled
columns_to_encode = ['rank']
columns_to_scale  = ['gre', 'gpa']

# Instantiate encoder/scaler
scaler = StandardScaler()
ohe    = OneHotEncoder(sparse=False)

Método 1. ver código aquí. Para mostrar la salida, puede usar

print(pd.DataFrame(processed_data).head())

Salida del Método 1.

          0         1    2    3    4    5
0 -1.800263  0.579072  0.0  0.0  1.0  0.0
1  0.626668  0.736929  0.0  0.0  1.0  0.0
2  1.840134  1.605143  1.0  0.0  0.0  0.0
3  0.453316 -0.525927  0.0  0.0  0.0  1.0
4 -0.586797 -1.209974  0.0  0.0  0.0  1.0

Método 2.

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline


p = Pipeline(
    [("coltransformer", ColumnTransformer(
        transformers=[
            ("assessments", Pipeline([("scale", scaler)]), columns_to_scale),
            ("ranks", Pipeline([("encode", ohe)]), columns_to_encode),
        ]),
    )]
)

print(pd.DataFrame(p.fit_transform(dataset)).head())

Salida del Método 2.

          0         1    2    3    4    5
0 -1.800263  0.579072  0.0  0.0  1.0  0.0
1  0.626668  0.736929  0.0  0.0  1.0  0.0
2  1.840134  1.605143  1.0  0.0  0.0  0.0
3  0.453316 -0.525927  0.0  0.0  0.0  1.0
4 -0.586797 -1.209974  0.0  0.0  0.0  1.0

Método 3.

from sklearn.pipeline import Pipeline
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import FeatureUnion


class ItemSelector(BaseEstimator, TransformerMixin):
    def __init__(self, key):
        self.key = key
    def fit(self, x, y=None):
        return self
    def transform(self, df):
        return df[self.key]

p = Pipeline([("union", FeatureUnion(
    transformer_list=[
        ("assessments", Pipeline([
            ("selector", ItemSelector(key=columns_to_scale)),
            ("scale", scaler)
            ]),
        ),
        ("ranks", Pipeline([
            ("selector", ItemSelector(key=columns_to_encode)),
            ("encode", ohe)
            ]),
        ),
    ]))
])

print(pd.DataFrame(p.fit_transform(dataset)).head())

Salida del Método 3.

          0         1    2    3    4    5
0 -1.800263  0.579072  0.0  0.0  1.0  0.0
1  0.626668  0.736929  0.0  0.0  1.0  0.0
2  1.840134  1.605143  1.0  0.0  0.0  0.0
3  0.453316 -0.525927  0.0  0.0  0.0  1.0
4 -0.586797 -1.209974  0.0  0.0  0.0  1.0

Explicación

  1. El método 1. ya está explicado.

  2. Los métodos 2 y 3 aceptan el conjunto de datos completo, pero solo realizan acciones específicas en subconjuntos de datos. Los subconjuntos modificados/procesados ​​se reúnen (combinan) en el resultado final.

Detalles

pandas==0.23.4
numpy==1.15.2
scikit-learn==0.20.0

Notas adicionales

Los 3 métodos que se muestran aquí probablemente no sean las únicas posibilidades… Estoy seguro de que hay otros métodos para hacer esto.

FUENTE UTILIZADA

Enlace actualizado a binary.csv conjunto de datos

Si aceptas, eres capaz de dejar un post acerca de qué te ha impresionado de este enunciado.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *