Técnicas para codificar las variables categóricas (III): codificación target

Feb 12, 2021 | Preprocesamiento de datos | 0 Comentarios

Continuamos con nuestra serie que tiene como objetivo explicar diferentes procedimientos para codificar variables categorías. En la primera parte explicamos los métodos más comúnmente usados: la codificación ordinal y one-hot.

En la segunda publicación de la serie nos centraremos en otros dos procesos recomendables cuando contamos con variables categóricas de alta cardinalidad: la codificación binaria y hashing.

Para esta ocasión os mostraremos un método perteneciente al conjunto de las llamadas codificaciones bayesianas, que se caracterizan por incorporar información sobre la variable objetivo, es decir, la variable que queremos predecir.

La técnica que trataremos aquí se denomina codificación target (también llamada mean). La idea general de este método consiste en reemplazar el valor de cada categoría por el valor medio de la variable objetivo asociado a esa categoría. Veamos cómo funciona en más profundidad y por qué puede resultarnos útil.

 

El conjunto de datos Automobile Data Set

Al contrario que en las otras dos entregas, en esta ocasión sí que estamos interesados en la variable objetivo. Debido a ello, hemos escogido el conjunto de datos Automobile Data Set perteneciente al repositorio UCI Machine Learning para realizar el nuestro ejercicio práctico.

Este clásico dataset contiene 26 características de 205 modelos de automóviles del año 1985 como, por ejemplo, el tipo de gasolina que usa, la marca del automóvil o el número de cilindradas. La variable que utilizaremos como objetivo es price, que representa el precio del automóvil.

Comenzamos cargando los datos y rellenando los valores perdidos de la variable price para evitar posibles problemas posteriores. También mostramos las primeras observaciones para hacernos una primera idea.

In [1]:
import pandas as pd

# Cargamos el dataset
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-'
                 'databases/autos/imports-85.data', encoding = 'utf-8', 
                 header = None)

# Añadimos el nombre de cada variable
df.columns = ["symboling","normalized-losses","make","fuel-type",
              "aspiration","num-of-doors","body-style","drive-wheels",
              "engine-location","wheel-base","length","width",
              "height","curb-weight","engine-type","num-of-cylinders",
              "engine-size","fuel-system","bore","stroke",
              "compression-ratio","horsepower","peak-rpm","city-mpg",
              "highway-mpg","price"]

# Rellenamos los valores perdidos
df['price'] = df['price'].replace(['?'], 10000)

# Convertimos columna "price" a numerica
df["price"] = pd.to_numeric(df["price"])

df.head()
Out[1]:
symboling normalized-losses make fuel-type aspiration num-of-doors body-style drive-wheels engine-location wheel-base ... engine-size fuel-system bore stroke compression-ratio horsepower peak-rpm city-mpg highway-mpg price
0 3 ? alfa-romero gas std two convertible rwd front 88.6 ... 130 mpfi 3.47 2.68 9.0 111 5000 21 27 13495
1 3 ? alfa-romero gas std two convertible rwd front 88.6 ... 130 mpfi 3.47 2.68 9.0 111 5000 21 27 16500
2 1 ? alfa-romero gas std two hatchback rwd front 94.5 ... 152 mpfi 2.68 3.47 9.0 154 5000 19 26 16500
3 2 164 audi gas std four sedan fwd front 99.8 ... 109 mpfi 3.19 3.40 10.0 102 5500 24 30 13950
4 2 164 audi gas std four sedan 4wd front 99.4 ... 136 mpfi 3.19 3.40 8.0 115 5500 18 22 17450

5 rows × 26 columns

 

 

¿En qué consiste la codificación target?

Mediante la codificación target sustituimos nuestra variable categórica por una única nueva variable de tipo numérico que, como hemos dicho, contiene información de la variable objetivo. El funcionamiento en su forma básica es bastante simple:

  • En primer lugar, por cada categoría única que tenga la variable a codificar se calcula la media correspondiente a sus valores en la variable objetivo.
  • Después, se reemplaza cada valor por el de la media calculada.

Eso sería en el supuesto de que nuestra variable objetivo sea numérica, pero también se puede recurrir a esta técnica para varaibles categóricas, en cuyo caso se calcula la probabilidad asociada a esa categoría en lugar de la media.

La ventaja de este método es que es bastante rápido y no añade dimensiones a nuestro conjunto de datos.

 

Ejemplo práctico

Veamos ahora un ejemplo práctico para entender cómo podemos utilizarlo en nuestro dataset. De nuevo la librería category_encoders viene a nuestro rescate y nos proporciona el objeto TargetEncoder para poder aplicar esta técnica de manera sencilla.

Aplicaremos esta codificación a la variable make, que contiene 22 categorías únicas correspondientes a la marca del automóvil y que tomará valores como, por ejemplo, audi, volvo o alfa-romero.

Comenzamos creando el codificador, indicándole para ello en nombre de la variable a codificar make. Para conseguir el mismo resultado que el algoritmo explicado antes, debemos ajustar el parámetro smoothing a 0. Después explicaremos por qué no es recomendable hacer esto, pero por ahora y con fines didácticos lo dejamos a 0.

Después, ajustamos el codificador pasándole las dos columnas: la variable objetivo, que como recordareis es  price, y la que queremos codificar. Por último, transformamos la variable.

In [2]:
from category_encoders import TargetEncoder

# Creamos el codificador Target indicando nuestra variable
encoder = TargetEncoder(cols = ['make'], smoothing = 0)

# Ajustamos el codificador indicandole la variable objetivo
encoder.fit(df["make"], df['price'])
new_make = encoder.transform(df["make"], df['price'])

