Analítica web con R: estadísticas descriptivas y predictivas

En la primera parte del post vimos cómo realizar una exploración de los datos integrando como dataset la herramienta de analítica digital más utilizada, Google Analytics con la tool más utilizada por los estadísticos y analistas de datos, R Studio.

En esta segunda parte, nos centraremos en la estadística descriptiva y aplicaremos modelos predictivos para poder contrastar las informaciones recogidas desde nuestra herramienta de analítica y comprobar si nuestras decisiones van por un buen camino o, por lo contrario, estamos lejos y así reaccionar a tiempo.

Importante: os recomiendo leer la primera parte de este post, donde hablamos de la instalaciones de paquetes, librerías y dependencias.

La API que utilizaremos será validada por Token. Os recuerdo que hay una ligera actualización de la API principal y de su función google_analytics().  

Desde la última actualización de la librería de googleAnalyticsR a la versión 0.6.0 de Mark Edmonson, el mismo creador del paquete invita a reportar bugs o problemas directamente al repositorio de GitHub.

Instalación

Comenzaremos con la instalación y/o carga de las librerías utilizadas en este post:

# Instalamos las librerías
library(forecast)
library(reshape2)
library(stats)
library(ggplot2)
library(ggthemes)
library(ggrepel)
library(dplyr)
library(tidyr)

Creamos nuestro dataset con las siguientes métricas: Sesiones, Páginas vistas, Entradas, Rebotes; dimensiones: Fecha, Agrupación de canales, Dispositivos.

# Creamos dataframe con diferentes variables
web_data_metrics <- google_analytics_3(id = ga_id,
              start="2018-01-01",end="2018-06-30",
metrics=c("sessions","pageviews","entrances","bounces"),
dimensions = c("date","channelGrouping","deviceCategory"),
max = 5000,
samplingLevel = 'WALK')

En el ejemplo que os muestro a continuación, he puesto un filtro de muestreo que reúne solo un 55% de los datos recogidos. Aunque mi intención erae mostrar más de 5000 resultados, GA solo me proporciona unos 2700.

Pivotando tendríamos una tabla como resultado de esta manera:

## Aplicamos un filtro a nuestro dataframe solo para Desktop, teniendo en cuenta Fecha, Sesiones y Canales
pivoted <- web_data_metrics %>% 
  filter(deviceCategory == "desktop") %>% 
  select(date, channelGrouping, sessions) %>%
  spread(channelGrouping, sessions)

## En caso de tener valores NA lo sustituimos con valor cero
pivoted[is.na(pivoted)] <- 0

head(pivoted)

Aplicar modelos de forecasting en la analítica web

Otro aspecto interesante que podemos realizar en R Studio es aplicar modelos, algoritmos de aprendizajes y realizar predicciones. Uno de ellos, por ejemplo, sería el Forecasting y Time Series, teniendo en cuenta una y más variables.

Las series de tiempo son una subclase especial de datos, que se refieren a cuando tenemos observaciones ordenadas en el tiempo.

A menudo, las series de tiempo se encuentran cuando se trata de analítica digital, y R usa una clase especial para tratarlas, ya que tienen algunas propiedades únicas.

Las series de tiempo se crean en R mediante la función ts(), que normalmente se incluirá en algunos datos numéricos que se supone que están en orden de observación.

## Creamos un objeto del tipo time-series
web_data_ts <- ts(pivoted[-1], frequency = 7)

## lo representamos gráficamente
plot(web_data_ts, axes = FALSE)

Observamos la serialidad para cada uno de los canales de marketing. Tenemos, además, otro caso de uso, la estacionalidad.

A través de la función decompose(), podemos extraer, por ejemplo, una variable y estudiar la estacionalidad (por ejemplo, en nuestro ejemplo anterior es semanal).

decomp <- decompose(web_data_ts[, "Organic Search"])
plot(decomp)

Según la gráfica tenemos cuatro subplots:

  • Observed, la serie original.
  • Trend, los datos menos la estacionalidad.
  • Seasonal, los datos con la estacionalidad (nuestro ejemplo semanal).
  • Random, una serialidad temporal de manera aleatoria, muy útil para detectar anomalías.

Pasamos ahora al Forecasting. El pronóstico analiza la tendencia de los datos y hace una predicción sobre dónde evolucionará dicha tendencia. Veamos ejemplos realizados con la librería forecast.

library(forecast)
## prepara el dataset con el solo canal Orgánico
fit <- ets(web_data_ts[, "Organic Search"])
## realizar el forecast
fc <- forecast(fit)
plot(fc)

El otro modelo es HoltWinters, muy bien explicado aquí, permite suavizar la serie de tiempo, además de tener en cuenta los errores del pronóstico. Nos facilita una capacidad de análisis y un pronóstico de datos a corto plazo es de forma muy rápida.

## Manteniendo el dataframe anterior, aplicamos la función HoltWinters
fit2 <- HoltWinters(web_data_ts[, "Organic Search"])

## lo representamos gráficamente
fc2 <- forecast(fit2, h = 25)
plot(fc2)

