scikit-learn

ScikitLearn

Tutorial ScikitLearn: Preprocesamiento de datos con pipelines

Scikit-Learn: Aprende a integrar escalado y normalización en un pipeline. Optimización del preprocesamiento de datos para mejorar la precisión del modelo.

Aprende ScikitLearn GRATIS y certifícate

Escalado y normalización de características en pipeline

El escalado y la normalización de características son pasos fundamentales en el preprocesamiento de datos para muchos algoritmos de aprendizaje automático. Integrar estas transformaciones dentro de un pipeline de Scikit-Learn permite automatizar y encadenar procesos, garantizando que todas las etapas se apliquen de manera consistente durante el entrenamiento y la predicción.

Para ilustrar cómo incorporar el escalado y la normalización en un pipeline, consideremos un ejemplo práctico. Supongamos que tenemos un conjunto de datos y queremos aplicar una regresión logística. Primero, importamos las bibliotecas necesarias:

import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, MinMaxScaler, Normalizer
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
from joblib import Memory

A continuación, generamos datos sintéticos:

# Habilitar caching
memory = Memory(location='cachedir', verbose=0)

# Generar datos sintéticos
X, y = make_classification(n_samples=1000, n_features=20, 
                           n_informative=15, n_redundant=5, 
                           random_state=42)

Crearemos diferentes pipelines que incluyen distintas técnicas de escalado.

El StandardScaler estandariza las características restando la media y dividiendo entre la desviación estándar:

pipeline_std = Pipeline(
    [
        ("scaler", StandardScaler()),
        ("classifier", LogisticRegression(
            penalty="l2",
            solver="liblinear",
            random_state=42,
            max_iter=100
        )),
    ],
    memory=memory
)

El MinMaxScaler escala las características al rango [0, 1]:

pipeline_minmax = Pipeline(
    [
        ("scaler", MinMaxScaler()),
        ("classifier", LogisticRegression(
            penalty="l2",
            solver="liblinear",
            random_state=42,
            max_iter=100
        )),
    ],
    memory=memory
)

El Normalizer normaliza cada muestra individual para tener una norma unitaria:

pipeline_norm = Pipeline(
    [
        ("normalizer", Normalizer()),
        ("classifier", LogisticRegression(
            penalty="l2",
            solver="liblinear",
            random_state=42,
            max_iter=100
        )),
    ],
    memory=memory
)

Procedemos a entrenar y evaluar los pipelines utilizando validación cruzada:

from sklearn.model_selection import cross_val_score

scores_std = cross_val_score(pipeline_std, X, y, cv=5)
print("Precisión con StandardScaler:", scores_std.mean())

scores_minmax = cross_val_score(pipeline_minmax, X, y, cv=5)
print("Precisión con MinMaxScaler:", scores_minmax.mean())

scores_norm = cross_val_score(pipeline_norm, X, y, cv=5)
print("Precisión con Normalizer:", scores_norm.mean())

Es importante comparar los resultados obtenidos con cada método de escalado para determinar cuál mejora el rendimiento del modelo. La elección del escalador puede afectar significativamente la precisión de las predicciones.

Incorporar el escalado y la normalización dentro de un pipeline no solo simplifica el código sino que también garantiza que las transformaciones se apliquen correctamente tanto en el conjunto de entrenamiento como en los datos nuevos. Las buenas prácticas recomiendan siempre incluir los pasos de preprocesamiento en los pipelines para evitar inconsistencias y facilitar el mantenimiento del código.

Manejo de valores faltantes en pipeline

Los valores faltantes en los conjuntos de datos pueden afectar negativamente el rendimiento de los algoritmos de aprendizaje automático. Integrar el manejo de estos valores dentro de un pipeline garantiza que el procesamiento sea consistente tanto durante el entrenamiento como en la predicción.

