Prevendo o Churn em uma empresa de Telecomunicação

Projeto — Churn Rate Prediction

Matheus Buniotto
9 min readJun 19, 2021

O Churn rate é uma métrica utilizada para detectar a perda de clientes em um determinado período e é muito utilizada em empresas SaaS (Software as a Services) ou que trabalham com produtos ou serviços por assinatura.

O cálculo do Churn Rate é representado pela fórmula:

Fonte: Meet

A importância do Churn Rate

A fidelização de um cliente é fundamental o sucesso das empresas.

“Manter um cliente é muito mais barato do que atrair um novo”

Isso faz sentido, afinal, você não precisa gastar tempo e recursos para atrair alguém que já é seu cliente.

Hoje, essa máxima é ainda mais importante e as cada vez mais as empresas estão despendendo esforços para haver uma maior retenção dos consumidores.

O problema

Manter uma taxa de Churn o mais baixo possível representa um aumento significativo nos lucros da empresa.

Se você ainda não está convencido, um estudo conduzido por Frederick Reichheld da Bain & Company(o inventor do NPS), revelou que melhorar a retenção de clientes em apenas 5% pode aumentar os lucros da empresa de 25 a 95%!

Fonte: Harvard Business Review

  • Você já imaginou se pudéssemos prever um cliente que provavelmente cancelará sua assinatura?

Hipótese

Utilizando dados históricos de clientes e através de algorítimos de Machine Learning podemos prever a probabilidade de um cliente cancelar sua assinatura.

Sabendo qual cliente terá maior chance de desistir de sua assinatura podemos direcionar os esforços para mante-lo fiel ao produto ou serviço.

Podemos ainda, utilizar os dados do cliente para fazermos uma oferta especial e personalizada a ele, dessa forma podemos aumentar a satisfação do cliente em relação ao serviço ou produto ofertado.

91% dos consumidores dizem que são mais propensos a comprar com marcas que fornecem ofertas e recomendações que são relevantes para eles. — Accenture

O Projeto

Nesse projeto irei utilizar os dados fornecidos originalmente na plataforma de ensino da IBM Developer, e refletem um problema típico de Churn em empresas de telecomunicação.

Utilizando os dados, iremos prever os clientes que serão mais propensos a cancelar o serviço.

1. Aquisição dos dados

Como citado acima, os dados foram disponibilizados pela plataforma IBM Developer, e podem ser encontrados através do link: IBM

Apesar de não termos informações explícitas sobre o que cada variável representa, os nomes das colunas nos permite entender o que cada uma representa.

2. Análise exploratória

Nessa etapa iremos entender os dados, sua composição, formatos, estrutura, etc. Além disso, vamos transformar os dados em gráficos que facilitem a compreensão e nos ajude a extrair informações relevantes para construção do nosso modelo.

Verificando as 5 primeiras entradas do conjunto de dados. Vamos ver qual é a “cara” dos nossos dados.

Tamanho, composição e formato dos dados:

O conjunto de dados possui: 7043 entradas
O conjunto de dados possui: 21 variáveis

Vamos investigar a nossa variável Alvo : Churn!

In [ ]:

df['Churn'].value_counts()No     5174
Yes 1869
Name: Churn, dtype: int64

A variável Churn é composta de por Sim e Não. Mais a frente iremos balancear os Churn para que nosso modelo possa aprender sem nenhum viés.

Grande parte das variáveis do conjunto de dados são variáveis categóricas, vamos entender como elas são compostas:

criar df para ver as categorias das colunas
df_categorias = df.drop(['tenure', 'MonthlyCharges', 'TotalCharges'], axis = 1)
for c in df_categorias.columns:
print(c, ':', df[c].nunique(), 'categorias')
gender : 2 categorias
SeniorCitizen : 2 categorias
Partner : 2 categorias
Dependents : 2 categorias
PhoneService : 2 categorias
MultipleLines : 3 categorias
InternetService : 3 categorias
OnlineSecurity : 3 categorias
OnlineBackup : 3 categorias
DeviceProtection : 3 categorias
TechSupport : 3 categorias
StreamingTV : 3 categorias
StreamingMovies : 3 categorias
Contract : 3 categorias
PaperlessBilling : 2 categorias
PaymentMethod : 4 categorias
Churn : 2 categorias

Vamos criar 2 listas representando as variáveis binárias e não binárias. Isso facilitará o tratamento das variáveis futuramente.

categorias_binarias = []
categorias_n_binarias = []