Para entender mejor la gráfica, los colores más oscuros se refieren a una tendencia más o menos óptima, mientras los colores más claros se refieren a las tendencias al alza o a la baja entre el 80% y 95% de intervalo de confianza.

Realizamos otras predicciones, con duración 26 y 90 días, y así poder observar las diferencias de la confianza.

#Cargamos las librerías y crearemos para ello un nuevo dataset para un periodo de 6 meses.

library(forecast)
library(reshape2)
library(stats)

gadata_5 <- google_analytics_·(id = ga_id, 
                           start="2018-06-01", end="2018-06-30",
                           metrics = "sessions", 
                           dimensions = "date",
                           max = 5000)

# Creamos dos nuevas variables, timeseries y el componente

timeseries <- ts(gadata_5$sessions, frequency=7)
components <- decompose(timeseries)
plot(components)

Aplicamos la función HoltWinters sobre timeseries y lo representaremos gráficamente:

forecastmodel <- HoltWinters(timeseries)
plot(forecastmodel)

En este último gráfico vemos cómo se solapan los datos observados con los calculados por el Forecast.Aplicando este método, podemos realizar una predicción, por ejemplo, de 26 días.

forecast <- forecast:::forecast.HoltWinters(forecastmodel, h=26) # 26 days in future
plot(forecast, xlim=c(0,12))

Probamos con el Forecasting a 90 días:

gadata_6 <- google_analytics(id = ga_id, 
                           start="2019-01-01", end="2019-01-30",
                           metrics = "sessions", 
                           dimensions = "date",
                           max = 5000)


timeseries <- ts(gadata_6$sessions, frequency=7)
components <- decompose(timeseries)
plot(components)

# note the way we add a column to a data.frame
gadata_6$adjusted <- gadata_6$sessions - components$seasonal

theme(axis.text.x = element_text(angle = 90, hjust = 1))

forecastmodel <- HoltWinters(timeseries)
plot(forecastmodel)

forecast <- forecast:::forecast.HoltWinters(forecastmodel, h=30) # 26 days in future
plot(forecast, xlim=c(0,13))

forecastdf <- as.data.frame(forecast)
totalrows <- nrow(gadata_6) + nrow(forecastdf)
forecastdata <- data.frame(day=c(1:totalrows),
actual=c(gadata_6$sessions,rep(NA,nrow(forecastdf))),
forecast=c(rep(NA,nrow(gadata_6)-1),tail(gadata_6$sessions,1),forecastdf$"Point Forecast"),
forecastupper=c(rep(NA,nrow(gadata_6)-1),tail(gadata_6$sessions,1),forecastdf$"Hi 50"),
forecastlower=c(rep(NA,nrow(gadata_6)-1),tail(gadata_6$sessions,1),forecastdf$"Lo 50")
)

ggplot(forecastdata, aes(x=day)) +
geom_line(aes(y=actual),color="black") +
geom_line(aes(y=forecast),color="blue") +
geom_ribbon(aes(ymin=forecastlower,ymax=forecastupper), alpha=0.4, fill="green") +
xlim(c(0,50)) +
xlab("Day") +
ylab("Sessions")

Obviamente, el intervalo de confianza de una serie de tiempo a 90 días es mucho más inestable que el primero. Las series tienen más validez a corto plazo.

Aplicar el modelo Causal Impact

CausalImpact proporciona una estimación del efecto que tuvo un evento en un momento determinado en sus métricas, en términos absolutos y relativos.

En este caso, un evento podría ser una campaña de pago, un evento mediático que inicia o cambia sus etiquetas de título. También permite agregar segmentos de control, para ajustar los efectos conocidos.

Podemos observar cómo hay diferentes picos durante un periodo:

# Primero formateamos los datos
library(xts)

## create a time-series zoo object
web_data_xts <- xts(pivoted[-1], order.by = as.Date(pivoted$date), frequency = 7)

Sucesivamente cargamos la librería CausalImpact y realizamos los cálculos:

# install.packages(CausalImpact)
library(CausalImpact)
library(bupaR)
pre.period <- as.Date(c("2018-03-13","2018-04-14"))
post.period <- as.Date(c("2018-04-15","2018-06-30"))

## Llamamos las variables en orden de aparición por Canal
model_data <- web_data_xts[,c("Direct","Social","Organic Search","Paid Search","Referral")]


impact <- CausalImpact(model_data,  pre.period, post.period)
plot(impact)

Que podemos observar de esta gráfica:

  • Original: los datos originales del data frame y el pronóstico en azul.
  • Pointwise: la diferencia entre los datos reales y pronosticados.
  • Cumulative: los datos post-periodo de manera cumulativa.

Un caso de uso de los más comunes en los departamentos de marketing es cómo observar un evento (campaña de newsletter, captación de tráfico a través de Google Ads, incluso una caída del tráfico SEO en virtud de una penalización).

Podemos marcar este evento en nuestro gráfico y observar la tendencia (alta o baja) respecto a las métricas, nuevos usuarios, sesiones, más páginas vistas, rebote, etc.

Si quieres conocer más sobre esta representación de forecasting, puedes verlo en esta webapp.

Categorización y modelo de árbol de decisión

