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

Ene 23, 2021 | Preprocesamiento de datos | 0 Comentarios

Seguimos con esta serie de publicaciones donde explicamos diferentes técnicas que se encargan de codificar variables categorías. Si te perdiste la anterior publicación puedes echarle un vistazo aquí.

Como ya explicamos, la mayoría de los modelos de machine learning en Python, entre ellos las redes neuronales, solo pueden leer valores numéricos y por ello es importante convertir este tipo de variables categóricas en numéricas para que los modelos puedan utilizarlas.

En la anterior entrega presentamos los métodos más populares: la codificación ordinal y one-hot. En esta ocasión nos centraremos en otros dos métodos probablemente no tan conocidos, pero bastante útiles en caso de que tengamos variables categóricas de alta cardinalidad: la codificación binaria y hashing.

 

El conjunto de datos Adult

En los casos prácticos seguiremos usando el conjunto de datos Adult, perteneciente al repositorio UCI Machine Learning. Como ya explicamos, este dataset contiene 48.842 instancias que representan datos personales (edad, género, raza, etc.) de ciudadanos anónimos extraídos de la base de datos del Censo de 1994 de los Estados Unidos.

En primer lugar, cargamos el dataset usando para ello la función read_csv de pandas y lo almacenamos en un un objeto DataFrame. Posteriormente le asignamos el nombre de cada columna como se muestra en el siguiente código:

In [1]:
import pandas as pd

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

# Añadimos el nombre de cada variable
df.columns = ["age", "workclass", "fnlwgt", "education", 
              "education-num", "marital-status", "occupation", 
              "relationship", "race", "sex", "capital-gain", 
              "capital-loss", "hours-per-week", "native-country", 
              "class"]

 

Codificación binaria

Este tipo de codificación binaria es parecido a one-hot, pero en este caso las categorías se almacenan primero como códigos binarios. Los pasos que sigue este método para codificar son los siguientes:

  • Primeramente, cada categoría única de nuestra variable categórica se convierte en un número ordinal sin tener en cuenta ningún orden. Así, este número irá desde el 1 hasta el número total de categorías únicas que tengamos.
  • Después, estos valores ordinales se transforman a su código binario. De esta manera, la categoría que le corresponda un valor de 10 se convertiría al código binario 1010.
  • Finalmente, cada dígito binario se separa en distintas columnas, una por cada dígito, por lo que para el código binario 1010 necesitaríamos 4 columnas.

Para calcular el número total de columnas que se crearán tras este procedimiento, podemos aplicar la siguiente formula, cuyo resultado deberemos redondear hacia arriba:

    \begin{align*} \frac{\log(n + 1)}{\log(2)}\end{align*}

donde n es el número total de categorías.

Entonces, si queremos saber cuántas columnas se necesitan para codificar una variable con 10 categorías, aplicamos la anterior fórmula y tenemos que necesitamos 4 columnas.

Esta claro que esta técnica nos proporciona una solución con muchas menos dimensiones que en el caso de one-hot, por lo que este método es recomendable cuando tenemos un gran número de categorías únicas y estamos buscando reducir la cardinalidad. ¡Mediante este proceso podrás representar 10.000 categorías con tan solo 14 columnas!

Para poder aplicar este tipo de codificación en Python, la librería category_encoders nos proporciona el objeto BinaryEncoder. Veamos un ejemplo de cómo podemos utilizarlo en nuestro dataset. Aplicaremos esta codificación a la variable native-country, que contiene 42 categorías únicas correspondientes a nombres de países.

A partir de la anterior fórmula, sabemos que vamos a necesitar 6 columnas. Ahora sí, creamos el codificador indicándole en nombre de nuestra columna, lo ajustamos con esta y finalmente la transformamos.

In [2]:
from category_encoders import BinaryEncoder

# Creamos el codificador indicandole la columna
encoder = BinaryEncoder(cols=["native-country"])

# Ajustamos el codificador con native-country y la transformamos
encoder.fit(df["native-country"])
df_binario = encoder.transform(df["native-country"])
df = pd.concat([df, df_binario], axis=1)
Ahora solo nos queda mostrar la antigua variable native-country junto con las nuevas variables creadas para comparar.
In [3]:
df.loc[:, df.columns.str.startswith('native-country')].head()
Out[3]:
native-country native-country_0 native-country_1 native-country_2 native-country_3 native-country_4 native-country_5 native-country_6
0 United-States 0 0 0 0 0 0 1
1 United-States 0 0 0 0 0 0 1
2 United-States 0 0 0 0 0 0 1
3 United-States 0 0 0 0 0 0 1
4 Cuba 0 0 0 0 0 1 0
Vemos en la tabla que se han creado 7 nuevas columnas binarias para representar todos los países. Como podéis observar, BinaryEncoder nos creará la mayor parte de las veces una variable de más que no utiliza. Si investigamos un poco más veremos que se trata de la variable native-country_0, ya que solo contiene ceros, por lo que sería buena idea eliminarla del conjunto de datos.

 