for c in df_categorias.columns:
if df[c].nunique() == 2:
categorias_binarias.append(c)
else:
categorias_n_binarias.append(c)
Categorias Binárias:
['gender', 'SeniorCitizen', 'Partner', 'Dependents', 'PhoneService', 'PaperlessBilling', 'Churn']

Categorias Não Binárias:
['MultipleLines', 'InternetService', 'OnlineSecurity', 'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies', 'Contract', 'PaymentMethod']

Sabendo que a maioria dos conjuntos de dados apresentam algum problema em relação a valores nulos ou em brancos, vamos analisar nosso conjunto.

O conjunto de dados possui: 0 valores nulos

Vamos extrair as informações estatísticas relevantes dos dados numéricos.

Anteriormente descobrimos que a variável alvo (aquela que estamos tentando prever) está desbalanceada. Vamos analisar melhor:

Os clientes Churn representam 26.54% do total

Agora, vamos partir para análise de outras variáveis do conjunto de dados para extrairmos informações relevantes, como por exemplo a correlação entre algumas variáveis ou os clientes mais propensos à cancelarem sua assinatura.

Através dos gráficos acima vemos que a maioria dos cancelamentos ocorrem nos primeiros meses de contrato do serviço. Além disso, pessoas que gastam mais com as recargas estão mais propensas ao Churn.

Veja como após um processamento inicial dos dados já temos informações valiosas para redução do Churn. Nesse exemplo, a empresa poderia implantar benefícios extras para pessoas com gastos maiores e nos primeiros meses de contrato.

Após isso, seria necessário acompanhar os indicadores para entender se as medidas foram efetivas e otimizar a estratégia.

Vamos ver o boxplot das variáveis numéricas.

  • Boxplot é uma ferramenta gráfica para representar a variação de dados observados de uma variável numérica por meio de quartis.

Clientes parceiros:

Tipo de pagamento:

Preparação dos dados

Nessa etapa faremos o tratamento dos dados para que possamos realizar o treinamento do nosso modelo de Machine Learning

Vamos transformar as variáveis categóricas em numéricas para que possamos treinar nossos modelos. Para isso utilizaremos o LabelEncoder para variáveis binárias e o get_dummy para variáveis categóricas não binárias, disponível na biblioteca sklearn.

O que são variáveis categóricas?

Variáveis categóricas também são chamadas variáveis quantitativas ou variáveis de atributo. Os valores de uma variável categórica são categorias ou grupos mutuamente exclusivos. Os dados categóricos podem ou não ter alguma ordem lógica. Fonte: Mintlab

Os valores categóricos Male e Female, foram transformados em 1 e 0, respectivamente. Isso ajudará no treinamento do nosso modelo de machine learning.

Vamos verificar se há alguma correlação evidente entre as variáveis.

Agora, também vamos transformar as variáveis categóricas não binárias, utilizando a função get_dummy

Balancear os dados

Como vimos acima, os dados da variável Churn estão desbalanceados, possuindo uma quantiade muito maior de uma categoria do que outra. Chegou a hora de balancear o conjunto de dados para que não haja viés nas previsões. Para isso, vamos utilizar o SMOTE.

A SMOTE (técnica de sobreamostragem minoritária sintética) é uma técnica estatística para aumentar o número de casos em seu conjunto de um modo equilibrado. O módulo funciona gerando novas instâncias de casos minoritários existentes que você fornece como entrada. Essa implementação de SMOTE não altera o número de casos de maioria.

Fonte: Microsoft Machine Learning

Distribuição atual de Churn

Como ficaram os dados da variável Churn após a aplicação do SMOTE

[5174 5174]
Agora temos 10348 entradas
sendo 50% para Churn Sim e 50% para Churn Não

Construção do modelo

Agora que nossos dados já estão balanceados e devidamente preparados, vamos dar início ao processo de construção do nosso modelo que será responsável por prever se um cliente cancelará o serviço ou não.

Estamos lidando com um problema de classificação, então utilizaremos modelos que condizem com a nosso necessidade de classificar o Churn entre:

  • Sim
  • Não

Vamos utilizar 4 modelos de classificação para comparação e definir qual será o que possui o melhor desempenho dentre os 4 escolhidos.

Os modelos são:

  • Árvore de decisão
  • Regressão Logística
  • SVC (Support Vector Machine)
  • Floresta de decisão aleatória

A seguir, faremos as seguintes etapas:

  • Dividir nossos dados em treino e teste para que não ocorra overfitting
  • Normalizar os dados
  • Treinar os modelos
