BigQuery ML: machine learning desde BigQuery

Hace unos meses Google anunció una nueva funcionalidad de Google BigQuery llamada BigQuery ML, la cual está actualmente en Beta. Consiste en un conjunto de extensiones del lenguaje SQL que permiten crear modelos de aprendizaje automático (machine learning, en inglés), evaluar su capacidad predictiva y hacer predicciones para nuevos datos directamente desde dentro de BigQuery.

Una de las ventajas de BigQuery ML es que para usarlo solo se necesita saber standard SQL, sin necesidad de herramientas especializadas como R o Python para entrenar modelos, por lo que hace más accesible el aprendizaje automático. Incluso se encarga por defecto de la transformación de los datos, de dividir tus datos en conjuntos de entrenamiento y de test, etc. Además, al usarse directamente en BigQuery, que es dónde están almacenados los datos, no se necesita exportar los datos a otras herramientas, lo que permite reducir el tiempo de entrenamiento de los modelos. Por ejemplo, gracias a la vinculación con Analytics 360, podemos usar BigQuery ML para predecir si un usuario comprará o no en base a su actividad en la web.

Pero no todo son ventajas. En primer lugar, los modelos que se pueden implementar son limitados (aunque veremos que nos ofrece cierta flexibilidad), cosa que seguramente siempre sea así por el hecho de adaptarse a SQL. En segundo lugar (y para mí más importante), aunque BigQuery ML facilite la creación de un modelo, una persona que no está familiarizada con los conceptos de machine learning puede seguir teniendo dificultades a la hora de interpretar el modelo que ha creado, evaluar su rendimiento e incluso intentar mejorarlo.

En este post, voy a explicar las principales funciones de BigQuery ML y cómo usarlas para crear nuestro modelo, evaluarlo y usarlo para hacer predicciones. Este proceso consistirá en los siguientes pasos:

  1. Crear dataset (opcional)
  2. Crear modelo
  3. Información del modelo (opcional)
  4. Evaluar modelo
  5. Predecir

Crear dataset (opcional)

Al igual que con las tablas de BigQuery (BQ), el modelo se tiene que guardar en algún “dataset”, por lo que el paso previo a crear el modelo será decidir en qué dataset guardarlo, ya sea en uno ya existente o en uno nuevo que crearemos.

Si tu caso es el segundo, crear un nuevo dataset es tan sencillo como:

  1. En la interfaz de BQ, seleccionar el proyecto en el que queremos crear el dataset y hacer clic en el botón de crear dataset.

2. Poner un nombre al nuevo dataset, una localización donde se almacenarán los datos y la expiración. Puedes encontrar más información sobre estos campos en el siguiente enlace

Crear modelo

En aprendizaje automático (supervisado), se usa un conjunto de datos de entrenamiento (training data) cuyas variables respuesta se conocen para generar un modelo que capture los patrones subyacentes, de manera que pueda generar predicciones sobre datos nuevos para los que no se conoce la respuesta.

BigQuery ML permite hacer este proceso directamente dentro de BigQuery. Actualmente, permite crear tres tipos de modelos:

  • Regresión lineal. Se usa para predecir el resultado de una variable numérica continua, como el número de sesiones o los ingresos de nuestra web de un día.
  • Regresión logística multinomial (o multiclase). Se usa para predecir el resultado de una variable categórica con más de dos clases.
  • Regresión logística binaria. Se usa para predecir el resultado de una variable categórica con dos clases posibles, como por ejemplo cuando se quiere determinar si un usuario comprará o no comprará.

Para crear (y entrenar) un modelo con BigQuery ML, se tiene que usar la siguiente sintaxis:

#standardSQL
{CREATE MODEL | CREATE MODEL IF NOT EXISTS | CREATE OR REPLACE MODEL}
project.dataset.model_name
OPTIONS(model_option_list)
AS query_statement

