Más allá de la predicción de la pérdida de clientes y el aumento de la retención

Predicción de pérdida de clientes y retención

CIENCIA DE DATOS CAUSAL

Cómo enfocar mejor las políticas en presencia de churn

Portada, imagen por el autor

Una tarea muy común en la ciencia de datos es la predicción de churn. Sin embargo, predecir el churn a menudo es solo un paso intermedio y rara vez el objetivo final. Por lo general, lo que realmente nos importa es reducir el churn, que es un objetivo separado, no necesariamente relacionado. De hecho, por ejemplo, saber que los clientes a largo plazo tienen menos probabilidades de abandonar que los clientes nuevos no es un conocimiento accionable, ya que no podemos aumentar la permanencia de los clientes. Lo que nos gustaría saber en cambio es cómo afecta un tratamiento (o varios) al churn. Esto a menudo se conoce como incremento del churn.

En este artículo, iremos más allá de la predicción de churn y el incremento del churn, y consideraremos en su lugar el objetivo final de las campañas de prevención de churn: aumentar los ingresos. En primer lugar, una política que reduzca el churn también puede tener un impacto en los ingresos, lo cual debe tenerse en cuenta. Sin embargo, y lo que es más importante, aumentar los ingresos solo es relevante si el cliente no abandona. Por otro lado, reducir el churn es más relevante para los clientes de alto valor. Esta interacción entre el churn y los ingresos es fundamental para comprender la rentabilidad de cualquier campaña de tratamiento y no debe pasarse por alto.

Regalos y suscripciones

Para el resto del artículo, vamos a utilizar un ejemplo ilustrativo para mostrar la idea principal. Supongamos que somos una empresa interesada en reducir el churn de nuestros clientes y, en última instancia, aumentar nuestros ingresos. Supongamos que hemos decidido probar una nueva idea: enviar un regalo de 1$ a nuestros usuarios. Para probar si el tratamiento funciona, lo hemos enviado aleatoriamente solo a una submuestra de nuestra base de clientes.

costo = 1

Echemos un vistazo a los datos que tenemos a nuestra disposición. Importo el proceso generador de datos dgp_gift() de src.dgp. También importo algunas funciones de visualización y bibliotecas de src.utils.

from src.utils import *from src.dgp import dgp_giftdgp = dgp_gift(n=100_000)df = dgp.generate_data()df.head()
Instantánea de datos, imagen por el autor

Tenemos información de 100_000 clientes para los cuales observamos el número de meses en los que han sido clientes activos, los ingresos generados en el último mes (rev_old), el cambio en los ingresos entre el último mes y el anterior (rev_change), si se les envió aleatoriamente un regalo y los dos resultados de interés: churn, es decir, si ya no son clientes activos, y los ingresos generados en el mes actual. Denotamos los resultados con la letra Y, el tratamiento con la letra W y las otras variables con la letra X.

Y = ['churn', 'ingresos']W = 'regalo'X = ['meses', 'rev_old', 'rev_change']

Nótese que, para simplificar, consideramos una instantánea de un solo período de los datos, y resumimos la estructura panel de los datos en solo un par de variables. Por lo general, tendríamos una serie de tiempo más larga, pero también un horizonte temporal más largo en lo que respecta al resultado (por ejemplo, el valor de vida del cliente).

Podemos representar el proceso subyacente de generación de datos con el siguiente grafo acíclico dirigido (DAG). Los nodos representan variables y las flechas representan posibles relaciones causales. He resaltado en verde las dos relaciones de interés: el efecto del regalo en el churn y los ingresos. Nótese que el churn está relacionado con los ingresos ya que los clientes que abandonan, por definición, generan cero ingresos.

DAG del proceso de generación de datos, imagen del autor

Es importante destacar que los ingresos pasados y el cambio en los ingresos son predictores de churn y revenue, pero no están relacionados con nuestra intervención. Por el contrario, la intervención afecta al churn y a los ingresos de manera diferente según los meses activos totales del cliente.

Aunque simplista, este proceso de generación de datos tiene como objetivo capturar una idea importante: las variables que son buenos predictores de churn o revenue, no necesariamente son variables que predicen el aumento del churn o revenue. Veremos más adelante cómo esto afecta nuestro análisis.

Comencemos explorando los datos.

Análisis Exploratorio de Datos

Comencemos con churn. ¿Cuántos clientes perdió la empresa el mes pasado?

df.churn.mean()

0.19767

