Técnicas de normalización de variables numéricas con Python

En este tutorial vamos a ver las mejores técnicas de normalización de variables numéricas para Machine Learning y las vamos a implementar en Python.

¿Qué es la normalización de datos?

En ocasiones puede ser conveniente transformar las variables numéricas de manera que logremos cambiar la distribución de los datos para que se corresponda con una distribución normal o gaussiana.

Normalizar en este ámbito viene de distribución normal (o gaussiana).

Una distribución normal es una forma específica de distribuir los datos, caracterizada por la famosa "curva de campana". En una distribución normal:

  • La mayoría de los datos cae cerca de la media (el centro de la curva).
  • La probabilidad de alejarse de la media disminuye exponencialmente.
  • Está simétricamente distribuida, lo que significa que los datos a un lado de la media son un espejo de los datos al otro lado.

¿Cuándo es conveniente normalizar las variables numéricas?

Es conveniente normalizar las variables numéricas cuando vamos a utilizar modelos de Machine Learning que asumen que los datos de entrada siguen una distribución normal.

Este es el caso de la regresión logística y de la regresión lineal.

En ocasiones al transformar la distribución de las características numéricas y convertirlas en gaussianas conseguimos incluso descubrir relaciones lineales entre las características y la variable objetivo, lo que puede mejorar el rendimiento de los modelos de Machine Learning que se basan en este tipo de relaciones entre los datos (como la regresión lineal y logística, que te comentaba antes 🙂).

Diferencia entre normalización y escalado de variables numéricas

Otro tipo de transformación habitual de variables numéricas es el escalado.

El escalado de variables se refiere al proceso de ajustar el rango de los datos numéricos para que se ajusten a una escala común.

En ocasiones se utiliza indistintamente el término "normalización" de variables numéricas para hacer referencia al escalado de variables y a la transformación de la distribución.

En este tutorial vamos a utilizar únicamente técnicas de transformación de la distribución pero puedes ver técnicas de escalado de variables numéricas y cuándo aplicarlas en este otro tutorial.

Ejemplo de transformación de variables numéricas en Python

Para implementar en Python las transformaciones sobre las variables numéricas y cambiar su distribución vamos a utilizar el dataset Breast cancer Wisconsin (diagnosis) que está incluido en Scikit-learn.

El dataset se compone de características extraídas de imágenes digitalizadas de biopsias de mama.

Hay un total de 30 características, que se pueden agrupar en diez categorías principales, cada una con tres estadísticas: el promedio, el error estándar, y el "peor" o mayor (la media de las tres medidas más grandes) de estas características.

Te cuento un poco más sobre las categorías de características principales:

  1. Radio: Mide el promedio de las distancias desde el centro del núcleo celular hasta su contorno. Un radio mayor puede indicar un crecimiento anormal de las células, lo cual es un indicativo potencial de malignidad.
  2. Textura: Mide la variación en la escala de grises en las imágenes del tejido. La textura más áspera o irregular puede ser un signo de tejido tumoral, dado que los tejidos cancerosos a menudo tienen una apariencia más desordenada comparada con los tejidos normales.
  3. Perímetro: Mide el tamaño del contorno del núcleo celular. Un perímetro irregular o en aumento es común en los tumores malignos debido a su crecimiento y forma anormal.
  4. Área: Mide el tamaño del área ocupada por el núcleo celular. El aumento del área puede ser un indicativo de células cancerosas, que tienden a ser más grandes que las células normales.
  5. Suavidad: Mide la variación local en las longitudes de los radios del núcleo. La suavidad o la textura irregular de los bordes del núcleo pueden indicar malignidad.
  6. Compacidad: Mide el grado en que el perímetro y el área del núcleo se aproximan a los de un círculo perfecto (perímetro^2 / área). Las células tumorales a menudo presentan una mayor compacidad debido a su crecimiento desordenado y densidad.
  7. Concavidad: Mide la severidad de las porciones cóncavas del contorno del núcleo. La presencia de concavidades en el contorno puede indicar que el núcleo está siendo invadido por tejido tumoral, que a menudo se muestra irregular.
  8. Puntos Cóncavos: Mide el número de porciones cóncavas en el contorno del núcleo. Los puntos cóncavos pueden ser indicativos de la formación de nuevos tumores o de la invasión de tejidos adyacentes.
  9. Simetría: Evalúa la simetría del núcleo celular. Una simetría reducida puede ser un signo de cáncer, ya que las células normales tienden a ser más simétricas.
  10. Dimensión Fractal: Mide la complejidad del contorno del núcleo. Un valor más alto puede indicar una frontera más compleja y fracturada, común en la morfología de las células cancerosas.

Además, cada muestra en el dataset tiene una etiqueta que indica si el tumor es maligno (M) o benigno (B).

Vamos a importar las librerías que vamos a usar y a cargar el dataset 🙂.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as stats            
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import FunctionTransformer

cancer_data = load_breast_cancer()
data = pd.DataFrame(cancer_data.data,columns=cancer_data.feature_names)

Ahora vamos a representar el histograma de las características que representan el error estándar, que son las que vamos a transformar.

