Machine Learning con Princesas Disney

A menos que hayas estado viviendo en una cueva desconectado del mundo durante los últimos años, seguro que estás al tanto de uno de los fenómenos que ha resurgido con fuerza: las Princesas Disney. Aunque algunas llevan desde los años cuarenta del siglo pasado entre nosotros y el concepto de unir a todas las protagonistas femeninas de películas Disney data de los 90, desde finales de los 2000 han recuperado su tirón en determinados sectores de la población.

Al igual que las Princesas Disney, en los últimos tiempos el machine learning (aprendizaje automático) ha vuelto a ser una disciplina en auge. No se trata de algo nuevo, las ideas en las que se basa y muchos de los algoritmos que utiliza son de hace varias décadas, pero la potencia de cálculo disponible actualmente (bendita nube) y el volumen de datos recolectado por los sistemas modernos ha hecho que vuelva a estar en el candelero.

OJO: No soy un experto en machine learning (ni en Princesas Disney) y no creo que lo sea a corto plazo, así que es probable que en este post haya imprecisiones o, directamente, errores. Estaré encantado de recibir correcciones en los comentarios.

Machine Learning

A grandes rasgos, el machine learning consiste en el proceso de grandes volúmenes de datos no estructurados para intentar detectar generalizaciones entre ellos. Por ejemplo, a partir de información de miles de compras podríamos intentar buscar patrones que nos indiquen si una compra es potencialmente fraudulenta o si un cliente es más propenso o no a volver a comprar después de adquirir determinados productos.

Existen varios tipos de algoritmos de machine learning, pero en general podríamos separarlos en dos tipos:

  • Aprendizaje supervisado: son algoritmos que alimentamos con un conjunto de valores de entrada para los cuales conocemos la salida obtenida. El algoritmo se encargará de construir un modelo que, dado un valor de entrada, sea capaz de generar la salida esperada. Un ejemplo típico son los filtros bayesianos que se utilizan en lo sistemas antispam. A partir de muchos correos de los que sabemos a priori si son spam o no, construimos un modelo que nos permita decidir si un nuevo correo es o no es spam.
  • Aprendizaje no supervisado: son algoritmos en los cuales sólo tenemos ejemplos, pero no existe una categorización a priori. Estos algoritmos lo que hacen es clasificar los valores de entrada, permitiéndonos encontrar relaciones entre ellos que no conocíamos inicialmente. Un ejemplo de esto serían algoritmos que nos permitiesen segmentar una base de datos de clientes para luego lanzar ofertas personalizadas.

Estos algoritmos suelen tener una base estadística importante y no siempre son fáciles de implementar, pero por suerte existen librerías que nos dan parte del trabajo hecho.

Analizando las Princesas Disney

Para jugar un poco con estas ideas vamos a utilizar numl, una librería para .NET disponible como paquete NuGet que implementa varios algoritmos de machine learning, tanto supervisados como no supervisados, y que resulta bastante fácil de manejar una vez que comprendemos ciertos conceptos.

Los algoritmos de machine learning necesitan recibir un conjunto de ejemplos iniciales para generar las funciones que nos permitan predecir el valor de salida en el caso de los algoritmos de aprendizaje supervisado, o establecer las categorías en el caso e los algoritmos de aprendizaje no supervisado.

Cada ejemplo constará de una serie de características (features) que serán las propiedades que definan el ejemplo, y un resultado (label) que será lo que intentemos predecir con el modelo generado por un algoritmo de aprendizaje supervisado. A partir de esa metainformación podremos crear un Descriptor para convertir nuestros datos de ejemplo en un formato manejable por los algoritmos genéricos.

Para representar los datos de entrada, que en nuestro caso es la información de Princesas Disney, usaremos la siguiente clase:

public class Princess
{
  public string Name { get; set; }
  public string Country { get; set; }
  public int Age { get; set; }
  public HairColor HairColor { get; set; }
  public bool Married { get; set; }
  public bool FatherAlive { get; set; }
  public bool MotherAlive { get; set; }
}