¡La empresa perdió casi el 20% de sus clientes el mes pasado! ¿Ayudó el gift a prevenir el churn?

Queremos comparar la frecuencia de churn de los clientes que recibieron el gift con la frecuencia de churn de los clientes que no recibieron el gift. Dado que el gift fue aleatorio, el estimador de diferencia de medias es un estimador no sesgado para el efecto medio del tratamiento (ATE) del gift en el churn.

Efecto Medio del Tratamiento, imagen del autor

Calculamos la estimación de diferencia de medias mediante regresión lineal. También incluimos otras covariables para mejorar la eficiencia del estimador.

smf.ols("churn ~ " + W + " + " + " + ".join(X), data=df).fit().summary().tables[1]
Tabla de regresión del churn, imagen del autor

Parece que el gift redujo el churn en alrededor de 11 puntos porcentuales, es decir, ¡casi un tercio del nivel base del 32%! ¿También tuvo un impacto en revenue?

Al igual que con el churn, hacemos una regresión de revenue en el gift, nuestra variable de tratamiento, para estimar el efecto medio del tratamiento.

smf.ols("revenue ~ " + W + " + " + " + ".join(X), data=df).fit().summary().tables[1]
Tabla de regresión de revenue, imagen del autor

Parece que el gift en promedio aumentó los ingresos en 0.63$, lo que significa que no fue rentable. ¿Significa esto que deberíamos dejar de enviar regalos a nuestros clientes? Depende. De hecho, el regalo podría ser efectivo para ciertos segmentos de clientes. Solo necesitamos identificarlos.

Políticas de Segmentación

En esta sección, intentaremos entender si hay una forma rentable basada en los datos para enviar el gift, mediante la segmentación de clientes específicos. En particular, vamos a comparar diferentes políticas de segmentación con el objetivo de aumentar los ingresos.

A lo largo de esta sección, necesitaremos algunos algoritmos para predecir revenue, churn o la probabilidad de recibir el gift. Utilizamos modelos de árboles de refuerzo de gradiente de la biblioteca lightgbm. Utilizamos los mismos modelos para todas las políticas para que no podamos atribuir las diferencias en el rendimiento a la precisión de la predicción.

from lightgbm import LGBMClassifier, LGBMRegressor

Para evaluar cada política denotada con τ, comparamos sus ganancias con la política Π⁽¹⁾, con sus ganancias sin la política Π⁽⁰⁾, para cada individuo, en un conjunto de datos de validación separado. Es importante tener en cuenta que esto usualmente no es posible, ya que para cada cliente solo observamos uno de los dos resultados potenciales, con o sin el regalo. Sin embargo, como estamos trabajando con datos sintéticos, podemos realizar una evaluación oráculo. Si deseas obtener más información sobre cómo evaluar modelos de incremento con datos reales, te recomiendo mi artículo introductorio.

Evaluando Modelos de Incremento

Una de las aplicaciones más extendidas de la inferencia causal en la industria es el modelado de incremento, también conocido como la estimación…

towardsdatascience.com

En primer lugar, definamos las ganancias Π como los ingresos netos R cuando el cliente no abandona C.

Fórmula de ganancias, imagen por Autor

Por lo tanto, el efecto general en las ganancias para los individuos tratados se calcula como la diferencia entre las ganancias cuando se aplica el tratamiento Π⁽¹⁾ y las ganancias cuando no se aplica Π⁽⁰⁾.

Fórmula de incremento de ganancias, imagen por autor

El efecto para los individuos no tratados es cero.

def evaluar_politica(politica):    data = dgp.generar_datos(seed_datos=4, seed_asignacion=5, mantener_po=True)    data['ganancias'] = (1 - data.abandono) * data.ingresos    base = (1-data.abandono_c) * data.ingresos_c    efecto = politica(data) * (1-data.abandono_t) * (data.ingresos_t-costo) + (1-politica(data)) * (1-data.abandono_c) * data.ingresos_c    return np.sum(efecto - base)

1. Objetivo: Clientes que Abandonan

Una primera política podría ser dirigirse solo a los clientes que abandonan. Digamos que enviamos el regalo solo a los clientes con una tasa de abandono predicha superior al promedio.

modelo_abandono = LGBMClassifier().fit(X=df[X], y=df['abandono'])politica_abandono = lambda df : (modelo_abandono.predict_proba(df[X])[:,1] > df.abandono.mean())evaluar_politica(politica_abandono)

-5497.46

La política no es rentable y llevaría a una pérdida total de más de 5000$.