# Concatenamos la nueva variable con el resto
df = pd.concat((df, new_make.make.rename('new_make')), axis=1)
Seguidamente, mostramos la antigua variable make junto con la nueva codificada (new_make) y price para ver los resultados.
In [3]:
df[["make", "price", "new_make"]].head(8)
Out[3]:
make price new_make
0 alfa-romero 13495 15498.333333
1 alfa-romero 16500 15498.333333
2 alfa-romero 16500 15498.333333
3 audi 13950 16736.428571
4 audi 17450 16736.428571
5 audi 15250 16736.428571
6 audi 17710 16736.428571
7 audi 18920 16736.428571

En la anterior tabla se puede ver claramente que a las observaciones pertenecientes a la categoría alfa-romero se les ha asignado el valor 15498.333, que no es más que la media del precio en las tres instancias que pertenecen a esa categoría: (13495 + 16500 + 16500) / 3 = 15498.333. Sencillo, ¿verdad?

Es importante señalar que en un escenario en el que tengamos un conjunto de datos de entrenamiento y otro de validación, solo deberemos ajustar el codificador con el conjunto de entrenamiento, es decir, calcularemos las medias teniendo en cuentas los datos de entrenamiento.

 

Como evitar el sobreajuste

Debido a la fuerte relación que tiene con la variable objetivo, el problema de utilizar este método es que puede dar lugar a sobreajuste. Esto se puede dar sobre todo en los casos en los tenemos pocos valores en las categorías y tenemos que calcular la media de esos valores. Debido a ello, no es recomendable usar esta técnica sin algún tipo de regularización para evitar el sobreajuste.

Afortunadamente, hay varios mecanismos para tratar este problema. Uno de ellos consiste en utilizar la técnica de validación cruzada (cross-validation en inglés) y calcular en cada iteración la media de los datos de entrenamiento. Finalmente se realiza la media de los resultados de cada iteración para obtener el resultado final.

Otra técnica de regularización es el llamado smoothing, que además nos viene por defecto en la librería category_encoders. No entraremos en los detalles sobre el funcionamiento de esta técnica. En este paper encontrareis una explicación en profundidad de este tipo de regularización. En líneas generales, mediante este proceso de suavizado, cuanto más pequeño sea nuestro conjunto de datos, el resultado sera mas cercano al valor medio global de la variable objetivo.

Volvamos a nuestro ejemplo práctico. Como ya vimos, al construir el objeto TargetEncoder, le podemos indicar el nivel de regularización que queremos mediante el argumento smoothing. Un valor más alto significa una regularización más fuerte.

En el ejemplo anterior, al ajustar el valor de smoothing a 0, no estábamos usando regularización y en consecuencia nos devolvía simplemente la media correspondiente a sus valores en la variable objetivo como ya comprobamos.

De manera análoga, aplicamos la codificación a nuestra variable, pero en esta ocasión ajustando el valor de smoothing a 3:

In [4]:
# Creamos el codificador Target indicando nuestra variable
encoder = TargetEncoder(cols = ['make'], smoothing = 3)

# Ajustamos el codificador indicandole la variable objetivo
encoder.fit(df["make"], df['price'])
new_make = encoder.transform(df["make"], df['price'])

# Concatenamos la nueva variable con el resto
df = pd.concat((df, new_make.make.rename('new_make_smooth')), axis=1)
Del mismo modo, mostramos la nueva variable new_make_smooth junto con el resto con el fin de comparar los resultados.
In [5]:
df[["make", "price", "new_make", "new_make_smooth"]].head(8)
Out[5]:
make price new_make new_make_smooth
0 alfa-romero 13495 15498.333333 14699.827742
1 alfa-romero 16500 15498.333333 14699.827742
2 alfa-romero 16500 15498.333333 14699.827742
3 audi 13950 16736.428571 16308.266296
4 audi 17450 16736.428571 16308.266296
5 audi 15250 16736.428571 16308.266296
6 audi 17710 16736.428571 16308.266296
7 audi 18920 16736.428571 16308.266296

Observamos que aplicando la técnica de smoothing los valores son distintos y más bajos que cuando no lo aplicamos.

Con este post, hemos aprendido a utilizar la codificación target y aplicar la regularización mediante la técnica smoothing. Si queréis repasar todas las técnicas de codificación que hemos visto hasta ahora, no dudes en echar un vistazo a nuestra serie completa:

Para más información recordar que podéis ver todo el código usado en este artículo desde nuestra cuenta de GitHub y si tienes cualquier duda, nos la podéis hacer llegar a través de los comentarios.

También te puede interesar:

Técnicas para codificar las variables categóricas (I): codificación ordinal y one-hot

Aprende con ejemplos el funcionamiento de los métodos más populares para codificar variables categóricas: la codificación ordinal y one-hot.

Técnicas para codificar las variables categóricas (II): codificación binaria y hashing

Aprende la codificación binaria y hashing: dos métodos muy útiles en caso de que tengamos variables categóricas de alta cardinalidad.

Identificación e imputación de valores perdidos en Python

Dedicaremos esta nueva publicación a explicar cómo detectar, eliminar e imputar los valores perdidos en nuestros conjuntos de datos en Python mediante un ejemplo práctico.

Ads Blocker Image Powered by Code Help Pro

Por favor, permite que se muestren anuncios en nuestro sitio web

Querido lector,

Esperamos que estés disfrutando de nuestro contenido. Entendemos la importancia de la experiencia sin interrupciones, pero también queremos asegurarnos de que podamos seguir brindándote contenido de alta calidad de forma gratuita. Desactivar tu bloqueador de anuncios en nuestro sitio nos ayuda enormemente a lograrlo.

¡Gracias por tu comprensión y apoyo!