data.iloc[:,10:20].hist(bins=30, figsize=(15, 10))
plt.tight_layout()
plt.show()
Normalización de la distribución en variables numéricas con Python

Aquí te muestro el histograma de las 6 características que vamos a poner de ejemplo en este tutorial.

Antes de proseguir, decirte que puedes aplicar las siguientes técnicas sobre todas las variables numéricas pero tienes que cerciorarte de que no toman valores nulos en las transformaciones que no lo soportan.

# Hacemos una copia del DataFrame
data_transformada = data.iloc[:,10:20].copy()

# Comprobamos si las características que hemos seleccionado (las correspondientes al error) toman valores nulos
if (data_transformada == 0).any().any():
    print("Hay valores cero en el dataset.")
else:
    print("No hay valores cero en el dataset.")

# Reemplazamos los ceros por un valor pequeño
data_transformada.replace(0, 1e-6, inplace=True)

Sobre los valores faltantes, ya te aviso yo de que este dataset no tiene 🙂.

Trasformación logarítmica

La transformación logarítmica es muy útil cuando queremos transformar la distribución de una característica numérica.

¿Cuándo aplicar una transformación logarítmica para normalizar los datos?

Especialmente es conveniente aplicar una transformación logarítmica en estos si la característica numérica que quieres transformar cumple lo siguiente:

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Transformación logarítmica con numpy

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Transformación logarítmica con Scikit-learn

Vamos a transformar con Scikit-learn únicamente las 6 primeras características.

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Transformación recíproca

La transformación recíproca es otra técnica de preprocesamiento de características numéricas que puede ser útil en análisis de datos y machine learning, especialmente cuando trabajamos con variables que no se distribuyen de manera normal.

Esta transformación implica calcular el recíproco de cada valor de la variable, es decir, 1/x para cada valor x en el conjunto de datos.

¿Cuándo aplicar una transformación recíproca?

Aquí hay algunas situaciones donde aplicar una transformación recíproca puede ser conveniente:

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Transformación recíproca con numpy

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Transformación recíproca con Scikit-learn

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Potenciación y raíces

La transformación de variables numéricas mediante potenciación consiste simplemente en elevar los valores de la característica que queremos transformar a una potencia determinada.

¿Cuándo aplicar una transformación basada en potenciación?

Cuando los datos tienen un sesgo significativo (ya sea positivo o negativo), elevarlos a una potencia puede ayudar a corregir este sesgo y acercar la distribución a una normal.

Por ejemplo:

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Transformación Box-Cox

La transformación Box-Cox es un método estadístico parecido a la potenciación que se utiliza para hacer que los datos sean más similares a una distribución normal (que es lo que hemos venido a hacer hoy 😉).

Es especialmente útil cuando tratamos con datos que no cumplen los supuestos de normalidad requeridos para muchos análisis de datos o si queremos aplicar modelos de regresión.

⚠️ Un detalle importante es que la transformación Box-Cox solo se puede aplicar directamente a datos positivos. Si los datos incluyen ceros o valores negativos, se deben ajustar sumando una constante antes de aplicar la transformación.

Box-COx con Scipy

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

Box-Cox con Scikit-learn

Este contenido está únicamente disponible para suscriptores. Puedes identificarte en este enlace o apuntarte a la plataforma.

PowerTransformer() permite aplicar transformaciones a los datos para hacer que su distribución se parezca más a la distribución normal. Este transformador es capaz de aplicar dos tipos de transformaciones: Box-Cox y Yeo-Johnson.

Al crear el transformador PowerTransformer, debes especificar qué método de transformación deseas usar. En este caso: Box-Cox.

PowerTransformer tiene un argumento llamado standardize. Si lo estableces en True, el transformador escalará los valores transformados para que tengan media 0 y varianza 1.

Antes de transformar los datos, necesitas "ajustar" el transformador a los datos que quieres transformar. Esto implica que PowerTransformer analizará los datos proporcionados y aprenderá los valores óptimos de lambda (λ) para cada variable. Esto se hace llamando al método fit() en la porción del DataFrame que contiene las variables que deseas transformar.

Una vez que el transformador está ajustado, almacena los valores de λ aprendidos en su atributo lambdas_, que puedes revisar para entender cómo se transformó cada variable.

Finalmente, usas el método transform() sobre la porción del DataFrame que quieres transformar. Esto aplicará la transformación Box-Cox (con los λ aprendidos durante el ajuste) a los datos y devolverá los valores transformados en un array de Numpy que luego volvemos a convertir en dataframe de Pandas.

Ten en cuenta que para hacer predicciones con modelos que incluyen características numéricas transformadas, generalmente necesitamos revertir la transformación (por ejemplo, exponenciando si hemos aplicado un logaritmo).

Es importante que tengas esto en cuenta para que las predicciones sean interpretables y comparables con los valores observados.

Boletín Ninja

Suscríbete a la newsletter y recibe la guía ninja del Big Data y la Inteligencia Artificial.

Guía ninja del Big Data
Copyright © 2024  · Datos 🥷 · Todos los derechos reservados
💼 Aviso legal y cookies