Puede que pienses que el problema es el umbral arbitrario, pero este no es el caso. A continuación, grafico el efecto total para todos los posibles umbrales de la política.

x = np.linspace(0, 1, 100)y = [evaluar_politica(lambda df : (modelo_abandono.predict_proba(df[X])[:,1] > p)) for p in x]fig, ax = plt.subplots(figsize=(10, 3))sns.lineplot(x=x, y=y).set(xlabel='Umbral de Política de Abandono', title='Efecto Total');ax.axhline(y=0, c='k', lw=3, ls='--');
Efecto total por umbral de abandono, imagen por Autor

Como podemos ver, no importa el umbral, es prácticamente imposible obtener ganancias.

El problema radica en que el hecho de que un cliente tenga probabilidades de abandonar no implica que el regalo tenga algún impacto en su probabilidad de abandono. Las dos medidas no están completamente relacionadas (por ejemplo, no podemos reducir la probabilidad de abandono de clientes que tienen una probabilidad de abandono del 0%), aunque no son lo mismo.

2. Clientes objetivo de ingresos

Ahora intentemos una política diferente: enviamos el regalo solo a clientes de alto ingreso. Por ejemplo, podríamos enviar el regalo solo a los 10 mejores clientes en términos de ingresos, es decir, al 10% superior de los clientes en ingresos. La idea es que si la política realmente reduce la pérdida de clientes, estos son los clientes para quienes reducir la pérdida de clientes es más rentable.

modelo_ingresos = LGBMRegressor().fit(X=df[X], y=df['ingresos'])politica_ingresos = lambda df : (modelo_ingresos.predict(df[X]) > np.quantile(df.ingresos, 0.9))evaluar_politica(politica_ingresos)

-4730.82

Nuevamente, esta política no es rentable y genera pérdidas sustanciales. Como antes, esto no es un problema de seleccionar el umbral, como podemos ver en el gráfico a continuación. Lo mejor que podemos hacer es establecer un umbral tan alto que no tratemos a nadie y obtengamos ganancias cero.

x = np.linspace(0, 100, 100)y = [evaluar_politica(lambda df : (modelo_ingresos.predict(df[X]) > c)) for c in x]fig, ax = plt.subplots(figsize=(10, 3))sns.lineplot(x=x, y=y).set(xlabel='Umbral de la política de ingresos', title='Efecto agregado');ax.axhline(y=0, c='k', lw=3, ls='--');
Efecto agregado por umbral de ingresos, imagen de Autor

El problema es que, en nuestro entorno, la probabilidad de pérdida de clientes de los clientes de alto ingreso no disminuye lo suficiente como para que el regalo sea rentable. Esto se debe también en parte al hecho, a menudo observado en la realidad, de que los clientes de alto ingreso también son los menos propensos a perderse en primer lugar.

Ahora consideremos un conjunto de políticas más relevantes: políticas basadas en incremento.

3. Clientes objetivo de incremento de pérdidas

Un enfoque más sensato sería dirigirse a los clientes cuya probabilidad de pérdida disminuye más cuando reciben el regalo de 1$. Estimamos el incremento de pérdidas utilizando el estimador de doble robustez, uno de los modelos de incremento de pérdidas de mejor rendimiento. Si no estás familiarizado con los meta-aprendices, te recomiendo que comiences por mi artículo introductorio.

Comprendiendo los Meta Aprendices

En muchos entornos, no solo estamos interesados en estimar un efecto causal, sino también en si este efecto es…

towardsdatascience.com

Importamos el aprendiz de doble robustez de econml, una biblioteca de Microsoft.

from econml.dr import DRLearnerDR_learner_churn = DRLearner(modelo_regresion=LGBMRegressor(), modelo_propension=LGBMClassifier(), modelo_final=LGBMRegressor())DR_learner_churn.fit(df['pérdida'], df[W], X=df[X]);

Ahora que hemos estimado el incremento de pérdidas, podríamos ser tentados a dirigirnos solo a los clientes con un incremento negativo alto (negativo, ya que queremos disminuir la pérdida). Por ejemplo, podríamos enviar el regalo a todos los clientes con un incremento estimado mayor que el promedio de pérdidas.

politica_incremento_perdidas = lambda df : DR_learner_churn.effect(df[X]) < - np.mean(df.pérdida)evaluar_politica(politica_incremento_perdidas)

-3925.24

Todavía la política no es rentable y genera casi 4000$ en pérdidas.

