Churn Prediction para uma Empresa de Telecomunicações

O Churn é um dos maiores inimigos de empresas como a Netflix e o Spotify e nesse artigo vou te ensinar como realizar sua previsão!

João Gustavo
Data Hackers

--

Image by rawpixel.com on Freepik

Primeiro, preciso deixar esclarecer o que é o churn e para que ele é usado. Dessa forma, é possível dizer que o churn, ou churn rate, representa a taxa de evasão da sua base de clientes. Em serviços por assinatura, como Netflix e Spotify, ela representa a taxa de cancelamento.

A análise dessa taxa é de extrema importância, pois ao longo do tempo pode nos mostrar um problema que deve ser resolvido.

O churn também pode ser usado para identificar possíveis cancelamentos, com certa antecedência, assim dando a oportunidade para a empresa tentar manter esses clientes. Nos negócios o Custo de Aquisição de Cliente (CAC) é maior que o custo para mantê-lo, por isso uma alta taxa de churn é prejudicial para o negócio, visto que obter mais clientes é mais caro que manter os clientes que você já possui!

Obtenção dos Dados

Os dados utilizados foram originalmente disponibilizados na plataforma de ensino da IBM Developer, e tratam de um problema típico para companhias de Telecomunicação. O dataset completo pode ser encontrado clicando aqui!

Apesar de não haver informações explícitas disponíveis, os nomes das colunas permitem que nós tenhamos um entendimento a respeito do problema!

O objetivo do projeto é de construir modelos de machine learning, para realizar a previsão do churn, algo que algumas empresas já fazem para amenizar esse problema. Dessa forma, irei começar mostrando como ficoui distribuído o projeto, dado que este foi o mais extenso que já fiz!

O projeto ficou dividido da seguinte forma:

  • Análise Exploratória
  • Limpeza dos Dados
  • Processamento dos Dados com Label Encoder e Get Dummies
  • Preparação dos Dados

Nesta seção é onde está a maior parte prática de todo o projeto!

  • Conclusão

Análise exploratória

Para começar a análise, é necessário verificar as dimensões do DataFrame, após isso, checar o nome das variáveis/colunas e realizar a checagem de quantos valores únicos estão presentes em cada uma das colunas. Identificando os valores únicos, também identificamos se as colunas são categóricas ou não.

O DataFrame possui 7043 entradas e 21 colunas, sendo assim ele é menor que o último projeto que publiquei aqui, Detectando Fraudes em Cartões de Crédito com Machine Learning!

Existem colunas que não possuem apenas 2 valores, algumas colunas possuem 3 ou mais valores. Por exemplo, a coluna tenure possui 73 valores diferentes, possivelmente é uma coluna referente a quantidade de meses de assinatura do serviço.

Para a análise ficar completa, eu chequei a quantidade de dados ausentes, porém foi retornado que não havia valores ausentes.

Algumas observações a serem feitas:

  • A coluna customerID é insignificante para a análise, visto que apenas nos fornece o identificador de cada cliente.
  • A variável alvo está presente na coluna Churn, ela indica se o cliente cancelou ou não o serviço.
  • A coluna TotalCharges assim como a coluna MonthlyCharges, apresenta valores flutuantes, mas está como string dado que seu tipo de dado deveria ser float.
  • Diversas colunas vão precisar de um trabalho de codificação, transformando-as em valores numéricos.
  • Apesar do nosso código retornar que não há valores ausentes, pode ser que algumas strings representem valores ausentes.

Limpeza dos Dados

Como já foi dito, a coluna TotalCharges deveria ser apresentada como float, porém estava sendo apresentada como string. Portanto, para converter a coluna foi necessário o uso de um método mais complexo, visto que ao usar df[TotalCharges].astype(float32) era retornado um erro.

O erro em questão ocorre devido aos dados ausentes terem sido preenchidos com "", quando tentamos converter "" para float, o interpretador nos retorna um erro.

Para contornar o erro e converter de forma adequada criei uma função para lidar com o erro. Consequentemente, foi possível identificar valores ausentes, que logo foram preenchidos com o valor da mediana da coluna.

Também, excluí a coluna customerID, tendo em vista que não agregava em nada para o projeto.

O código da função em questão é esse:

def str_to_float(entrada):
try:
return float(entrada)except ValueError:return np.nan

A função converte um objeto string em float, porém caso não seja possível realizar tal operação o objeto string será convertido em um valor NaN.

