Existen decenas de posibilidades de estimar la procedencia del tráfico de nuestras campañas publicitarias, o lo que es lo mismo, entender qué canales o fuente/medio son los que aportan valor real a los objetivos de la empresa. Por ejemplo, hace unas pocas semanas en este mismo Blog detallaba la posibilidad de conocer esto a través del Marketing Mix Model

Sin embargo, el artículo que se detalla a continuación se centra en otro desarrollo igualmente importante para cualquier persona que gestione campañas. No es algo excluyente, sino todo lo contrario, algo complementario. De ahí la importancia de incorporar todos ellos al flujo de actuación habitual del equipo de Marketing, más allá de únicamente llevar a cabo su implementación de manera individualizada. 

En concreto, en este caso me estoy refiriendo a la creación del Channel Scoring. Éste no es más que la representación ponderada (escala por puntos) de la relevancia real de los diferentes canales involucrados en el proceso de venta. Dicho de otra manera, comparar todos los canales entre sí teniendo en cuenta su influencia e impacto en el objetivo final (habitualmente relacionada a métricas transaccionales). Es decir, por lo general una mayor calificación se equiparará a una mayor inversión publicitaria.

Valga como ejemplo de lo que comentaba previamente sobre la necesidad de interrelacionar o complementar este tipo de proyectos entre sí, el uso normalizado del Channel Scoring con otros desarrollos como el Lead Scoring Ambos son similares en cuanto a metodología, aunque diferentes en lo que a lógica de análisis se refiere. El uso conjunto de ellos permite conocer la calidad y procedencia del tráfico.

 

Proceso de la cadena de Markov para la atribución de canales

Existen numerosas librerías cuyo propósito es determinar la atribución de canales. En este caso y con el objetivo de simplificar el proceso he utilizado el proyecto open-source ChannelAttribution, el cual utiliza los procesos de Markov de K-orden o cadena de Markov. Que no es más que el uso reiterativo del proceso de 1er-orden de Markov el cual determina la probabilidad de que ocurra un evento basándose únicamente en el evento inmediatamente anterior. El objetivo es identificar correlaciones estructurales durante todo el customer-journey del usuario. Además, de este approach, este paquete contiene tres algoritmos heurísticos habituales: first-click, last-click y linear-attribution.

Proceso cadena de Markov con librería ChannelAttribution para atribución de canales de tráfico

Proceso de la cadena de Markov con un ejemplo de la librería ChannelAttribution.

En este imagen se puede ver perfectamente el proceso probabilístico que se lleva a cabo aplicándose el modelo de Markov. El proceso mostrado consta esencialmente de 3 partes fácilmente diferenciables:

  1. Customer Journeys. En este ejemplo se muestran 3 customer-journeys diferentes con hasta 2 canales posibles involucrados. Todos ellos, como es lógico, generar una conversión.
  2. Tabla resumen. Agrupación de todas y cada una de las diferentes aristas involucradas en el análisis (de los 3 customer-journeys) con el objetivo de contabilizarlas y obtener sus probababilidades de conversión. Además, se puede representar esta tabla como un grafo que permite entender mejor las interacciones.
  3. Importancia de cada canal. Para calcular la relevancia de cada canal se debe llevar a cabo un procesado concreto para cada uno de ellos.
    • Canal A. La relevancia del canal A se puede definir como el cambio en la tasa de conversión (Conversion Rate, CR) si el nodo A se eliminase del grafo, o en otros términos, si A se convierte en un estado NULL. Si esto ocurre, no hay forma de alcanzar la conversión desde el estado START (CR = 0). La conversión cae de 1 (conversión del grafo original) a 0. Por lo tanto, la importancia del canal A es 1.
    • Canal B. Igualmente, para definir la importancia del canal B se debe transformar éste a NULL. De esta forma, la probabilidad de alcanzar la conversión desde START es CR = 0,5. Es decir, la conversión cae un 0,5. Por lo tanto, la importancia del canal B es 0,5. 

Tras este procesado, solo queda balancear y ponderar los resultados obtenidos por cada canal y según el número de conversiones totales tal y como se ve en la siguiente imagen.

Resultado final de las cadenas de Markov para diferentes customer journeys de ejemplo

Resultado final del modelo de Markov presentado.

De manera más o menos resumida, se puede decir que el modelo de Markov permite analizar las relaciones entre los diferentes canales involucrados en el customer-journey para comprender su relevancia en la consecución de la conversión seleccionada. A diferencia de los modelos heurísticos, los cuales se basan en supuestos subjetivos (normalmente en base al conocimiento de negocio previo), tiene en cuenta «todos» los touchpoint y conversiones registradas.

 

Implementación del Channel Scoring con diferentes modelos de atribución

Por último y tras entender el modelo de Markov, solo queda implementar y compartir el código básico. En este caso he optado por hacerlo en R y no en Python (documentación). Creo que permite simplificar mucho todo lo explicado previamente y en consecuencia comprenderlo mejor. Este desarrollo permite visualizar de manera sencilla los diferentes modelos de atribución explicados: First click, Last click, Linear attribution y Markov.

Después de la siguiente imagen, donde se puede observar la visualización del resultado final y cómo quedaría el Channel Scoring, te comparto el código R detallado para llevarlo a cabo. 

Channel Scoring, ponderación de canales de tráfico

Ponderación de canales para la visualización del Channel Scoring.

library(stringr)library(ggplot2)
library(googleAuthR)
library(googleAnalyticsR)
library(dplyr)
library(ChannelAttribution)
library(reshape)