Para abordar los valores faltantes, Scikit-Learn ofrece transformadores como SimpleImputer y KNNImputer, que pueden incorporarse fácilmente en un pipeline. Supongamos que tenemos un conjunto de datos con características numéricas y categóricas, y algunos de sus valores están ausentes. Importamos las bibliotecas necesarias:

import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer, KNNImputer
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from joblib import Memory

Creamos un conjunto de datos de ejemplo:

# Habilitar caching
memory = Memory(location='cachedir', verbose=0)

# Crear datos de ejemplo
data = {'edad': [25, np.nan, 35, 45, np.nan],
        'ingresos': [50000, 60000, np.nan, 80000, 90000],
        'género': ['M', 'F', np.nan, 'F', 'M'],
        'compra': [0, 1, 0, 1, 1]}

df = pd.DataFrame(data)
X = df.drop('compra', axis=1)
y = df['compra']

Identificamos las columnas numéricas y categóricas:

# Identificar columnas numéricas y categóricas
columnas_numericas = ['edad', 'ingresos']
columnas_categoricas = ['género']

Definimos transformadores para manejar los valores faltantes. Para las columnas numéricas utilizaremos SimpleImputer con estrategia de imputación por la media, y para las categóricas, imputación con el valor más frecuente:

# Transformador para columnas numéricas
transformador_numerico = Pipeline(steps=[
    ('imputar', SimpleImputer(strategy='mean'))
], memory=memory)

# Transformador para columnas categóricas
transformador_categorico = Pipeline(steps=[
    ('imputar', SimpleImputer(strategy='most_frequent')),
    ('codificar', OneHotEncoder(handle_unknown='ignore'))
], memory=memory)

Combinamos los transformadores utilizando ColumnTransformer:

preprocesamiento = ColumnTransformer(transformers=[
    ('numerico', transformador_numerico, columnas_numericas),
    ('categorico', transformador_categorico, columnas_categoricas)
])

Creamos el pipeline completo agregando un clasificador al final. Utilizaremos un RandomForestClassifier:

pipeline = Pipeline(steps=[
    ('preprocesamiento', preprocesamiento),
    ('clasificador', RandomForestClassifier())
], memory=memory)

Entrenamos el pipeline con los datos:

pipeline.fit(X, y)

Podemos realizar predicciones sobre nuevos datos, asegurándonos de que el preprocesamiento se aplique de manera consistente:

# Nuevos datos con valores faltantes
nuevos_datos = {'edad': [30, np.nan],
                'ingresos': [70000, 85000],
                'género': ['F', np.nan]}

df_nuevos = pd.DataFrame(nuevos_datos)
predicciones = pipeline.predict(df_nuevos)
print("Predicciones:", predicciones)

Es importante destacar que manejar los valores faltantes dentro del pipeline garantiza que cualquier transformación se aplique de manera idéntica durante el entrenamiento y la inferencia. Las mejores prácticas sugieren integrar todas las etapas de preprocesamiento en el pipeline para evitar inconsistencias y simplificar el proceso de despliegue.

Para conjuntos de datos más grandes o cuando los valores faltantes tienen patrones complejos, puede ser útil utilizar imputadores más sofisticados como KNNImputer. Por ejemplo:

# Usando KNNImputer para columnas numéricas
transformador_numerico_knn = Pipeline(steps=[
    ('imputar', KNNImputer(n_neighbors=3))
])

preprocesamiento_knn = ColumnTransformer(transformers=[
    ('numerico', transformador_numerico_knn, columnas_numericas),
    ('categorico', transformador_categorico, columnas_categoricas)
])

pipeline_knn = Pipeline(steps=[
    ('preprocesamiento', preprocesamiento_knn),
    ('clasificador', RandomForestClassifier())
], memory=memory)

De esta manera, el KNNImputer utilizará los valores de los vecinos más cercanos para imputar los datos faltantes, lo que puede mejorar la precisión del modelo en ciertos casos.

Integrar el manejo de valores faltantes en los pipelines no solo mejora la robustez del modelo, sino que también facilita su uso en producción, asegurando que todas las transformaciones estén encapsuladas y sean reproducibles.