El problema es que no hemos considerado el costo de la política. De hecho, disminuir la probabilidad de pérdida solo es rentable para los clientes de alto ingreso. Tomemos el caso extremo: evitar la pérdida de un cliente que no genera ningún ingreso no vale la pena ninguna intervención.

Por lo tanto, solo enviemos el regalo a los clientes cuya probabilidad de pérdida ponderada por los ingresos disminuya más que el costo del regalo.

modelo_ingresos_1 = LGBMRegressor().fit(X=df.loc[df[W] == 1, X], y=df.loc[df[W] == 1, 'ingresos'])politica_incremento_perdidas = lambda df : - DR_learner_churn.effect(df[X]) * modelo_ingresos_1.predict(df[X]) > costevaluar_politica(politica_incremento_perdidas)

318.03

¡Esta política es finalmente rentable!

Sin embargo, aún no hemos considerado un canal: la intervención también podría afectar los ingresos de los clientes existentes.

4. Objetivo de aumento de ingresos de los clientes

Un enfoque simétrico al anterior sería considerar solo el impacto en ingresos, ignorando el impacto en la rotación. Podríamos estimar el aumento de ingresos para los clientes que no abandonan y tratar solo a aquellos clientes cuyo efecto incremental en los ingresos, neto de la rotación, sea mayor que el costo del regalo.

DR_learner_netrevenue = DRLearner(model_regression=LGBMRegressor(), model_propensity=LGBMClassifier(), model_final=LGBMRegressor())DR_learner_netrevenue.fit(df.loc[df.churn==0, 'revenue'], df.loc[df.churn==0, W], X=df.loc[df.churn==0, X]);model_churn_1 = LGBMClassifier().fit(X=df.loc[df[W] == 1, X], y=df.loc[df[W] == 1, 'churn'])policy_netrevenue_lift = lambda df : DR_learner_netrevenue.effect(df[X]) * (1-model_churn_1.predict(df[X])) > costevaluate_policy(policy_netrevenue_lift)

50.80

Esta política también es rentable pero ignora el efecto en la rotación. ¿Cómo combinamos esta política con la anterior?

5. Objetivo de aumento de ingresos de los clientes

La mejor manera de combinar eficientemente tanto el efecto en la rotación como en los ingresos netos es simplemente estimar el aumento total de ingresos. La política óptima implícita es tratar a los clientes cuyo incremento total de ingresos sea mayor que el costo del regalo.

DR_learner_revenue = DRLearner(model_regression=LGBMRegressor(), model_propensity=LGBMClassifier(), model_final=LGBMRegressor())DR_learner_revenue.fit(df['revenue'], df[W], X=df[X]);policy_revenue_lift = lambda df : (DR_learner_revenue.effect(df[X]) > cost)evaluate_policy(policy_revenue_lift)

2028.21

¡Parece que esta es, con mucho, la mejor política, generando una ganancia agregada de más de 2000$!

El resultado es sorprendente si comparamos todas las políticas diferentes.

policies = [policy_churn, policy_revenue, policy_churn_lift, policy_netrevenue_lift, policy_revenue_lift] df_results = pd.DataFrame()df_results['policy'] = ['churn', 'revenue', 'churn_L', 'netrevenue_L', 'revenue_L']df_results['value'] = [evaluate_policy(policy) for policy in policies]fig, ax = plt.subplots()sns.barplot(df_results, x='policy', y='value').set(title='Efecto incremental general')plt.axhline(0, c='k');
Comparación de políticas, imagen del autor

Intuición y Descomposición

Si comparamos las diferentes políticas, está claro que dirigirse directamente a los clientes con alta probabilidad de ingresos o alta probabilidad de rotación fueron las peores opciones. Esto no siempre es necesariamente el caso, pero sucedió en nuestros datos simulados debido a dos hechos que también son comunes en muchos escenarios reales:

  1. Los ingresos y la probabilidad de rotación están correlacionados negativamente
  2. El efecto del regalo en la rotación (o en los ingresos) no estaba fuertemente correlacionado negativamente (o positivamente para los ingresos) con los valores de referencia

Cualquiera de estos dos hechos puede ser suficiente para considerar que dirigirse a los ingresos o la rotación es una mala estrategia. En cambio, lo que se debería buscar son clientes con un alto efecto incremental. Y es mejor utilizar directamente como resultado la variable de interés, en este caso, los ingresos, siempre que estén disponibles.

Para comprender mejor el mecanismo, podemos descomponer el efecto agregado de una política en las ganancias en tres partes.

