Scikit-learn versión 0.20, más madera para tus PipeLines

Scikit-learn versión 0 20 más madera para tus PipeLines

La librería scikit-learn de Python sigue siendo una de las favoritas de los Kagglers (aunque Keras y Tensorflow ganan cada vez más adeptos). Igualmente, para todo el que desea iniciarse en Machine Learning utilizando Python como lenguaje de cabecera, la caja de herramientas que conforman numpy, pandas, matplotlib y scikit-learn se presenta como una manera razonablemente amigable de hacer los primeros pinitos.

Por ello, el hecho de que scikit-learn (biblioteca que encapsula distintas funciones de preprocesamiento de datos así como implementaciones de multitud de modelos orientados a resolver problemas tanto de aprendizaje supervisado como aprendizaje no supervisado) haya alcanzado la versión 0.20, es motivo de celebración. Qué mejor manera que celebrarlo con un pequeño post con algunas de las novedades que esta versión incorpora.

Empezando con la nueva versión de scikit-learn

Lo primero de todo es actualizar nuestra versión de scikit-learn para empezar a trastear con ella. Se recomienda utilizar algún entorno experimental (si tenéis instalado Anaconda podéis crearos uno con conda create y si no, pues con virtualenv  env). Aquí, por ejemplo, utilizamos Anaconda y lo que haremos será simplemente listar nuestros entornos y activar aquel en el cual queremos actualizar la versión de scikit-learn.

Scikit-learn versión 0.20, más madera para tus PipeLines

Una de las primeras novedades que nos llamó la atención es la que afecta a la imputación o procedimiento. Mediante esta, se rellenaban aquellos huecos en el conjunto de datos propiciados por los valores missing (nulos, NA, NaN…como se prefiera llamar). La herramienta que scikit-learn proporcionaba para solventar esta tarea era principalmente el Imputer, si bien es cierto que presentaba algunas carencias. Por ejemplo: solo podía reemplazar valores missing o enteros o no permitía imputar un valor constante. Ahora SimpleImputer pone remedio a ambas carencias. Veamos un ejemplo:

Scikit-learn versión 0.20, más madera para tus PipeLines

Dataframes y features categóricas

Se define un dataframe de pandas con columnas de distintos tipos, en la columna disponibilidad, el último de los valores es u. Consideremos u el valor que queremos reemplazar y constant la estrategia a utilizar. Al aplicar el SimpleImputer definido sobre nuestro dataframe, vemos como el valor u ha sido reemplazado por la constante definida mediante fill_value: d.

Existen casos como el de OrdinalEncoder, en el que nuevas funcionalidades han sido añadidas un componente ya existente. Recordemos que este componente transforma las features con valores categóricos, asignando a cada uno de sus posibles valores un número entre 0 y el número de categorías – 1.

Veamos un ejemplo centrado únicamente en dos features categóricas:

Scikit-learn versión 0.20, más madera para tus PipeLines

Se define de nuevo un dataframe con las dos features categóricas que va a gestionar el OrdinalEncoder. Luego, este se entrena con este dataframe aprendiendo los posibles valores que pueden tomar dichas features y transformándolos en números (del tipo indicado mediante el parámetro dtype) en el rango de 0 a número de categorías – 1. Al examinar las categorías que ha detectado el OrdinalEncoder, apreciamos que lo que ha hecho es ordenarlas alfabéticamente y asignar un número empezando por 0 a cada una de ellas para cada una de las dos features. Pero ¿qué ocurre si aplicamos el OrdinalEncoder entrenado a nuevos datos?

Usando el OrdinalEncoder para entrenar nuevos datos

Scikit-learn versión 0.20, más madera para tus PipeLines

Si fichamos un manager para nuestro equipo, OrdinalEncoder será incapaz de hacer la transformación del nuevo dataframe. La razón de esto es que ha recibido una categoría (manager) con la cual no ha sido entrenado… Aquí es cuando viene al rescate el parámetro categories. Repitamos el ejemplo:

Scikit-learn versión 0.20, más madera para tus PipeLines

La gran diferencia es que, al definir el OrdinalEncoder, hemos indicado, mediante el parámetro categories, todos los posibles valores de nuestras features categóricas. Si no especificamos ningún valor para dicho parámetro, su valor por defecto será auto. Esto básicamente indica que los posibles valores de las features categóricas se inferirán de los datos con los que se entrene. Nota: en la versión 0.20.0 el uso del parámetro categories con otro valor que no sea el por defecto, dará un error. En la versión 0.20.1 está subsanado.

Otras novedades de interés

ColumnTransformer

Finalmente, mencionaremos una de las novedades que más nos ha gustado. Scikit-Learn ya ofrecía una amplia cantidad de transformers que permiten llevar a cabo distintas operaciones sobre nuestros datos. El problema es que, en el mundo real, es sencillo encontrarse datos en los que las distintas features son de diversos tipos, esto implica que los requisitos de preprocesamiento no serán los mismos para todas ellas. Es necesario, por tanto, aplicar transformaciones de manera focalizada según el tipo de cada feature. ColumnTransformer (aun en versión experimental) nos permite seleccionar a qué columna o columnas les será aplicada cada transformación. Veamos un ejemplo:

Scikit-learn versión 0.20, más madera para tus PipeLines

Definimos primeramente un dataframe nuevo. A diferencia de los ejemplos anteriores, en los que cada transformer se aplicaba a todas las columnas de cada dataframe, en esta ocasión definimos un ColumnTransformer que nos permite montar un pipeline. En este, indicaremos las transformaciones que se desean aplicar y a qué columnas deseamos aplicarlas. El primer parámetro es una lista de tuplas en la que cada tupla indica:

  • el nombre que nosotros le damos a la transformación (a nuestro gusto),
  • la definición del transformer
  • una lista con los índices de las columnas a las que afectará.

Una vez hayamos definido la lista de tuplas, especificaremos, mediante el parámetro remainder, lo que queremos que les pase a las columnas que no han sido afectadas por ninguna transformación: passthrough (si queremos que pasen al final del pipeline intactas), drop (si queremos que se eliminen del resultado).

Es interesante recalcar, aún más, que el funcionamiento del ColumnTransformer es como el de un pipeline. Por tanto podremos acceder a los “eslabones” de la estructura que hayamos especificado a través de las tuplas, mediante los nombres que hayamos utilizado para denominar cada una. Por ejemplo en el caso anterior:

Scikit-learn versión 0.20, más madera para tus PipeLines

Named_transformer_

La propiedad named_transformer_ devuelve un diccionario en el que cada clave corresponde con los nombres utilizados para definir los transformer (el primer elemento de cada tupla). Al acceder al diccionario utilizando uno de estos nombres estaremos accediendo a su vez a cada uno de los transformer definidos.

Incluso es posible construir un ColumnTransformer sin necesidad de especificar un nombre para cada transformación. Por ejemplo:

Scikit-learn versión 0.20, más madera para tus PipeLines

Esta vez, no hemos especificado nombre alguno para los transformadores definidos, scikit-learn los ha nombrado por nosotros y podremos acceder a ellos a través de los nombres generados.

 

Esperemos que algunas de estas novedades introducidas en scikit-learn, os resulten tan interesantes como a nosotros; seguro que en un futuro cercano os facilitarán el trabajo. De todos modos, id con cuidado ya que algunas partes todavía son experimentales.


Alejandro Arranz, Data Engineer en datahack

Deja un comentario

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