Codificación de variables categóricas en pipeline

La codificación de variables categóricas es un paso crucial en el preprocesamiento de datos para muchos algoritmos de aprendizaje automático, ya que estos generalmente requieren datos numéricos. Integrar esta codificación dentro de un pipeline en Scikit-Learn garantiza que el proceso sea consistente durante el entrenamiento y la predicción.

Para ilustrar cómo incorporar la codificación de variables categóricas en un pipeline, consideremos un ejemplo práctico. Supongamos que tenemos un conjunto de datos que incluye tanto características numéricas como categóricas y deseamos aplicar una regresión logística. Primero, importamos las bibliotecas necesarias:

import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LogisticRegression
from joblib import Memory

Creamos un conjunto de datos de ejemplo:

# Habilitar caching
memory = Memory(location='cachedir', verbose=0)

# Crear datos de ejemplo
data = {
    'edad': [25, 32, 47, 51, 62],
    'ingresos': [50000, 60000, 80000, 72000, 90000],
    'género': ['M', 'F', 'F', 'M', 'F'],
    'estado_civil': ['Soltero', 'Casado', 'Casado', 'Soltero', 'Viudo'],
    'compra': [0, 1, 0, 1, 1]
}

df = pd.DataFrame(data)
X = df.drop('compra', axis=1)
y = df['compra']

Identificamos las columnas numéricas y categóricas:

# Identificar columnas numéricas y categóricas
columnas_numericas = ['edad', 'ingresos']
columnas_categoricas = ['género', 'estado_civil']

Definimos transformadores para cada tipo de dato. Para las columnas numéricas, utilizaremos StandardScaler para estandarizar las características. Para las columnas categóricas, emplearemos OneHotEncoder para convertir las categorías en variables binarias:

# Transformador para columnas numéricas
transformador_numerico = Pipeline(steps=[
    ('escalar', StandardScaler())
], memory=memory)

# Transformador para columnas categóricas
transformador_categorico = Pipeline(steps=[
    ('codificar', OneHotEncoder(handle_unknown='ignore'))
], memory=memory)

Combinamos los transformadores utilizando ColumnTransformer:

preprocesamiento = ColumnTransformer(transformers=[
    ('numerico', transformador_numerico, columnas_numericas),
    ('categorico', transformador_categorico, columnas_categoricas)
])

Creamos el pipeline completo agregando el modelo de regresión logística al final:

pipeline = Pipeline(steps=[
    ('preprocesamiento', preprocesamiento),
    ('clasificador', LogisticRegression())
], memory=memory)

Entrenamos el pipeline con los datos:

pipeline.fit(X, y)

Podemos realizar predicciones sobre nuevos datos, asegurándonos de que el preprocesamiento se aplique de manera consistente:

# Nuevos datos para predicción
nuevos_datos = {
    'edad': [29, 55],
    'ingresos': [58000, 85000],
    'género': ['F', 'M'],
    'estado_civil': ['Soltero', 'Casado']
}

df_nuevos = pd.DataFrame(nuevos_datos)
predicciones = pipeline.predict(df_nuevos)
print("Predicciones:", predicciones)

El uso de OneHotEncoder convierte las variables categóricas en una representación numérica adecuada para el modelo. Integrar este proceso dentro del pipeline garantiza una transformación coherente tanto en el entrenamiento como en la inferencia.

Si preferimos utilizar una codificación ordinal, podemos emplear OrdinalEncoder. Sin embargo, es importante tener en cuenta que OrdinalEncoder asigna un valor entero a cada categoría según su orden, lo que implica una relación ordinal que puede no existir:

from sklearn.preprocessing import OrdinalEncoder

# Transformador categórico con OrdinalEncoder
transformador_categorico_ordinal = Pipeline(steps=[
    ('codificar', OrdinalEncoder())
], memory=memory)

