En mi anterior artículo definía qué es la tasa de abandono de clientes y los puntos clave para su análisis con Machine Learning. En éste veremos un ejemplo de principio a fin e iremos viendo el efecto de las diferentes técnicas en los resultados que obtenemos durante el análisis de abandono de clientes con Python.
Lo primero que haremos será obtener nuestro dataset de ejemplo. Hay muchos datasets sobre abandono de clientes, en éste caso hemos escogido uno que podemos encontrar en Kaggle. Lo podemos descargar directamente desde la web, en este caso lo tendremos en formato CSV. Se trata de un dataset sobre dato de abandono de clientes en una entidad bancaria.
Nuestro dataset, nuestro tesoro
Una vez descargado y puesto en la carpeta adecuada (en nuestro caso, la carpeta “data” pero puede ser cualquiera a vuestra elección), procederemos a cargarlo y, como hacemos habitualmente en procesos de Machine Learning, dar un primer vistazo a los datos con los que trabajamos. Además, vamos a eliminar algunas variables que ya sabemos que tendremos y que no nos van a interesar por ser irrelevantes (como el apellido del cliente) o que no aportarán al modelo predictor de abandono por ser identificadores. Esto es un caso habitual en datasets de todo tipo, donde tenemos datos MUY detallados (teléfonos, IDs, etc.) que sabemos automáticamente que no van a aportar. Algo parecido podría parecer con un campo de fecha y hora: por sí mismos son demasiado detallados y no nos interesan, pero desglosandolo podremos generar atributos interesantes. Hablaremos de éstas técnicas en futuros posts 🙂
Tenemos varios atributos como la edad de los clientes, la antiguedad, el número de productos, etc. Todos potencialmente interesantes para analizar y predecir el abandono de los clientes. Además de una previsualización de los datos, también es importante saber la forma de los mismos: cuántas filas y columnas tenemos disponibles. Además vamos a crear unas cuantas variables que nos serán útiles a lo largo de la exploración.
No es un dataset muy masivo, 10.000 filas y 11 columnas. Habitualmente los datasets de sistemas reales pueden ser bastante más ricos en atributos, desde las decenas de atributos hasta los miles (especialmente si generamos atributos automáticamente). Aún siendo relativamente pocas filas y columnas es imposible analizar 10.000 filas manualmente.
Exploración visual del dato
Para hacernos una idea breve de cómo se relacionan nuestros datos con nuestro label (la columna “Exited”, que marca si ese cliente se fue del banco o no) vamos a explorar visualmente los datos con algunos gráficos básicos. Así podremos empezar a tener una idea de qué atributos pueden ser importantes a la hora de predecir el abandono. Esta exploración de variables puede ser mucho más compleja, pero es importante hacerla de manera al menos de un modo básico porque nos puede dar pistas sobre varios puntos fundamentales de aquí en adelante:
- Qué atributos pueden ser importantes por sí mismos (si ayudan a diferenciar claramente los clientes que abandonan de los que no)
- Qué atributos pueden ser útiles para generar atributos compuestos para incrementar el rendimiento del algoritmo
- Potenciales problemas de calidad de datos
- Presencia de nulos
- Presencia de categorías muy dominantes en atributos de tipo texto
- Presencia de valores extremos y qué tipo de distribuciones tenemos: ¿son muy compactas? ¿muy dispersas?
Una de las columnas que puede ser importante en el análisis puede ser Edad. Vemos que al segmentarla por el label, diferencia los casos 0 (no abandona) y 1 (abandona) de manera significativa. Sin embargo, el hecho de que por sí misma diferencie el label no es una garantía de que al entrenar nuestro modelo de predicción de abandono tenga una gran importancia, ya que la mayoría de los modelos de Machine Learning actuales se aprovechan de las relaciones entre atributos además de su importancia individual.
Para las variables categóricas (aquellas no-numéricas que representan categorías, como “Género” o “País”) podemos crear histogramas en vez de boxplots para representar la distribución de los valores.
En principio no parece que estos atributos segmenten bien el hecho de que un cliente nos abandone, pero esperemos al impacto que pueden tener cuando construyamos el modelo.
A pesar de que los atributos categóricos pueden ser muy valiosos en los datasets para Machine Learning, los modelos no saben entrenarse con otro dato que no sea numérico. Por eso, librerías como Scikit-Learn ofrecen diferentes maneras de codificar estos valores categóricos como numéricos. La codificación de variables categóricas es un tema en sí mismo, ¡estad atentos al blog porque publicaremos sobre éste tema! Mientras tanto, vamos a usar la codificación más sencilla posible, la que nos ofrece OrdinalEncoder.
Como vemos, esta codificación sólo nos traduce de texto a números. Esto hace que ahora el modelo pueda entrenar con éstas variables. Sin embargo, no suele ser la mejor manera de codificar porque da a entender al modelo que hay una relación de magnitud (como la hay entre los números) y esto no es cierto en muchos casos. Por ejemplo, si estuviésemos codificando la variable “Color”, el verde no es mejor que el azul, pero es posible que al codificar el verde tuviese asignado el número 6 y el azul el 2, y el modelo entendería que 6 es más que 2, algo que no se corresponde con la realidad del negocio que estamos modelando. Por simplicidad y por salirse del ámbito de este post, codificaremos de ésta manera y trataremos el tema de la codificación en siguientes artículos.
Además de codificar también hemos partido el dato en dos conjuntos, entrenamiento y test. Entrenamiento tiene 7000 filas y test 3000 para poder medir el rendimiento de nuestro modelo con dato que nunca haya visto (como los nuevos clientes que tenga que analizar cuando lo estemos usando en producción en la empresa).
Nuestro primer modelo de análisis de abandono de clientes
Ahora que ya tenemos el dato separado en entrenamiento y test y con la forma adecuada para que los algoritmos puedan trabajar con él, ¡vamos a entrenar nuestro primer modelo de abandono de clientes! Vamos a usar un bosque de decisión (la combinación de muchos árboles de decisión individuales) por ser un modelo potente y robusto, rápido de entrenar y con una fácil interpetación. Podríamos usar modelos más complejos o incluso combinaciones de modelos, pero de nuevo se sale del ámbito de éste post.
Una vez entrenado, usaremos el conjunto de test para evaluar el rendimiento de nuestro modelo prediciendo qué clientes abandonarán nuestro negocio y cuáles no.
Las métricas son bastante buenas! Un acierto (accuracy) del 85%! Fantástico! O… bueno, pensemos un poco antes. ¿Es realmente el accuracy la métrica que queremos observar? ¿Qué quiere detectar nuestro negocio con éste modelo?
Esa es la pregunta que debemos hacernos a la hora de evaluar un modelo. En este caso, la detección de aquellos casos que SÍ abandonan, y dada la codificación de nuestro label (0 -> se queda / 1 -> abandona) queremos ver Precision (abandonos predichos correctamente / (abandonos predichos correctamente + abandonos falsamente predichos)). Tenemos un valor de 39%, no tan buena como parecía en un principio.
Pero si miramos la curva ROC (habitualmente usada en evaluación de modelos de clasificación binaria como éste) parece bastante buena…
Parece que algunas de las métricas que habitualmente se usan para evaluar modelos de éste tipo pueden ser engañosas. Saber qué métricas tienen sentido en nuestro caso de negocio es especialmente importante para poder evaluar si nuestro modelo es realmente bueno o sólo es que estamos mirando las métricas equivocadas. Elegir la(s) métrica(s) que realmente refleja el aporte de valor del modelo al negocio es clave y tiene que estar claro antes de empezar el diseño del conjunto de datos y el modelo.
Mejorando el modelo a través de hiperparámetros
Para intentar mejorar estos resultados podemos intentar diversas acciones. La primera de ellas, y que debería ser parte integral de nuestro flujo de entrenamiento de modelos de ML es buscar mejores combinaciones de hiperámetros para nuestro modelo. Los hiperámetros son parámetros externos que nosotros especificamos para modificar el comportamiento del algoritmo al explorar el dataset y construir reglas y ajustar pesos para llegar a las conclusiones que le estemos pidiendo (predecir el abandono de clientes en nuestro caso). Cada algoritmo tiene unos hiperparámetros, cuanto más complejo el algoritmo más hiperparámetros a ajustar. Los bosques de clasificación que hemos empezado a usar no es de los más complejos pero ya cuenta con bastantes hiperparámetros disponibles. Para buscar una combinación de hiperparámetros que se ajuste mejor a nuestro problema primero definiremos un grid de hiperparámetros (un espacio de búsqueda) y tomaremos 20 combinaciones de manera aleatoria. Dependiendo del tipo de hiperparámetro (lista, valores enteros o continuos) deberemos declarar su parte del espacio de busqueda de manera adecuada.
Para establecer el rendimiento de cada una de ellas usaremos validación cruzada con 5 particiones (únicamente sobre el conjunto de entrenamiento). Puedes encontrar más información sobre validación cruzada aquí. Por último, vamos a usar F1 Score para elegir la mejor combinación por ser la métrica que refleja el comportamiento de negocio que queremos usar (balance entre los casos de detección de abandono y no-abandono correctamente).
Vamos a comprobar el rendimiento de nuestro modelo con los nuevos hiperparámetros.
Precision ha subido un 6% y F1 Score también lo hace en un 5%… ¡para una exploración sencilla no es mal avance!
El problema del label desbalanceado
Además de mejorar el algoritmo en sus parámetros, la gran mayoría de los casos en Machine Learning la clave está en los datos. Su calidad, su completitud, cómo los tratamos y codificamos, cómo los combinamos, etc; es lo que realmente marca la diferencia en los resultados finales.
Ya sabíamos que el abandono de clientes es, por definición, un problema de clasificación binaria desbalanceado, con más casos de un tipo (‘no abandona’) que del otro (‘abandona’).
Vamos a aplicar varias técnicas de supersampleo de datos para equilibrar el dato y hacer que nuestro algoritmo aprenda sobre más ejemplos de la clase minoritaria. Vamos a probar SMOTE, ADASYN y SVMSMOTE, pero dependiendo del caso de negocio habría que probar diferentes aproximaciones, así como de infrasampleo o quizás métodos híbridos.
Ahora tenemos bastantes más filas en el conjunto de entrenamiento. Ahora tenemos unas 11.000 cuando antes teníamos 7.000, resultado de añadir casos “ficticios” pero que se parecen suficiente a los que integraban nuestra clase minoritaria (abandona) como para que el algoritmo los use para mejorar su aprendizaje.
Adicionalmente vamos a usar una versión del RandomForestClassifier en el que usaremos subconjuntos de datos balanceados en lo que respecta a la distribución de la clase para cada árbol que construye, sin tocar el dato de entrenamiento original.
Vamos a evaluar nuestros modelos entrenados con diferentes versiones de los datasets con supersampleo y con la modificación sobre el bosque de decisión balanceado sobre nuestro dato de test. Es MUY importante que este dato de test no haya sido modificado ni balanceado, y que mantenga la distribución original (desbalanceada) que caracteriza a nuestro problema de abandono de clientes.
Vemos que el mejor resultado tanto en Precision como en F1 Score lo ha obtenido la versión del modelo donde no tocamos el dato pero usamos una técnica de balanceo a través del algoritmo, con el RandomForestClassifer aprendiendo de subconjuntos del dato con la clase balanceada. Por tanto, ese será el modelo que usemos a partir de ahora.
Hemos mejorado un 10% la precision y un 4% el F1 Score sólo cambiando un parámetro en la creación del modelo. Si recuerdas nuestro artículo de introducción (puedes consultarlo aquí), por cada 5% que mejorabamos la retención de clientes, ¡podíamos incrementar el ingreso entre un 25 y un 95%! Que el modelo sea capaz de detectar dichos casos de abandono no nos asegura que vayamos a reducir la tasa en la que los clientes nos abandonan, pero nos da herramientas para avanzarnos a ello y tomar medidas que sí pueden ayudar a fidelizar a nuestros clientes.
Para más información y detalle podéis ver todo el código en mi GitHub.
En próximos posts seguiremos mejorando el modelo y evaluando los resultados para predecir de manera más efectiva el abandono de clientes, así como introduciendo las consideraciones de negocio asociadas. ¡Sigue atento y suscríbete! 🙂
¿Quieres ver una demo de análisis de churn rate con Python?
Durante la pasada edición del SolidQ Summit 2019 Pau Sempere y Pablo Corral nos contaban cómo analizar el abandono de clientes.
Accede GRATIS a la sesión suscribiéndote a nuestra Newsletter ?
[gravityform id=”3″ title=”false” description=”false”]