Esta consulta creará un modelo (CREATE MODEL) con las opciones especificadas (OPTIONS) y usando como datos de entrenamiento el resultado de una consulta (AS). Tenemos que especificar:

  • El nombre del modelo y dónde se tiene que guardar. CREATE MODEL crea y entrena el modelo (que guardará con el nombre «model_name» dentro del dataset especificado) siempre y cuando no exista un modelo ya creado con el mismo nombre. Si el nombre del modelo existe, la consulta con CREATE MODEL devolverá un error. Para evitar este error, podemos usar dos alternativas:

     

      • CREATE MODEL IF NOT EXISTS, que crea y entrena el modelo únicamente si no existe un modelo ya creado con el mismo nombre.
    • CREATE OR REPLACE MODEL, que crea el modelo (si no existe) o lo reemplaza (si existe) y lo entrena.
  • model_option_list. Listado en el que podemos especificar algunas opciones relacionadas con el modelo y el proceso de entrenamiento. El formato es el siguiente: opcion1=valor1, opcion2=valor2, … Las dos opciones más importantes son:

     

      • model_type (obligatorio): especifica el tipo de modelo que queremos entrenar: linear_reg para regresión lineal o logistic_reg para regresión logística binaria o multiclase.
    • input_label_cols: especifica el nombre de la columna de la tabla con los datos de entrenamiento que contiene la variable respuesta. Si la columna se llama label, este campo es opcional; sino hay que especificarlo con el formato siguiente: [‘nombre_columna’].

Aunque por defecto BigQuery ML tiene unas opciones determinadas para entrenar el modelo, también ofrece cierta flexibilidad para definir aspectos relacionados con evitar el sobreajuste (overfitting) y con el proceso de optimización de los parámetros del modelo. Por ejemplo, podemos aplicar regularización L1 o L2, separar los datos en un training set y un validation set, o fijar el número máximo de iteraciones del gradient descent. Puedes encontrar todas las opciones configurables en el siguiente enlace.

  • query_statement. Consulta que genera la tabla de datos que se usará como training data. Una de las ventajas de BigQuery ML es que se encarga de la transformación de los datos para el entrenamiento del modelo. En particular, lo hace de la siguiente manera:

     

      • Las variables categóricas (de tipo BOOL, STRING, BYTES, DATE, DATETIME o TIME) se convierten en una variable binaria por cada clase. Esto no es recomendable si, además de querer usar el modelo para hacer predicciones, se quieren sacar conclusiones sobre las relaciones entre las variables explicativas y la respuesta. Este problema se conoce como multicolinealidad.
      • Las variables numéricas (tipo NUMERIC, FLOAT64 o INT64) se estandarizan tanto para el entrenamiento como en posteriores predicciones.
    • Los valores NULL se sustituyen por la media en el caso de variables numéricas o por una nueva clase que agrupa todos estos datos faltantes en el caso de variables categóricas.

Respecto a la variable respuesta, hay que tener en cuenta que:

  • En regresión lineal no puede tener valores infinito o NaN.
  • En regresión logística binaria tiene que tener exactamente dos posibles valores.
  • En regresión logística multiclase puede tener un máximo de 50 categorías distintas.

Por ejemplo, imaginemos que queremos crear un modelo que intente predecir si una sesión terminará comprando o no en función de una serie de variables explicativas relacionadas con la navegación del usuario (páginas vistas, duración de la sesión, tipo de usuario, el dispositivo que usa y si es tráfico de pago o no). Por si queréis seguir este ejemplo, usaremos el conjunto de datos de prueba de Google Analytics que ofrece BigQuery.

Para crear el modelo, tendríamos que usar la siguiente consulta:

#standardSQL
CREATE MODEL `project.dataset.sample_model`
OPTIONS(model_type='logistic_reg',
input_label_cols=['isBuyer'])
AS
SELECT
IF(totals.transactions IS NULL, 0, 1) AS isBuyer,
IFNULL(totals.pageviews, 0) AS pageviews,
IFNULL(totals.timeOnSite, 0) AS timeOnSite,
IFNULL(totals.newVisits, 0) AS isNewVisit,
IF(device.deviceCategory = 'mobile', 1, 0) AS isMobile,
IF(device.deviceCategory = 'desktop', 1, 0) AS isDesktop,
IF(trafficSource.medium in ('affiliate', 'cpc', 'cpm'), 1, 0) AS isPaidTraffic
FROM
`bigquery-public-data.google_analytics_sample.ga_sessions_*`
WHERE
_TABLE_SUFFIX BETWEEN '20160801' AND '20170630'

Como nuestra variable respuesta es categórica con dos clases (1=»con compra» o 0=»sin compra»), en las opciones hemos tenido que especificar que el tipo de modelo es una regresión logística (logistic_reg). Además, en la query que genera los datos la variable respuesta se llama «isBuyer», por lo que también tenemos que especificarlo en las opciones.  