Codificación hashing

La principal característica de la codificación hashing es que utiliza una función hash para asignar un número de longitud fija a cada categoría única. Para conocer cómo funciona de manera detallada podéis consultar el paper original.

Para emplear este método en Python, usaremos de nuevo la librería category_encoders que nos proporciona el objeto HashingEncoder. Pero antes debemos tener en cuanto los siguientes factores.

Por defecto, el codificador hashing implementado en category_encoders utiliza el algoritmo hash denominado MD5 (Message Digest Algorithm 5), pero podemos elegir cualquier otro algoritmo siempre que se encuentre dentro del módulo hashlib en Python. Para ello debemos indicar el algoritmo de nuestra elección con el argumento hash_method.

Además, debemos elegir el numero de bits que vamos a usar para representar la variable, es decir, el número de dimensiones que obtendremos tras la codificación. Para ello simplemente le indicamos el número que queramos mediante el argumento n_components.

Probablemente os estaréis preguntado cuántas dimensiones necesitáis para representar vuestra variable categórica. No hay una respuesta clara sobre esto, pero si miramos en la documentación oficial, la función utiliza por defecto 8 bits para representar la variable y nos recomiendan usar hasta 32 en caso de que se trate de una variable de alta cardinalidad.

Asimismo, debemos tener en cuenta que si tenemos un gran número de categorías y elegimos un número de columnas demasiado bajo, corremos el riesgo de que se produzca una colisión de hash, es decir, que dos entradas distintas tengan el mismo valor hash.

Dicho esto, estamos listos para ver un ejemplo de cómo podemos utilizarlo con la variable native-country de nuestro dataset. Lo primero de todo y como recordaréis, necesitamos fijar el número de dimensiones. En este caso usaré 6 dimensiones para representar las 42 categorías de nuestra variable native-country.

In [4]:
from category_encoders import HashingEncoder

# Creamos el codificador indicandole el número de columnas
encoder = HashingEncoder(n_components=6)

# Ajustamos el codificador con native-country y la transformamos
encoder.fit(df["native-country"])
df_hash = encoder.transform(df["native-country"])
df = pd.concat([df, df_hash], axis=1)
Del mismo modo, mostramos la variable native-country junto con las nuevas variable creadas.
In [5]:
df.loc[:, df.columns.str.startswith('col_') | 
       df.columns.str.startswith("native")].head(8)
Out[5]:
native-country native-country_0 native-country_1 native-country_2 native-country_3 native-country_4 native-country_5 native-country_6 col_0 col_1 col_2 col_3 col_4 col_5
0 United-States 0 0 0 0 0 0 1 0 0 0 0 1 0
1 United-States 0 0 0 0 0 0 1 0 0 0 0 1 0
2 United-States 0 0 0 0 0 0 1 0 0 0 0 1 0
3 United-States 0 0 0 0 0 0 1 0 0 0 0 1 0
4 Cuba 0 0 0 0 0 1 0 0 1 0 0 0 0
5 United-States 0 0 0 0 0 0 1 0 0 0 0 1 0
6 Jamaica 0 0 0 0 0 1 1 0 0 1 0 0 0
7 United-States 0 0 0 0 0 0 1 0 0 0 0 1 0
Al igual que en el caso anterior, con este método el número de dimensiones será también mucho menor que usando otro tipo de técnicas como la codificación one-hot, por lo que será de gran utilidad cuando la cardinalidad de nuestra variable categórica sea muy alta.

Además, con esta técnica podemos elegir nosotros mismos el número de dimensiones a utilizar y nos aseguramos de esta manera que nunca aumente.

Eso sí, un inconveniente que tenemos que tener en cuenta al usar este método es el hecho de que no se puede deshacer un hash MD5 o cualquier otra función hash unidireccional.

En esta ocasión hemos aprendido otras dos aproximaciones no tan conocidas para codificar variables categóricas. Si te ha parecido útil o interesante este contenido, por favor, ¡compártelo!

Como siempre recordar que el código usado en este artículo se puede obtener desde mi GitHub.

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 (III): codificación target

Aprende con ejemplos prácticos el funcionamiento de la codificación target, que utiliza información sobre la variable objetivo.

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!