preprocesamiento_ordinal = ColumnTransformer(transformers=[
    ('numerico', transformador_numerico, columnas_numericas),
    ('categorico', transformador_categorico_ordinal, columnas_categoricas)
])

pipeline_ordinal = Pipeline(steps=[
    ('preprocesamiento', preprocesamiento_ordinal),
    ('clasificador', LogisticRegression())
], memory=memory)

pipeline_ordinal.fit(X, y)

En algunos casos, puede ser necesario aplicar diferentes estrategias de codificación a distintas columnas categóricas. Por ejemplo, podríamos codificar 'género' con OneHotEncoder y 'estado_civil' con OrdinalEncoder:

# Aplicar diferentes codificadores a columnas categóricas
preprocesamiento_mixto = ColumnTransformer(transformers=[
    ('numerico', transformador_numerico, columnas_numericas),
    ('onehot', OneHotEncoder(handle_unknown='ignore'), ['género']),
    ('ordinal', OrdinalEncoder(), ['estado_civil'])
])

pipeline_mixto = Pipeline(steps=[
    ('preprocesamiento', preprocesamiento_mixto),
    ('clasificador', LogisticRegression())
], memory=memory)

pipeline_mixto.fit(X, y)

De esta manera, adaptamos la codificación a las características específicas de cada variable, lo que puede mejorar la eficacia del modelo.

Integrar la codificación de variables categóricas dentro del pipeline no solo simplifica el código, sino que también garantiza que todas las transformaciones se apliquen correctamente tanto en el conjunto de entrenamiento como en los nuevos datos. Las buenas prácticas recomiendan incluir todos los pasos de preprocesamiento y modelado en un pipeline para asegurar la reproducibilidad y facilitar el mantenimiento del código.

Además, si trabajamos con datos que pueden contener categorías desconocidas en el conjunto de validación o prueba, es fundamental configurar el parámetro handle_unknown='ignore' en OneHotEncoder. Esto evita errores durante la predicción cuando se encuentran categorías nuevas que no estuvieron presentes durante el entrenamiento.

Es importante prestar atención al orden de las transformaciones y asegurarse de que todas las variables estén correctamente procesadas antes de ser enviadas al modelo. La implementación cuidadosa de la codificación de variables categóricas en el pipeline contribuye significativamente a la robustez y precisión del modelo.

Selección de características dentro del Pipeline

La selección de características es un paso esencial en el preprocesamiento de datos que busca reducir la dimensionalidad, eliminar ruido y mejorar el rendimiento de los modelos. Integrar la selección de características dentro de un pipeline en Scikit-Learn permite automatizar y encadenar este proceso con otras transformaciones, asegurando coherencia y eficiencia durante el entrenamiento y la predicción.

Scikit-Learn ofrece diversas técnicas de selección de características que pueden incorporarse fácilmente en un pipeline. A continuación, exploraremos cómo integrar estas técnicas mediante ejemplos prácticos.

Para empezar, creamos un conjunto de datos de clasificación utilizando make_classification:

import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

# Crear datos sintéticos
X, y = make_classification(
    n_samples=1000,
    n_features=20,
    n_informative=5,
    n_redundant=2,
    random_state=42
)

# Dividir datos en entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

Creamos un pipeline que incluye escalado, selección de características y el modelo:

from sklearn.pipeline import Pipeline
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler
from joblib import Memory

# Configurar memoria para caching
memory = Memory(location='cachedir', verbose=0)

# Construir el pipeline
pipeline = Pipeline([
    ('escalar', MinMaxScaler()),  # Escalado para garantizar valores no negativos
    ('seleccionar', SelectKBest(score_func=chi2, k=10)),  # Selección de características
    ('clasificador', LogisticRegression(random_state=42))  # Modelo
], memory=memory)

# Entrenar el pipeline
pipeline.fit(X_train, y_train)

# Evaluar el pipeline
precision = pipeline.score(X_test, y_test)
print("Precisión del modelo:", precision)