#1 importar modelos
dt = DecisionTreeClassifier()
lr = LogisticRegression()
svc = SVC()
rf = RandomForestClassifier()

names = ['Decision Tree', 'Logistic Regression', 'SVC', 'Random Forest']
classifiers = [dt, lr, svc, rf]

#4 separar entre treino e teste
X_train, X_test, y_train, y_test = train_test_split(X,y)


#4.1 normalizar os dados
scaler = StandardScaler()
scaler = scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)


#5 treinar modelo
model_dt = dt.fit(X_train, y_train)
model_lr = lr.fit(X_train, y_train)
model_svc = svc.fit(X_train, y_train)
model_rf = rf.fit(X_train, y_train)

Após treinarmos os modelos nos dados de treino, vamos verificar seu desempenho através de Cross-validation

Cross Validation dos Modelos: recall

Decision Tree tem recall de : 0.808 (+/- 0.02)

Logistic Regression tem recall de : 0.826 (+/- 0.03)

SVC tem recall de : 0.832 (+/- 0.03)

Random Forest tem recall de : 0.827 (+/- 0.03)


Cross Validation dos Modelos: Acurácia

Decision Tree tem acurácia de: 0.804 (+/- 0.01)

Logistic Regression tem acurácia de: 0.776 (+/- 0.01)

SVC tem acurácia de: 0.828 (+/- 0.01)

Random Forest tem acurácia de: 0.855 (+/- 0.01)

Os modelos Random Forest e SVC foram os que tiveram um melhor desempenho.

Agora, daremos início a parametrização para otimizar o modelo de Floresta de Decisão.

Tunning dos parâmetros

parametros = {'n_estimators': [10,15,20,30,50,75,100]}
parametros_d = {'max_depth': [5,7,10,15,20,30]}

grid_search = GridSearchCV(rf, parametros, scoring="recall")
clf = GridSearchCV(rf, parametros)
clf.fit(X_train, y_train)

# ver melhor parâmetro
print(clf.best_params_)
# ver todos parâmetros testados
means = clf.cv_results_['mean_test_score']
stds = clf.cv_results_['std_test_score']

for mean, std, params in zip(means, stds, clf.cv_results_['params']):
print("%0.3f (+/-%0.03f) for %r"
% (mean, std * 2, params))
grid_search = GridSearchCV(rf, parametros_d, scoring="recall")
clf = GridSearchCV(rf, parametros_d)
clf.fit(X_train, y_train)

# ver melhor parâmetro
print(clf.best_params_)
# ver todos parâmetros testados
means = clf.cv_results_['mean_test_score']
stds = clf.cv_results_['std_test_score']

for mean, std, params in zip(means, stds, clf.cv_results_['params']):
print("%0.3f (+/-%0.03f) for %r"
% (mean, std * 2, params))

Verificar o modelo parametrizado

                precision    recall  f1-score   support

0 0.87 0.84 0.86 1311
1 0.84 0.88 0.86 1276

accuracy 0.86 2587
macro avg 0.86 0.86 0.86 2587
weighted avg 0.86 0.86 0.86 2587

Recall: 0.875

Acurácia: 0.857

AUC: 0.858

Pronto! Nosso modelo está treinado e pronto para ser implementado na previsão de Churns! Na base de teste o modelo conseguiu prever corretamente 86% dos clientes que viriam a cancelar o serviço.

Conclusão

Além de aprender sobre Churn e o poder da retenção de clientes em uma empresa, conseguimos extrair informações valiosas do conjunto de dados.

Foi realizada a análise e o tratamento dos dados, bem como o ajuste das variáveis categóricas para que fosse possível treinar e implementar o modelo de machine learning.

Após o treinamento dos modelos, optamos utilizar o modelo de Random Forest, então, foi feito a otimização dos parâmetros do modelo.

Em seguida usamos o modelo treinado para fazer as previsões nos dados de teste, obtendo uma porcentagem de 86% para clientes que se tornariam Churn. Ainda há muitas otimizações que podem ser feitas, mas através desse projeto foi alcançado um excelente resultado, capaz de oferecer informações valiosas para a empresa, ajudado a mesma a atingir seu objetivo de reduzir a Churn Rate e aumentar a receita.

Obrigado !

--

--

Matheus Buniotto

Compartilho um pouco dos meus estudos e projetos com dados! Atualmente trabalho como analista de Dados e BI com foco em marketing e produto.