Representación: Ingeniería de atributos

En la programación tradicional, la atención se centra en el código. En los proyectos de aprendizaje automático, el foco cambia a la representación. Es decir, una forma en que los desarrolladores perfeccionan un modelo es agregar y mejorar sus atributos.

Asignación de datos sin procesar a los atributos

A la izquierda de la Figura 1, se muestran datos sin procesar de una fuente de datos de entrada; a la derecha, se muestra un vector de atributos, que es el conjunto de valores de punto flotante que incluye los ejemplos en el conjunto de datos. La ingeniería de atributos es la transformación de datos sin procesar en un vector de atributos. Debes dedicar una gran cantidad de tiempo a la ingeniería de atributos.

Muchos modelos de aprendizaje automático deben representar los atributos como vectores de números reales, ya que los valores de los atributos deben multiplicarse por los pesos del modelo.

Los datos sin procesar se asignan a un vector de atributos a través de un proceso llamado ingeniería de atributos.

Figura 1: La ingeniería de atributos asigna datos sin procesar a atributos de AA.

Cómo asignar valores numéricos

Los datos de número entero y de punto flotante no necesitan una codificación especial porque se pueden multiplicar por un peso numérico. Como se sugiere en la Figura 2, convertir el valor entero sin procesar 6 en el valor de atributo 6.0 es sencillo:

Un ejemplo de un atributo que se puede copiar directamente de los datos sin procesar

Figura 2: Asignación de valores enteros a valores de punto flotante

Asignación de valores categóricos

Los atributos categóricos tienen un conjunto discreto de valores posibles. Por ejemplo, podría haber una función llamada street_name con opciones que incluyan las siguientes:

{'Charleston Road', 'North Shoreline Boulevard', 'Shorebird Way', 'Rengstorff Avenue'}

Dado que los modelos no pueden multiplicar strings por los pesos aprendidos, usamos la ingeniería de atributos para convertir strings en valores numéricos.

Para ello, definimos una asignación de los valores de los atributos, a los que nos referiremos como vocabulario de valores posibles, a números enteros. Dado que no todas las calles del mundo aparecerán en nuestro conjunto de datos, podemos agrupar todas las demás calles en una categoría general llamada "otras", que se conoce como un bucket OOV (fuera del vocabulario).

Mediante este enfoque, podemos asignar nombres de calles a números de la siguiente manera:

  • asignar Charleston Road a 0
  • asignar North Shoreline Boulevard a 1
  • asignar Shorebird Way a 2
  • asignar Rengstorff Avenue a 3
  • asignar todo lo demás (OOV) a 4

Sin embargo, si incorporamos estos números índice directamente en nuestro modelo, impondrá algunas restricciones que podrían ser problemáticas:

  • Aprenderemos un peso único que se aplique a todas las calles. Por ejemplo, si aprendemos un peso de 6 para street_name, lo multiplicaremos por 0 para Charleston Road, por 1 para North Shoreline Boulevard, por 2 para Shorebird Way y así sucesivamente. Considera un modelo que prediga el precio de las casas usando street_name como atributo. Es poco probable que haya un ajuste lineal del precio basado en el nombre de la calle. Además, esto supondrá que ordenaste las calles según el precio promedio de las casas. Nuestro modelo necesita la flexibilidad de aprender los diferentes pesos para cada calle, que se agregarán al precio estimado con los otros atributos.

  • No estamos contemplando los casos en los que street_name puede tener varios valores. Por ejemplo, muchas casas se encuentran en la esquina de dos calles y no hay forma de codificar esa información en el valor street_name si este contiene un solo índice.

Para quitar ambas restricciones, podemos crear un vector binario para cada atributo categórico de nuestro modelo que represente valores de la siguiente manera:

  • En el caso de los valores que se aplican al ejemplo, establece los elementos correspondientes al vector en 1.
  • Establecer todos los demás elementos en 0.

La longitud de este vector es igual a la cantidad de elementos en el vocabulario. Esta representación se denomina codificación one-hot cuando un único valor es 1 y codificación multi-hot cuando varios valores son 1.

La figura 3 ilustra una codificación one-hot de una calle determinada: Shorebird Way. El elemento del vector binario de Shorebird Way tiene un valor de 1, mientras que los elementos de todas las demás calles tienen un valor de 0.

Asignación de un valor de string (

Figura 3: Asignación de direcciones de calle mediante codificación one-hot.

Este enfoque crea de manera efectiva una variable booleana para cada valor de atributo (p.ej., nombre de la calle). En este caso, si una casa se encuentra en Shorebird Way, el valor binario es solo 1 para Shorebird Way. Por lo tanto, el modelo utiliza solo el peso para la calle Shorebird Way.

Del mismo modo, si una casa se encuentra en la esquina de dos calles, entonces dos valores binarios se establecen en 1, y el modelo usa ambos pesos respectivos.

Representación dispersa

Supongamos que tienes 1,000,000 de nombres de calles diferentes en tu conjunto de datos y que deseas incluir como valores para street_name. La creación explícita de un vector binario de 1,000,000 de elementos en los que solo 1 o 2 son verdaderos es una representación muy ineficiente en términos de almacenamiento y tiempo de procesamiento cuando se procesan estos vectores. En esta situación, un enfoque común es usar una representación dispersa en la que solo se almacenen los valores que no son cero. En las representaciones dispersas, se aprende un peso de modelo independiente para cada valor de atributo, como se describió anteriormente.