Veamos en este otro caso cómo clasificar los datos web con diferentes segmentos, ayudando en la definición de las categorías.

En el modelo de árbol de decisión normalmente los datos se leen de arriba a abajo y representan dónde el modelo cree que puede dividir sus datos. A medida que se mueve hacia abajo en el árbol, el modelo divide las ramas de «mejor ajuste».

# Cargamos la librería dplyr
library(dplyr) 
cats <- web_data_metrics %>% dplyr::select(deviceCategory, channelGrouping, sessions)

kable(head(cats), row.names = FALSE)
# Creamos ahora el árbol teniendo los dispositivos
library(rpart)

tree <- rpart(deviceCategory ~ ., cats)
plot(tree)
text(tree)

Gráficamente no aparecerá de una forma muy atractiva, así que podemos darle un toque más bonito y personal.

library(rpart.plot)
rpart.plot(tree, type=1) 

Análisis de las correlaciones

Por definición, la correlación es un número que describe la fortaleza en la relación entre dos variables.

En términos de analítica digital, se podría usar para explorar las relaciones entre las métricas web y ver si se puede inferir una influencia, pero debemos tener cuidado de no caer precipitadamente en conclusiones erróneas que no tengan en cuenta otros factores.

Por ejemplo, una alta correlación entre las acciones sociales y la posición SEO podría significar:

  • Las acciones sociales influyen en la posición de SEO.
  • La posición SEO influye en las acciones sociales.
  • Las acciones sociales y la posición de SEO están influenciadas por un tercer factor (como la notoriedad de la marca).
  • La relación fue un error casual.

Desafortunadamente, es bastante común ver conclusiones precipitadas, lo cual es peligroso por dos razones:

Pero, aún así, la correlación puede ser muy útil: podemos identificar relaciones que, si las detectamos a tiempo, nos pueden ayudar a impulsar determinadas acciones que sean de nuestro interés.

Veamos en la práctica con el nuestro data frame:

# Cargamos las métricas de sesiones, páginas vistas, entradas y rebotes
kable(cor(web_data_metrics[,c("sessions","pageviews","entrances","bounces")]))
# Lo representamos gráficamente

## see correlation between all metrics
pairs(web_data_metrics[,c("sessions","pageviews","entrances","bounces")])

Cada uno de los gráfico tiene que mostrar una linealidad cuando las dos variables tiene una correlación.

Y, efectivamente, las Sesiones tienen una correlación directa con las Entradas, ya que una visita se traduce en una entrada en una página. Pero las Sesiones pueden tener tantas páginas vistas como rebotes.

Para entenderlo con los valores de la primera tabla aquí un resumen:

Ahora podemos realizar más análisis con los diferentes canales y observar los resultados de correlaciones entre las diferentes métricas.

library(ggplot2)
gg <- ggplot(data = pivoted) + 
      theme_minimal() + 
      ggtitle("Pago (blue) vs Orgánico (green)")
gg <- gg + 
      geom_line(aes(x = as.Date(date), y = `Paid Search`), col = "blue")

gg + geom_line(aes(x = as.Date(date), y = `Organic Search`), col = "green")
library(ggplot2)
gg <- ggplot(data = pivoted) + 
              theme_minimal() + 
              ggtitle("Social (red) vs Referral (orange)")
gg <- gg + 
      geom_line(aes(x = as.Date(date), y = Social), col = "red")
gg + geom_line(aes(x = as.Date(date), y = Referral), col = "orange")

Al parecer, solo el último tiene un grado de relación entre los canales directos y pago, por lo que podríamos pensar que hay más tráfico directo cuando en realidad lo que hay son anuncios de pago.

Conclusiones

El objetivo de este post, al igual que el anterior, es motivar los analistas digitales y de datos a no quedarse con una sola respuesta. Normalmente las herramientas de analítica nos proporcionan informaciones, pero somos nosotros los que debemos ser capaces de transformarlas en conocimiento. Este es el mayor reto de trabajar con la estadística descriptiva y predictiva.

Por sí sola Google Analytics nos proporciona una ínfima parte de los conocimientos (cada vez nos entrega datos de más valor gracias al machine learning), pero si a esto podemos añadir el análisis en R studio (apoyándonos incluso en herramientas como Python, Knime…) podemos alcanzar un nivel de conocimiento más elevado y dirigir nuestras suposiciones a hechos concretos.

En la tercera entrega, aplicaremos otros modelos predictivos y veremos más ejemplos de aprendizaje automático. Si quieres tener acceso al repositorio de este artículo, puedes acceder a él a través de este link.

Foto de mrusso

Apasionado de Finanza, Marketing e IT, es consultor y especialista en Digital Data Analytics a nivel internacional trabajando para diferentes sectores industriales. Además, desde hace 6 años compagina su trabajo con la formación in-company y en diferentes escuelas de negocios y Cámara de Comercio, realizando módulos y cursos de Analytics, DataViz, CRO y Tag Manager. Cuando no piensa en los datos, además de compaginar su tiempo con la familia, puedes encontrarlo escalando montañas en la sierra de Madrid con su bici de carretera o en una cancha de basket.

Ver toda la actividad de Marco Russo

Escribe un comentario