En este ejemplo, SelectKBest selecciona las 10 características más relevantes según la prueba chi-cuadrado. Integrar esta selección dentro del pipeline asegura que solo se utilicen las características significativas para el modelo, mejorando su eficacia.

También podemos utilizar métodos de selección basados en modelos. Por ejemplo, empleando SelectFromModel con un RandomForestClassifier:

from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectFromModel
from sklearn.preprocessing import StandardScaler


pipeline_modelo = Pipeline([
    ('escalar', StandardScaler()),
    ('seleccionar', SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=42))),
    ('clasificador', LogisticRegression(random_state=42))
], memory=memory)

pipeline_modelo.fit(X_train, y_train)

# Ver las características seleccionadas
selector = pipeline_modelo.named_steps['seleccionar']
print("Características seleccionadas:", selector.get_support())

Con SelectFromModel, el modelo base (en este caso, un bosque aleatorio) determina la importancia de las características, y se seleccionan aquellas con mayor relevancia. Esta técnica es útil cuando se desea incorporar conocimientos de modelos más complejos en la selección de variables.

Otra opción es utilizar Recursive Feature Elimination (RFE), que elimina recursivamente las características menos importantes:

from sklearn.feature_selection import RFE

pipeline_rfe = Pipeline([
    ('escalar', StandardScaler()),
    ('seleccionar', RFE(estimator=LogisticRegression(random_state=42), n_features_to_select=10)),
    ('clasificador', LogisticRegression(random_state=42))
], memory=memory)

pipeline_rfe.fit(X_train, y_train)

La eliminación recursiva de características es especialmente útil cuando se quiere identificar un subconjunto óptimo de características que maximice el rendimiento del modelo.

Hablando de ajuste de hiperparámetros, es común integrarlo con herramientas como GridSearchCV para encontrar los valores óptimos. Por ejemplo:

from sklearn.model_selection import GridSearchCV

parametros = {
    'seleccionar__n_features_to_select': [5, 10, 15],
    'clasificador__C': [0.1, 1, 10]
}

grid = GridSearchCV(pipeline_rfe, parametros, cv=5)
grid.fit(X_train, y_train)

print("Mejores parámetros:", grid.best_params_)
print("Mejor score:", grid.best_score_)

Al integrar la selección de características en el pipeline y combinarla con la búsqueda de hiperparámetros, garantizamos un enfoque sistemático y reproducible para optimizar el modelo.

Es importante destacar que integrar la selección de características dentro del pipeline previene fugas de datos, ya que todas las transformaciones se ajustan únicamente en los datos de entrenamiento y luego se aplican al conjunto de prueba.

Además de los métodos mencionados, Scikit-Learn ofrece otros transformadores que pueden integrarse en el pipeline, como VarianceThreshold para eliminar características con baja varianza o SelectPercentile para seleccionar un porcentaje de características según una prueba estadística.

Por ejemplo, utilizando VarianceThreshold:

from sklearn.feature_selection import VarianceThreshold

pipeline_varianza = Pipeline([
    ('escalar', StandardScaler()),
    ('seleccionar', VarianceThreshold(threshold=0.1)),
    ('clasificador', LogisticRegression(random_state=42))
], memory=memory)

pipeline_varianza.fit(X_train, y_train)

Este transformador elimina características cuya varianza no supera el umbral especificado, lo que puede ser útil para eliminar características constantes o casi constantes.

Integrar la selección de características dentro del pipeline no solo simplifica el código sino que también mejora la robustez y mantenibilidad del modelo. Al encadenar los pasos de preprocesamiento y modelado, nos aseguramos de que todas las transformaciones se apliquen de manera consistente, tanto en el entrenamiento como en la predicción sobre nuevos datos.

En resumen, la selección de características es un componente fundamental en el desarrollo de modelos de aprendizaje automático, y su integración dentro de los pipelines de Scikit-Learn es una práctica recomendada que aporta claridad y eficiencia al proceso de modelado.

Implementación de transformaciones personalizadas