Descomposición del aumento de beneficios, imagen del autor

Esto implica que hay tres canales que hacen rentable tratar a un cliente.

  1. Si es un cliente de alto ingreso y el tratamiento disminuye su probabilidad de cancelación
  2. Si es un cliente que no cancela y el tratamiento aumenta sus ingresos
  3. Si el tratamiento tiene un fuerte impacto tanto en sus ingresos como en su probabilidad de cancelación

La segmentación por aumento de cancelación explota solo el primer canal, la segmentación por aumento de ingresos netos explota solo el segundo canal, y la segmentación por aumento de ingresos totales explota los tres canales, lo que la convierte en el método más efectivo.

Bono: ponderación

Como destacaron Lemmens, Gupta (2020), a veces vale la pena ponderar las observaciones al estimar el aumento del modelo. En particular, puede valer la pena dar más peso a las observaciones cercanas al umbral de la política de tratamiento.

La idea es que la ponderación generalmente disminuye la eficiencia del estimador. Sin embargo, no nos interesa tener estimaciones correctas para todas las observaciones, sino que nos interesa estimar correctamente el umbral de la política. De hecho, no importa si estimas una ganancia neta de 1$ o 1000$, la política implícita es la misma: enviar el regalo. Sin embargo, estimar una ganancia neta de 1$ en lugar de -1$ invierte las implicaciones de la política. Por lo tanto, a veces vale la pena una gran pérdida de precisión lejos del umbral a cambio de una pequeña ganancia de precisión en el umbral.

Intentemos usar pesos exponenciales negativos, disminuyendo en la distancia desde el umbral.

DR_learner_revenue_w = DRLearner(model_regression=LGBMRegressor(), model_propensity=LGBMClassifier(), model_final=LGBMRegressor())w = np.exp(1 + np.abs(DR_learner_revenue.effect(df[X]) - cost))DR_learner_revenue_w.fit(df['revenue'], df[W], X=df[X], sample_weight=w);policy_revenue_lift_w = lambda df : (DR_learner_revenue_w.effect(df[X]) > cost)evaluate_policy(policy_revenue_lift_w)

1398.19

En nuestro caso, no vale la pena ponderar: la política implícita sigue siendo rentable pero menos que la obtenida con el modelo sin ponderar, 2028$.

Conclusión

En este artículo, hemos explicado por qué y cómo se debe ir más allá de la predicción de cancelación y la modelización del aumento de cancelación. En particular, uno debería concentrarse en el objetivo final del negocio de aumentar la rentabilidad. Esto implica cambiar el enfoque de la predicción al aumento, pero también combinar la cancelación y los ingresos en un único resultado.

Una advertencia importante se refiere a la dimensión de los datos disponibles. Hemos utilizado un conjunto de datos de prueba que simplifica en gran medida el problema en al menos dos dimensiones. En primer lugar, hacia atrás, normalmente tenemos series temporales más largas que se pueden (y se deben) utilizar tanto para la predicción como para fines de modelado. En segundo lugar, hacia adelante, se debe combinar la cancelación con una estimación a largo plazo de la rentabilidad del cliente, generalmente conocida como valor de vida del cliente.

Referencias

  • Kennedy (2022), “Hacia la estimación óptima de efectos causales heterogéneos de doble robustez”
  • Bonvini, Kennedy, Keele (2021), “Identificación óptima de subgrupos de submáximo”
  • Lemmens, Gupta (2020), “Gestión de la cancelación para maximizar los beneficios”
  • Evaluación de modelos de aumento
  • Comprensión de Meta Learners
  • Comprensión de AIPW, el estimador de doble robustez

Código

Puede encontrar el cuaderno Jupyter original aquí:

Blog-Posts/notebooks/beyond_churn.ipynb en main · matteocourthoud/Blog-Posts

Código y cuadernos para mis publicaciones de blog de VoAGI. Contribuye al desarrollo de matteocourthoud/Blog-Posts creando un…

github.com

¡Gracias por leer!

¡Lo aprecio mucho! 🤗 Si te gustó la publicación y quieres ver más, considera seguirme. Publico una vez a la semana sobre temas relacionados con la inferencia causal y el análisis de datos. Intento mantener mis publicaciones simples pero precisas, siempre proporcionando código, ejemplos y simulaciones.

También, una pequeña advertencia: escribo para aprender, por lo que los errores son normales, aunque hago todo lo posible. Por favor, cuando los encuentres, avísame. ¡También aprecio sugerencias sobre nuevos temas!