O DataFrame possui majoritariamente variáveis categóricas, mas estão presentes algumas variáveis numéricas, que após usar o método describe não possuem outliers. Veja abaixo:

Método Describe

As colunas MonthlyCharges e TotalCharges foram analisadas por meio de boxplots e olhando a imagem abaixo é possível confirmar a ausência de outliers, uma vez que mesmo não definindo limites, não foram encontados plots fora dos limites.

BoxPlot refente às colunas MonthlyCharges e TotalCharges

Uma forma de verificar a “fidelidade” de um cliente, o tempo o qual ele passa assinando o serviço, é plotar um gráfico de barras da variável tenure , que tem como possível unidade de tempo o “mês”.

Tempo de fidelidade dos clientes

Algo que deve ser levado em consideração ao lidar com variáveis categóricas é identificar os valores únicos. Dessa forma, podemos encontrar valores que podem ser unificados, como por exemplo:

  • No
  • No phone service
  • No internet service

Tendo em vista que esse valores, representam a “mesma” coisa, defini os valores apenas para No .

A fim de concluir a análise exploratória, verifiquei o balanceamento das classes. Dificilmente, as classes vão estar balanceadas em algum caso e dessa vez não foi diferente, a ocorrência de No é maior do que a ocorrência de Yes , algo positivo pra empresa.

Balanceamento das Classes

Porém, pode dar problemas na hora de treinar o modelo e por isso é necessário fazer o balanceamento das classes.

Processamento dos Dados

Nesta etapa, fiz o pré-processamento necessário dos dados. As variáveis binárias (que possuem apenas dois valores únicos), foram processadas usando o LabelEncoder , até mesmo a variável Churn .

Em seguida, separei as variáveis em categóricas e numéricas, onde as variáveis categóricas foram tratadas com o getDummies , assim podendo serem utilizadas em todos os modelos.

Após essa etapa, foi feito o processo de feature matrix e target vector do DataFrame.

Padronização e Balanceamento dos Dados

Para a padronização, usei 5 métodos diferentes, a fim de comparar o desempenho dos modelos de acordo com a padronização usada. Após a padronização, os dados foram combinados com 3 diferentes métodos de balanceamento de dados (RUS, SMOTE, ADASYN).

Avaliando Modelos com Cross-Validation

Após balancear e padronizar os dados, fiz uma validação e selecionei os modelos com os melhores desempenhos, para fazer a predição. Foram, selecionados 3 modelos de cada balanceamento, porém só falarei do que obteve o melhor desempenho! Os outros estarão no projeto, neste link!

O Modelo que obteve os melhores resultados após todo o processo de balanceamento, padronização e tuning dos hiperparâmetros foi o XGBoost com o balanceamento SMOTE e método de padronização Robust Scaler.

Avaliando o Desempenho do Modelo XGB

Este modelo é considerado o melhor por mim, pois foi o que menos teve falsos negativos, mesmo que o número de falsos positivos tenha sido consideravelmente maior. Contudo, também fez o maior número de previsões de churn, foram 405 previsões.

Matriz de Confusão XGBoost

O modelo, após todos os ajustes teve os parâmetros ajustados da seguinte forma:

xgb_smo_Rscaled = XGBClassifier(learning_rate=0.01, n_estimators=100, max_depth=1, min_child_weight=1, gamma=0)

Conclusão

O churn é algo que todas as empresas precisam lidar, até mesmo as grandes líderes do mercado. Porém, algo que pode ajudar a diminuir o a taxa de vazão de clientes e consequentemente alavancar o negócio é o churn prediction.

Portanto, para lidar e amenizar o churn criei alguns modelos de Machine Learning a fim de realizar a predição, de forma que a empresa possa contornar a situação e diminuir a sua taxa de vazão de clientes.

O modelo apresentado no artigo foi o que obteve os mehores resultados, o modelo de árvore de decisão XGBoost, que foi treinado com os dados balanceados com o método SMOTE.

Esse modelo obteve:

  • 405 previsões de churn — o modelo que mais fez previsões corretas.
  • 62 previsões de falsos negativos — o modelo que menos deixou passar possíveis churns.
  • 583 previsões de falsos positivos — foram feitas diversas previsões de falsos positivos. Porém, a empresa não teria problema em checar essas previsões, gerando aquelas ligações indesejadas que todos conhecemos.

Para ter acesso ao projeto completo, clique aqui! Aproveita para me seguir no LinkedIn e fica de olho no meu GitHub, lá você poderá encontrar mais projetos futuramente.

--

--