Información del modelo (opcional)

En los modelos lineales, cada variable explicativa tiene un coeficiente (o peso) asociado que determina la relación entre esta variable y la variable respuesta. Cuanto mayor es su magnitud, mayor impacto tiene sobre la variable respuesta. Además, el signo positivo (negativo) nos indica si la respuesta aumenta (disminuye) cuando aumenta el valor de esta variable explicativa (o, en el caso de variables categóricas, la categoría está presente).

En BigQuery ML, podemos consultar estos coeficientes del modelo resultante de la siguiente forma:

#standardSQL
SELECT *
FROM ML.WEIGHTS(MODEL `project.dataset.model_name`)

Lo que nos devuelve el peso que tiene cada variable explicativa. Como se ha comentado antes, si en lugar de haber convertido las variables categóricas en numéricas “manualmente” en la consulta como hemos hecho nosotros (por ejemplo, con isMobile) se hubiera introducido una variable categórica directamente en el modelo, no se podrían sacar conclusiones fiables de los pesos ya que todas las categorías posibles tendrían un peso.

Por ejemplo, nuestro modelo creado en el apartado anterior tiene los siguientes coeficientes:

Es decir, ser una sesión de un usuario nuevo, usar un dispositivo móvil o acceder a la web mediante un canal de pago disminuye la probabilidad de que esa visita termine en compra. Mientras que usar desktop o pasar más tiempo en el site aumentan la probabilidad de convertir.

Evaluar modelo

Una vez tenemos el modelo entrenado, necesitamos evaluar su comportamiento a la hora de hacer predicciones. Esto siempre se tiene que hacer sobre un conjunto de datos (llamado “conjunto de test”, o “test set” en inglés) diferente del que se ha usado para la creación/entrenamiento del modelo para evitar lo que se conoce como “sobreajuste” (overfitting, en inglés), que se produce cuando nuestro modelo “memoriza” las características de nuestros datos de entrenamiento, lo que resulta en que sea muy preciso en ese conjunto pero no es capaz de hacer buenas predicciones en nuevos datos (conjunto de test), que es el objetivo último del aprendizaje automático.

Para ello, BigQuery ML nos proporciona varias funciones:

    • ML.TRAINING_INFO. Esta función nos da información sobre las distintas iteraciones durante el entrenamiento del modelo, incluyendo la pérdida (loss) en el conjunto de entrenamiento y en el de validación en cada iteración. El resultado esperado es que la pérdida tanto en el conjunto de entrenamiento como en el de validación vaya disminuyendo (idealmente, hasta 0, cosa que significaría que el modelo acierta siempre).
    • ML.EVALUATE. Proporciona las métricas más comunes para evaluar las predicciones de un modelo. Se puede usar para cualquier tipo de modelo (regresión lineal, regresión logística, regresión logística multiclase), aunque serán diferentes dependiendo de si se trata de un problema de regresión o de clasificación.
    • ML.CONFUSION_MATRIX. Devuelve la matriz de confusión del conjunto de datos proporcionado, que nos permite saber los aciertos y errores para cada clase posible en un modelo de clasificación. Solo se puede usar para los modelos de clasificación, es decir, regresión logística y regresión logística multiclase.
  • ML.ROC_CURVE. Nos permite construir la curva ROC , que es una visualización gráfica que nos permite evaluar la capacidad predictiva de un modelo de clasificación binario. En este caso, solo se puede usar para un tipo de modelo en BigQuery ML: la regresión logística (binaria, no multiclase).

En este post nos centraremos en ML.EVALUATE, aunque dejaremos los ejemplos de sintaxis del resto de funciones por si alguien está interesado/a en usarlas.

ML.EVALUATE

Para evaluar un modelo previamente creado, se tiene que usar la siguiente sintaxis:

#standardSQL
SELECT *
FROM ML.EVALUATE(MODEL `project.dataset.model_name`,
{TABLE table_name | (query_statement)}
[, STRUCT(XX AS threshold)])