ga_auth()
#----- Descargando los datos necesarios del MCF de Google Analytics para generar los modelos heurísticos -----------
transactions_func <- google_analytics_3(id = {{GA View ID}}, start="2023-03-29", end="2023-04-05", metrics = c("totalConversions","totalConversionValue"), dimensions = c("basicChannelGroupingPath","transactionId","conversionDate","timeLagInDaysHistogram"), filters ="mcf:totalConversions!=0.0;mcf:totalConversionValue!=0.0", samplingLevel = "HIGHER_PRECISION", type="mcf")
transactions_func_Str <- str_remove_all(transactions_func$basicChannelGroupingPath, "CLICK:|NA:|:NA|:CLICK") transactions_func_Str1 <- str_remove(transactions_func$timeLagInDaysHistogram, "^0+") transactions <- transactions_func %>% mutate(attribution=transactions_func_Str,window=transactions_func_Str1) transactions <- transactions %>% group_by(attribution,transactionId) %>% summarise(revenue=sum(as.numeric(totalConversionValue)),conversions=n_distinct(transactionId),window=mean(as.numeric(timeLagInDaysHistogram)),) %>% arrange(desc(revenue))
attribution <- transactions %>% group_by(attribution) %>% summarise(revenue=sum(revenue),conversions=sum(conversions),window=mean(window)) %>% arrange(desc(revenue))
#----- Generando los modelos heurísticos First-Click, Last-Click y Linear Attribution -----------
hm <- heuristic_models(attribution, var_value = "revenue", var_path = "attribution", var_conv = "conversions")
#----- Descargando los datos necesarios del MCF de Google Analytics para generar el modelo de Markov (cadena) -----------
visits_func <- google_analytics_3(id = {{GA View ID}}, start="2023-03-29", end="2023-04-05", metrics = c("totalConversions"), dimensions = c("basicChannelGroupingPath","conversionDate"), filters ="mcf:conversionGoalNumber==002", samplingLevel = "HIGHER_PRECISION", type="mcf")
visits_func_Str <- str_remove_all(visits_func$basicChannelGroupingPath, "CLICK:|NA:|:NA|:CLICK") visits <- visits_func %>% mutate(attribution=visits_func_Str) visits <- visits %>% group_by(attribution) %>% summarise(visits=sum(as.numeric(totalConversions))) %>% arrange(desc(visits))
attr_visits <- merge.data.frame(visits, attribution, by = "attribution", all=T) attr_visits[is.na(attr_visits$conversions), "conversions"] <- 0 attr_visits$rate <- attr_visits$conversions / attr_visits$visits attr_visits$null<- attr_visits$visits - attr_visits$conversions
#----- Generando el modelo de Markov sin tener en cuenta el revenue (Motivo: limitación librería ChannelAttribution) -----------
mm <- markov_model(attr_visits, var_path = "attribution", var_conv = "conversions", var_null = "null")
#----- Unión de todos los modelos en una misma tabla -----------
model <- merge.data.frame(hm, mm, all=T, by="channel_name") model_final <- model %>% na.omit()
sc <- model_final[, (colnames(model_final) %in% c('channel_name', 'first_touch_conversions', 'last_touch_conversions', 'linear_touch_conversions', 'total_conversions'))] colnames(sc) <- c('channel_name', 'first_touch', 'last_touch', 'linear_touch', 'markov_model')sc <- melt(sc, id='channel_name')
#----- Integrando los costes de campañas (manualmente) a cada canal durante el período previamente seleccionado-----------
sc_costs <- data.frame (channel_name= c("Email", "Organic Search", "Paid Search", "Referral"), costs = c(6000, 2000, 12000,500))
#----- Añadiendo el scoring para cada canal (basado únicamente en revenue y gasto publicitario). Lo ideal sería añadir más características para la ponderación-----------
sc_final = inner_join(sc, sc_costs, by = "channel_name") sc_final$roas <- with(sc_final, (sc_final$value/sc_final$costs)*100) sc_final = sc_final %>% filter(((variable == 'markov_model'))) sc_final$ch_score = round(((sc_final$roas/max(sc_final$roas))*10),digits=1)
#----- Visualización de datos de los diferentes modelos de atribución presentados-----------
ggplot(sc, aes(x=reorder(channel_name,-value), value, fill = variable)) + geom_bar(stat='identity', position='dodge') + ggtitle('MODELOS DE ATRIBUCIÓN') +theme(axis.title.x = element_text(vjust = -2)) + theme(axis.title.y = element_text(vjust = +2)) + theme(title = element_text(size = 16)) + theme(plot.title=element_text(size = 20)) + ylab("ingresos") + xlab("canales") + labs(fill="Atribución")
#----- Visualización de datos del Channel Scoring ya ponderado y balanceado en una escalada de 10-----------
ggplot(sc_final, aes(x=reorder(channel_name,-ch_score), ch_score)) + geom_bar(stat='identity', position='dodge') + ggtitle('CHANNEL SCORING') + theme(axis.title.x = element_text(vjust = -2)) + theme(axis.title.y = element_text(vjust = +2)) + theme(title = element_text(size = 16)) + theme(plot.title=element_text(size = 20)) + ylab("score") + xlab("canales")

Creo que este post va a ser de gran utilidad para todo aquel que trabaja con datos en torno a la Publicidad y el Marketing. Se trata de una implementación con muchas posibilidades, esencialmente lo que al approach de la cadena de Markov se refiere. Cada vez más usada también en otros muchos proyectos de analítica. Si quieres seguir aprendiendo sobre este tipo de implementaciones de Analítica avanzada o saber más en torno al Marketing Digital, te invito a que visites el resto de artículos de mi Blog. ¡Te espero en el siguiente artículo!

Deja una respuesta

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