En ella incluimos datos como el nombre de la princesa, su país de procedencia, edad, color de pelo, si está casada, si su padre está vivo y si su madre está viva. Aunque podríamos decorar con atributos las propiedades para indicar qué es una feature y qué es un label, en este caso vamos a hacerlo de forma externa a la clase para poder analizar distintas facetas:

var marriedDescriptor = Descriptor.For<Princess>()
  .With(x => x.Age)
  .WithString(property: x => x.Country, asEnum: true, splitType: StringSplitType.Word)
  .With(x => x.FatherAlive)
  .With(x => x.MotherAlive)
  .With(x => x.HairColor)
  .Learn(x => x.Married);

Este Descriptor está estableciendo como datos de entrada las propiedades de la princesa (excepto el nombre) y como valor de salida si está casada o no. Es decir, pretendemos conseguir una función que nos ayude a determinar si una princesa se casará o no en función de si su color de pelo o de si sus padres están vivos o muertos. En el caso de Country, que es un poco más extraño, en realidad lo único que estamos diciendo es que trate los valores como si fuese un tipo enumerado aunque sean strings.

Ahora que tenemos el Descriptor vamos a construir un Generator que nos permita obtener el modelo con el que predecir si una princesa se casará o no. Para ello vamos a utilizar uno de los sistemas más sencillos: un árbol de decisión.

Simplificando mucho, en un árbol de decisión cada nodo interno discrimina sobre una característica y tiene tantos hijos como posibles valores pueda tomar esa característica. En las hojas se almacena el resultado final (label) asociado a una entidad cuyas propiedades se correspondiesen a haber recorrido el camino desde la raíz hasta ella. Si habéis jugado alguna vez al juego de las 20 preguntas para adivinar un personaje famoso, es la misma idea.

Sabiendo esto, vamos a generar un modelo a partir de un árbol de decisión:

var generator = new DecisionTreeGenerator(marriedDescriptor);
// Queremos aprender a detectar cuando el valor de Married será true
generator.SetHint(true);


// Lanzamos el proceso de aprendizaje (generación del árbol) con los 
// datos de todas las princesas conocidas hasta ahora
var model = Learner.Learn(PRINCESSES, 0.8m, 1000, generator);

Console.WriteLine(model);

Al pintar el árbol en consola, veremos algo así:

Model:
     [Country, 0,7342]
      |- ALEMANIA
      |       +(True, 1)
      |- FRANCIA
      |       +(True, 1)
      |- ATLÁNTIDA
      |       +(True, 1)
      |- CHINA
      |       +(True, 1)
      |- MALDONIA
      |       +(True, 1)
      |- ESCOCIA
      |       +(False, -1)
      |- NORUEGA
      |      [Age, 1,0000]
      |       |- 18 = x < 19,5
      |       |       +(True, 1)
      |       |- 19,5 = x < 21,01
      |       |       +(False, -1)
      
  Accuracy: 100,00 %

Interesante. Para que una Princesa Disney consiga casarse o no, influye más el país de origen que el color de pelo o que su madre (y futura suegra del esposo) esté viva o muerta.

Podemos utilizar este modelo para predecir si una princesa se casará o no:

var celia = new Princess 
{
  Name = "Celia",
  Age = 16,
  Country = "Noruega",
  FatherAlive = true,
  MotherAlive = true,
  HairColor = HairColor.Blonde,
}

var willGetMarried = model.Model.Predict(celia).Married;

Console.WriteLine("Celia se casará: {0}", willGetMarried);

El resultado de la predicción es que sí, afortunadamente Celia encontrará su principe azul. Tiene sentido, si tenemos en cuenta que según nuestro árbol de decisión generado previamente las princesas noruegas de menos de 19.5 años se casan.

No voy a alargar mucho el post con más ejemplos, pero podéis ver otros apasionantes análisis (ejem) sobre las Princesas Disney y las muertes de sus progenitores en este gist.

No hay magia

Obviando lo absurdo que es el ejemplo, es fundamental ser consciente de que esto del machine learning no tiene nada de magia. Es decir, vamos a construir un modelo a partir de unos datos de entrada y aunque parezca que ese modelo se construye a partir de algoritmos sofisticados muy inteligentes, en realidad nuestro análisis inicial va a condicionar la utilidad de los resultados que podamos obtener.