Donde tenemos que especificar:

  • El modelo.
  • La tabla para la que queremos calcular las métricas de evaluación del modelo este conjunto de datos, que puede ser el resultado de una query. Obviamente, la tabla tiene que tener las mismas columnas que la tabla con la que se ha entrenado el modelo, incluida la variable respuesta (para poder compararla con las predicciones de nuestro modelo). Si no se especifica ninguna tabla o query que la genere, se usa el conjunto de datos de validación (si se han especificado al crear el modelo) o todo el conjunto de datos de entrenamiento (si no se ha especificado conjunto de validación).
  • En el caso de una regresión logística, un umbral (threshold). Este valor es opcional, y especifica el valor a partir del cual las predicciones de nuestro modelo (que son valores entre 0 y 1 que se pueden interpretar como probabilidades de que esa observación sea de la clase 1) serán para la clase 0 o para la clase 1. Por defecto, el umbral será 0,5.

El resultado de esta consulta es una única fila con las métricas más comunes para evaluar las predicciones de un modelo, que dependerán del tipo de modelo usado. En particular, las métricas que proporciona BigQuery ML para modelos de regresión logística y regresión logística multiclase son:

    • precision
    • recall
    •  accuracy
    • f1_score
    • log_loss
  • roc_auc

En cambio, en el caso de regresiones lineales tendremos:

  • mean_absolute_error
  • mean_squared_error
  • mean_squared_log_error
  • median_absolute_error
  • r2_score
  • explained_variance

Para más detalles sobre la mayoría de estas métricas y cuándo usar cada una de ellas, os recomiendo este post para las de clasificación y éste para las de regresión.

Por ejemplo, para una regresión logística como la de nuestro ejemplo, tendríamos que usar:

#standardSQL
SELECT *
FROM ML.EVALUATE(MODEL `project.dataset.sample_model`,
(
SELECT
IF(totals.transactions IS NULL, 0, 1) AS isBuyer,
IFNULL(totals.pageviews, 0) AS pageviews,
IFNULL(totals.timeOnSite, 0) AS timeOnSite,
IFNULL(totals.newVisits, 0) AS isNewVisit,
IF(device.deviceCategory = 'mobile', 1, 0) AS isMobile,
IF(device.deviceCategory = 'desktop', 1, 0) AS isDesktop,
IF(trafficSource.medium in ('affiliate', 'cpc', 'cpm'), 1, 0) AS isPaidTraffic
FROM
`bigquery-public-data.google_analytics_sample.ga_sessions_*`
WHERE
_TABLE_SUFFIX BETWEEN '20170701' AND '20170801'
),
STRUCT(0.5 AS threshold)
)

Notemos que las fechas usadas para generar los datos son distintos a las que usamos para crear el modelo. El resutado de la anterior query es:

Otras funciones para evaluar modelos

1. ML.TRAINING_INFO

Sintaxis:

#standardSQL
SELECT *
FROM ML.TRAINING_INFO(MODEL `project.dataset.model_name`)

Ejemplo:

#standardSQL
SELECT *
FROM ML.TRAINING_INFO(MODEL `project.dataset.sample_model`)

2. ML.CONFUSION_MATRIX

Sintaxis:

#standardSQL
ML.CONFUSION_MATRIX(MODEL `project.dataset.model_name`,
{TABLE table_name | (query_statement)}
[, STRUCT(XX AS threshold)])

Ejemplo:

#standardSQL
SELECT *
FROM ML.CONFUSION_MATRIX(MODEL `project.dataset.sample_model`,
(
SELECT
IF(totals.transactions IS NULL, 0, 1) AS isBuyer,
IFNULL(totals.pageviews, 0) AS pageviews,
IFNULL(totals.timeOnSite, 0) AS timeOnSite,
IFNULL(totals.newVisits, 0) AS isNewVisit,
IF(device.deviceCategory = 'mobile', 1, 0) AS isMobile,
IF(device.deviceCategory = 'desktop', 1, 0) AS isDesktop,
IF(trafficSource.medium in ('affiliate', 'cpc', 'cpm'), 1, 0) AS isPaidTraffic
FROM
`bigquery-public-data.google_analytics_sample.ga_sessions_*`
WHERE
_TABLE_SUFFIX BETWEEN '20170701' AND '20170801'
),
STRUCT(0.5 AS threshold)
)

3. ML.ROC_CURVE

Sintaxis:

#standardSQL
ML.ROC_CURVE(MODEL `project.dataset.model_name`,
{TABLE table_name | (query_statement)},
[GENERATE_ARRAY(thresholds)])

Ejemplo:

#standardSQL
SELECT *
FROM ML.ROC_CURVE(MODEL `project.dataset.sample_model`,
(
SELECT
IF(totals.transactions IS NULL, 0, 1) AS isBuyer,
IFNULL(totals.pageviews, 0) AS pageviews,
IFNULL(totals.timeOnSite, 0) AS timeOnSite,
IFNULL(totals.newVisits, 0) AS isNewVisit,
IF(device.deviceCategory = 'mobile', 1, 0) AS isMobile,
IF(device.deviceCategory = 'desktop', 1, 0) AS isDesktop,
IF(trafficSource.medium in ('affiliate', 'cpc', 'cpm'), 1, 0) AS isPaidTraffic
FROM
`bigquery-public-data.google_analytics_sample.ga_sessions_*`
WHERE
_TABLE_SUFFIX BETWEEN '20170701' AND '20170801'
),
GENERATE_ARRAY(0.0, 1.0, 0.01)
)

Predicciones

Para usar un modelo creado con BigQuery ML para hacer predicciones, se tiene que usar la siguiente sintaxis:

#standardSQL
ML.PREDICT(MODEL model_name,
{TABLE table_name | (query_statement)}
[, STRUCT(XX AS threshold)])

Esta consulta usará un modelo (MODEL) y hará predicciones de un nuevo conjunto de datos (TABLE). Obviamente, la tabla tiene que tener las mismas columnas que la tabla con la que se ha entrenado el modelo, aunque no es necesario incluir la variable respuesta (ya que no la necesitamos para hacer predicciones de nuevos datos). En el caso de regresión logística, opcionalmente se puede especificar un threshold que defina a partir de qué probabilidad estimada se considera como predicción final una clase u otra.

El resultado de esta consulta tendrá tantas filas como la tabla de datos que le hayamos proporcionado e incluirá tanto la tabla de input como las predicciones del modelo. En el caso de modelos de regresión logística (binaria o multiclase), además de la clase que predice el modelo, también se proporciona la probabilidad estimada de cada una de las clases posibles.

Y siguiendo con nuestro ejemplo:

#standardSQL
SELECT *
FROM ML.PREDICT(MODEL `project.dataset.sample_model`,
(
SELECT
IFNULL(totals.pageviews, 0) AS pageviews,
IFNULL(totals.timeOnSite, 0) AS timeOnSite,
IFNULL(totals.newVisits, 0) AS isNewVisit,
IF(device.deviceCategory = 'mobile', 1, 0) AS isMobile,
IF(device.deviceCategory = 'desktop', 1, 0) AS isDesktop,
IF(trafficSource.medium in ('affiliate', 'cpc', 'cpm'), 1, 0) AS isPaidTraffic
FROM
`bigquery-public-data.google_analytics_sample.ga_sessions_*`
WHERE
_TABLE_SUFFIX BETWEEN '20170701' AND '20170801'
)
)

Notemos que no hace falta la columna con la respuesta (isBuyer). El resultado de la anterior query es:

La primera columna devuelve la clase que nuestro modelo predice para cada nuevo dato. La segunda y la tercera columna nos dan la probabilidad estimada para cada una de las clases (la que sea mayor es la que ha devuelto como predicción en la primera columna). El resto de columnas corresponden a los datos cuyas predicciones hemos pedido.

Y hasta aquí las funciones básicas para entrenar un modelo de machine learning desde BigQuery y usarlo para hacer predicciones de nuevos datos, ahora es vuestro turno de aplicarlo a vuestro negocio. Y, si queréis, podéis compartir vuestra experiencia o dudas sobre el post en los comentarios.

Hasta la próxima! 🙂

Pol Ferrando

Pol Ferrando

Share on facebook
Share on twitter
Share on linkedin
Share on email
9 min
Suscríbete a nuestra newsletter

Los mejores artículos de analítica digital para potenciar tu negocio.

Dejar un comentario

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

Entradas relacionadas

Jupyter Notebook

Jupyter Notebook es una aplicación web de código abierto que permite incluir texto, vídeo, audio e imágenes.

4 minutos

Dificultad

¡Hola TensorFlow!

TensorFlow es una de las herramientas más potentes qué conocemos enfocadas al machine learning.

3 minutos

Dificultad

Cómo integrar KNIME con R

Integrar KNIME con R nos permite construir flujos de análisis de datos fácilmente comprensibles.

2 minutos

Dificultad