En ocasiones, las transformaciones estándar que ofrece Scikit-Learn no son suficientes para satisfacer necesidades específicas de preprocesamiento. En estos casos, es útil implementar transformaciones personalizadas que se adapten a las particularidades de los datos. Integrar estas transformaciones en un pipeline permite encadenar procesos y garantizar que todas las etapas se apliquen de manera consistente durante el entrenamiento y la predicción.

Para crear un transformador personalizado en Scikit-Learn, se define una clase que hereda de BaseEstimator y TransformerMixin y se implementan los métodos fit y transform. A continuación, se muestra un ejemplo práctico de cómo hacerlo.

Supongamos que queremos crear una transformación que añada una nueva característica calculando el número de vocales en una columna de texto. Primero, importamos las bibliotecas necesarias:

import numpy as np
import pandas as pd
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from joblib import Memory

Definimos la clase del transformador personalizado:

class ContadorDeVocalesTransformer(BaseEstimator, TransformerMixin):
    def __init__(self, columna):
        self.columna = columna

    def fit(self, X, y=None):
        return self  # No requiere ajuste

    def transform(self, X):
        X = X.copy()
        X['numero_vocales'] = X[self.columna].apply(self._contar_vocales)
        return X

    def _contar_vocales(self, texto):
        texto = str(texto).lower()
        return sum(1 for char in texto if char in 'aeiou')

Este transformador añade una nueva columna numero_vocales que contiene el conteo de vocales en cada entrada de texto.

Creamos un conjunto de datos de ejemplo:

# Datos de ejemplo
data = {
    'frase': ['Hola Mundo', 'Scikit Learn', 'Transformación', 'Pipeline Personalizado', 'Machine Learning'],
    'valor_numerico': [10, 20, 30, 40, 50],
    'clase': [0, 1, 0, 1, 1]
}

df = pd.DataFrame(data)
X = df[['frase', 'valor_numerico']]
y = df['clase']

Identificamos las columnas numéricas y establecemos el preprocesamiento correspondiente:

# Columnas numéricas
columnas_numericas = ['valor_numerico', 'numero_vocales']

# Pipeline para características numéricas
pipeline_numerico = Pipeline(steps=[
    ('escalar', StandardScaler())
], memory=memory)

Utilizamos ColumnTransformer para aplicar el escalado solo a las columnas numéricas:

preprocesamiento = ColumnTransformer(transformers=[
    ('numerico', pipeline_numerico, columnas_numericas)
])

Creamos el pipeline completo integrando el transformador personalizado y el modelo de clasificación:

pipeline = Pipeline([
    ('contador_vocales', ContadorDeVocalesTransformer(columna='frase')),
    ('preprocesamiento', preprocesamiento),
    ('clasificador', LogisticRegression())
], memory=memory)

Entrenamos el pipeline con los datos:

pipeline.fit(X, y)

Podemos realizar predicciones sobre nuevos datos:

# Nuevos datos
nuevos_datos = pd.DataFrame({
    'frase': ['Aprendizaje Automático', 'Datos y Ciencia'],
    'valor_numerico': [25, 35]
})

predicciones = pipeline.predict(nuevos_datos)
print("Predicciones:", predicciones)

El transformador personalizado se integra sin problemas en el pipeline, permitiendo que la nueva característica se genere y procese automáticamente durante el entrenamiento y la inferencia.

En algunos casos, puede ser útil implementar el método get_feature_names_out para mantener un seguimiento de los nombres de las características después de la transformación:

class ContadorDeVocalesTransformer(BaseEstimator, TransformerMixin):
    # ... código previo ...

    def get_feature_names_out(self, input_features=None):
        if input_features is None:
            input_features = []
        return np.append(input_features, 'numero_vocales')

Esto es especialmente útil cuando se trabaja con herramientas que dependen de los nombres de las características para interpretación o visualización.

Si se requiere aplicar una transformación sencilla, como convertir textos a minúsculas, se puede utilizar FunctionTransformer:

from sklearn.preprocessing import FunctionTransformer

def convertir_minusculas(X):
    X = X.copy()
    X['frase'] = X['frase'].str.lower()
    return X

transformador_minusculas = FunctionTransformer(convertir_minusculas)

pipeline = Pipeline([
    ('minusculas', transformador_minusculas),
    ('contador_vocales', ContadorDeVocalesTransformer(columna='frase')),
    ('preprocesamiento', preprocesamiento),
    ('clasificador', LogisticRegression())
], memory=memory)

El uso de FunctionTransformer es práctico para funciones simples, pero para transformaciones más complejas o cuando se necesitan parámetros adicionales, es preferible crear un transformador personalizado.

Es posible combinar múltiples transformadores personalizados dentro del mismo pipeline. Por ejemplo, si queremos añadir una característica que cuente el número de consonantes:

class ContadorDeConsonantesTransformer(BaseEstimator, TransformerMixin):
    def __init__(self, columna):
        self.columna = columna

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

    def transform(self, X):
        X = X.copy()
        X['numero_consonantes'] = X[self.columna].apply(self._contar_consonantes)
        return X

    def _contar_consonantes(self, texto):
        texto = str(texto).lower()
        return sum(1 for char in texto if char.isalpha() and char not in 'aeiou')

    def get_feature_names_out(self, input_features=None):
        if input_features is None:
            input_features = []
        return np.append(input_features, 'numero_consonantes')

Actualizamos las columnas numéricas y el preprocesamiento:

# Nuevas columnas numéricas
columnas_numericas = ['valor_numerico', 'numero_vocales', 'numero_consonantes']

# Actualizar preprocesamiento
preprocesamiento = ColumnTransformer(transformers=[
    ('numerico', pipeline_numerico, columnas_numericas)
])

Integramos el nuevo transformador en el pipeline:

pipeline = Pipeline([
    ('minusculas', transformador_minusculas),
    ('contador_vocales', ContadorDeVocalesTransformer(columna='frase')),
    ('contador_consonantes', ContadorDeConsonantesTransformer(columna='frase')),
    ('preprocesamiento', preprocesamiento),
    ('clasificador', LogisticRegression())
], memory=memory)

Entrenamos el pipeline actualizado:

pipeline.fit(X, y)

De esta forma, el pipeline aplica múltiples transformaciones personalizadas, enriqueciendo el conjunto de características y potencialmente mejorando la precisión del modelo.

Implementar transformadores personalizados es una excelente manera de adaptar el preprocesamiento a necesidades específicas y puede ser fundamental para extraer información valiosa de los datos. Al integrarlos en un pipeline, se asegura que todo el proceso sea coherente, reproducible y fácil de mantener.

Es importante seguir las buenas prácticas al crear transformadores personalizados, como manejar correctamente copias de los datos para evitar modificaciones no deseadas y documentar claramente el propósito y funcionamiento de cada transformador. Esto facilita la colaboración y el mantenimiento a largo plazo del código.

Aprende ScikitLearn GRATIS online

Ejercicios de esta lección Preprocesamiento de datos con pipelines

Evalúa tus conocimientos de esta lección Preprocesamiento de datos con pipelines con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de ScikitLearn

Accede a todas las lecciones de ScikitLearn y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Aprendizaje Automático

scikit-learn

Introducción Y Entorno

Introducción E Instalación

scikit-learn

Introducción Y Entorno

Introducción Al Preprocesamiento De Datos

scikit-learn

Preprocesamiento De Datos

Identificación Y Tratamiento De Valores Faltantes

scikit-learn

Preprocesamiento De Datos

Escalado De Datos

scikit-learn

Preprocesamiento De Datos

Normalización De Datos

scikit-learn

Preprocesamiento De Datos

Codificación De Variables Categóricas

scikit-learn

Preprocesamiento De Datos

Ingeniería De Características

scikit-learn

Preprocesamiento De Datos