Cuando decidimos qué features queremos tener en cuenta estamos imponiendo ya una serie de ejes sobre los que tomar las decisiones, por lo que si los features no son representativos, los resultados tampoco lo serán.

Una vez que obtenemos el modelo, en el caso de ejemplo el árbol de decisión, debemos analizarlo con cuidado porque entramos en un terreno farragoso: ¿Es el modelo resultado de la casualidad? ¿Hay causalidad real? ¿Hay al menos correlación entre características y resultado? Podemos minimizar el peso la casualidad si tenemos un volumen suficientemente grande de datos, pero decidir si estamos ante una relación de causalidad o correlación es más complicado.

Conclusiones

El machine learning o aprendizaje automático es una disciplina muy interesante ahora que la potencia de cálculo es más accesible y tenemos grandes volúmenes de datos a nuestra disposición para alimentar los algoritmos.

Aunque la base matemática subyacente tiene cierta complejidad, con librerías como numl podemos empezar a jugar de una manera fácil con estos conceptos y, quién sabe, tal vez encuentres patrones interesantes en los datos que manejas en tu día a día que te ayuden a tomar decisiones.


10 comentarios en “Machine Learning con Princesas Disney

  1. El artículo es muy interesante aunque hubo un momento en el que he perdido donde esta el learning, de donde procesa la información, es aleatorio o de la nube o del árbol de decisiones, se pondera algo?
    Learner.Learn(PRINCESSES, 0.8m, 1000, generator);

  2. Hola Juan Pablo,

    La información que se procesa es la correspondiente a los datos de las princesas, que puedes ver en el código de ejemplo (https://gist.github.com/jmhdez/bbccc516d1ba4c53e457).

    Todo el proceso se hace en local, a través de la librería numl, que emplea un algoritmo de generación de árboles de decisión (tienes más info sobre este tipo de algoritmos aquí: http://en.wikipedia.org/wiki/Decision_tree_learning).

    La “gracia” de todo esto, es que la decisión de qué factores pesan más a la hora de generar el árbol se realiza automáticamente. Es el sistema el que “aprende” (nótense las comillas) qué es lo importante para clasificar princesas.

    Un saludo,

    Juanma.

  3. Muchas gracias, la verdad que es bastante interesante, lo que ahora mismo no se me ocurre así fácil donde podría aplicarlo en no se una app por ejemplo, para algún tipo de ayuda en la vida diaria, porque potencial tiene la verdad.

  4. Pingback: [#VS2015] #MachineLearning y Visual Studio? 3 opciones muy buenas para comenzar | El Bruno

  5. Pingback: [#VS2015] #MachineLearning and Visual Studio? 3 platforms for a quick start | El Bruno

  6. Hola Juanma,

    Qué tema más interesante!! Me picó la curiosidad con tu artículo y tengo ganas de probar numl con alguna idea que se me ha ocurrido. Ya te contaré si llega a buen puerto!

    Desde luego parece que vamos a tener Machine Learning en breve hasta en la sopa… buceando por los posts de El Bruno se encuentran también cositas muy interesantes al respecto, como Azure ML (entre tantas otras).

    Para mi se acaba de abrir otra puerta más. A ver si no me pierdo mucho… jejejee…

    Un saludo!

  7. Hola Antonio,

    Pues sí, es un tema muy entretenido. Yo empecé a jugar por curiosidad con numl y he acabado apuntándome al curso de Coursera de Machine Learning :-)

    Además, entran muchas ganas de jugar con datos reales de la empresa, aunque sólo sea por ver si sale algo curioso.

    Un saludo.

  8. Hola Juanma,

    Efectivamente lo primero que se te ocurre es “enchufar” datos de la empresa a ver qué pasa. También he visto el curso de Coursera, pero de momento tengo que dejar que la camisa me llegue al cuello… no me da la vida para tanto a día de hoy!!

    Ya me contarás, porque tiene muy buena pinta!

    Un saludete.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>