Selección De Características

scikit-learn

Preprocesamiento De Datos

Extracción De Características

scikit-learn

Preprocesamiento De Datos

Particionamiento De Datos

scikit-learn

Preprocesamiento De Datos

Preprocesamiento De Datos Desbalanceados

scikit-learn

Preprocesamiento De Datos

Introducción A La Regresión

scikit-learn

Regresión

Regresión Lineal

scikit-learn

Regresión

Regresión Knn Kneighborsregressor

scikit-learn

Regresión

Regresión Svm Con Svr

scikit-learn

Regresión

Regresión Con Árboles Decisiontreeregressor

scikit-learn

Regresión

Regresión Con Algoritmos De Conjunto

scikit-learn

Regresión

Introducción A La Clasificación

scikit-learn

Clasificación

Clasificación Con Regresión Logística

scikit-learn

Clasificación

Clasificación Knn Kneighborsclassifier

scikit-learn

Clasificación

Clasificación Svm Con Svc

scikit-learn

Clasificación

Clasificación Con Árboles Decisiontreeclassifier

scikit-learn

Clasificación

Clasificación Con Algoritmos De Conjunto

scikit-learn

Clasificación

Reducción De La Dimensionalidad Con Pca

scikit-learn

Aprendizaje No Supervisado

Clustering Con Kmeans

scikit-learn

Aprendizaje No Supervisado

Clustering Jerárquico

scikit-learn

Aprendizaje No Supervisado

Clustering De Densidad Con Dbscan

scikit-learn

Aprendizaje No Supervisado

Preprocesamiento De Textos Para Nlp

scikit-learn

Nlp

Representación De Texto Y Extracción De Características

scikit-learn

Nlp

Clasificación De Texto Con Scikit Learn

scikit-learn

Nlp

Análisis De Sentimiento

scikit-learn

Nlp

Técnicas Avanzadas De Extracción De Características

scikit-learn

Nlp

Introducción Al Análisis De Series Temporales

scikit-learn

Series Temporales

Preprocesamiento De Datos De Series Temporales

scikit-learn

Series Temporales

Ingeniería De Características Para Series Temporales

scikit-learn

Series Temporales

Transformación Y Escalado De Series Temporales

scikit-learn

Series Temporales

Validación Y Evaluación De Modelos En Series Temporales

scikit-learn

Series Temporales

Validación Y Evaluación De Modelos

scikit-learn

Validación De Modelos

Técnicas De Validación Cruzada

scikit-learn

Validación De Modelos

Métricas De Regresión

scikit-learn

Validación De Modelos

Métricas De Clasificación

scikit-learn

Validación De Modelos

Ajuste De Hiperparámetros

scikit-learn

Validación De Modelos

Introducción A Pipelines

scikit-learn

Pipelines Y Despliegue

Creación De Pipelines Básicos

scikit-learn

Pipelines Y Despliegue

Preprocesamiento De Datos Con Pipelines

scikit-learn

Pipelines Y Despliegue

Pipelines Y Validación Cruzada

scikit-learn

Pipelines Y Despliegue

Pipelines Con Columntransformer

scikit-learn

Pipelines Y Despliegue

Exportar E Importar Pipelines

scikit-learn

Pipelines Y Despliegue

Accede GRATIS a ScikitLearn y certifícate

Objetivos de aprendizaje de esta lección

  • Entender el concepto de escalado y normalización como pasos de preprocesamiento clave en pipelines de algoritmos de aprendizaje automático.
  • Ser capaz de implementar transformaciones de escalado y normalización en pipelines utilizando bibliotecas como Scikit-Learn.
  • Evaluar la precisión de diferentes métodos de escalado y normalización a través de validación cruzada.
  • Conocer la importancia de la consistencia en la aplicación de transformaciones de datos para evitar errores durante el entrenamiento y la predicción.
  • Comprender las buenas prácticas para optimizar el rendimiento del pipeline, incluyendo la caché de resultados intermedios.