• João Ataide

Predição de evasão de clientes em empresas de telecomunicações

Atualizado: 20 de jun.


 

Empresas prestadoras de serviços de comunicações costumam usar análises das insatisfações de clientes, identificando sempre se seus clientes estão confirmados ou não, essas análises são umas das principais métricas para manter e adquirir novos compradores. Em geral, as empresas desses setores costumam ter agências de atendimento ao cliente, onde uma das suas principais tarefas é tentar reconquistar aqueles clientes perdidos, os quais podem custar muito mais do que os novos.


Devido a isso, as empresas investem em novas tecnologias para realizar essas análises, estas comummente utilizam-se do Churn rate, ou simplesmente Churn, uma das formas de medir essa taxa de evasão dos clientes. Além de identificar essa taxa de evasão, o Churn auxilia a identificar futuros cancelamentos, realizando uma predição que auxilia na tomada de decisão e promoção de ações diferenciadas para estes clientes. Uma aplicação cotidiana nossa, são nas empresas de streaming como Spotifly e Netflix.


Por ser uma métrica tão importante, o Carlos Melos no seu curso Data Science, na prática nos passou um desafio, implementar do zero uma solução de Churn para uma empresa de telecomunicação, utilizando-se de dados reais. Os dados utilizados neste projeto foram originalmente disponibilizados na plataforma de ensino da IBM Developer, tais dados tratam-se de um típico problema das companhias de telecomunicações, no qual pode ser visto o dataset completo neste link.


Os dados disponibilizados pela IBM não apresentam informações explícitas, mas por vantagem, os nomes das colunas permitem facilmente o entendimento do problema, como podemos constatar nas cinco primeiras entradas abaixo, a qual introduz um dataset de 7042 entradas com 21 colunas.



Como passo inicial para qualquer projeto de Data Science , uma boa análise exploratória é de suma importância. Desta maneira, realizei algumas das análises que achei mais importante, iniciando por uma avaliação dos valores únicos.


Nesta avaliação, foi possível notar que as camadas em questão apresentam em sua maioria mais de dois tipos de classificação, sendo necessário realizar alguns procedimentos mais a frente para alimentação do modelo. Outras avaliações foram necessárias, como: identificação de outliers, estatística descritiva dos dados e a presença de Bias (Vieses) .


Entretanto, a estatística descritiva e avaliação da presença de outliers não disse muita coisa. Assim, fiz uma verificação a camada Tenure, a qual representa o tempo que cada cliente utilizou o serviço, podendo mostrar a "fidelidade de serviço". Assumindo que a unidade de tempos da camada Tenure é em meses.



Note que, o tempo de serviço utilizado apresenta uma queda do primeiro mês para os demais, com uma subida nos últimos meses de 70 a 72, mas com uma certa normalidade dos dados. De todos os procedimentos citados anteriormente, darei destaque a presença de Bias, pois as demais não apresentaram resultados que possam comprometer o modelo.


Os vieses analisados foram das camadas: gender (gênero), Partner (parcerias) e Churn (Taxa de evasão), entretanto, somente a última apresentou um desbalanceamento comprometedor, sendo então necessário realizar o balanceamento, como você pode ver abaixo:



Já para as outras camadas, poderia utilizar os seus valores únicos como sendo a mesma coisa, em especial as de serviço. Mesmo esta hipótese ser completamente válida, para o trabalho aqui em questão irei utilizá-los como variáveis únicas.


Nesta etapa realizei algumas manipulações, para preparação dos dados para construção de um bom modelo. Primeiro realizar o pré-processamento, utilizando os algorítimos LabelEcoder e Getdummies, para transformar em variáveis binárias, deixando cada classe em uma camada com um valor numérico e diferente, como pode ver abaixo:


E então, podendo gerar nossa matriz de correlação dos dados.


Com tudo isso realizado, podemos dar início aos preprocessamentos e criando nossa métrica de desempenho. Para tal métrica utiliza como estimador de erro o método Cross-Validation, o qual já falei em outro artigo. Tal método associado a métrica do recall para descobrir qual melhor modelo para esse problema.


Então, para facilitar a avaliação dos modelos, defini uma função de validação:


#Função de validação

def valid(X, y, model, quite = False):

  X = np.array(X)
  y = np.array(y)
  pipeline = make_pipeline(StandardScaler(), model)
  scores = cross_val_score(pipeline, X, y, scoring="recall")

  if quite == False:
     print("Recall: {:.3f} (+/- {:.3f})".format(scores.mean(), scores.std()))

  return scores.mean()

A qual retorna o valor do recall e o score. Construindo então uma baseline de comparação, para parâmetro para avaliar que modelos utilizei.


#Criando linha base
rfc = RandomForestClassifier()
score_baseline = valid(X_treino, y_treino, rfc)

Resultando em Recall: 0.485 (+/- 0.022), essa técnica de validação foi baseada da Under Sampling, e seguindo recomendações de algumas literaturas, os dados serão padronizados antes de usar essa técnica de balanceamento, deixando claro que somente na base de treino.


Como não sei qual modelo apresentará o melhor resultado, realizarei a validação cruzada para os seguintes modelos:

  • Floresta aleatória

  • Árvores de Decisão

  • Gradiente Descendente Estocástico

  • SVC

  • Regressão Logística

  • LightGBM

Foi necessário então instancia-lo e configura-los segundo o algorítimo abaixo:

#Instanciar os modelos
rc = RandomForestClassifier()
ad = DecisionTreeClassifier()
gde = SGDClassifier()
svc = SVC()
rl = LogisticRegression()
xgb = XGBClassifier()
lgbm = LGBMClassifier()
#Criar lista para resultados
modelo = []
recall = []
#Avaliar desempenho
for clf in (rc, ad, gde, svc, rl, xgb, lgbm):
  modelo.append(clf.__class__.__name__)
  recall.append(valid(X_treino_rus, y_treino_rus, clf, quite = True))

Recall = pd.DataFrame(data = recall, index=modelo, columns=["Recall"])

Gerando o seguinte resultado,

Podemos ver nos resultados, ressaltaram-se os resultados dos modelos XGBoost, Regressão Logística e SVC. Em que, tiveram os suas instâncias em default. Com isso, pegarei o melhor modelo anterior (XGBoost) e modificarei seus parâmetros procurando o melhor resultado possível, onde você pode encontra no projeto completo.


Avaliando algumas estruturas do XGboost, encontrei o melhor resultado como:

#Modelo Final
xgb=XGBClassifier(learning_rate=0.001,n_estimators=50,max_depth=1,min_child_weight=1,gamma=0.0)xgb.fit(X_treino_rus,y_treino_rus)

Resultando os seguintes valores de previsão:

E a Matriz de confusão:

Resultando então em um excelente modelo, com 0.89 dos dados Verdadeiros Positivos e 0.57 verdadeiros negativos, com uma ASC de 0.72.


Neste projeto, trabalhamos em um problema de previsão de churn em que o objetivo principal era construir um modelo de aprendizado de máquina capaz de identificar corretamente os maiores números de possíveis clientes que envasaram. Para tanto, foi necessário realizar diversos procedimentos como balanceamento e padronização, testando diversos modelos para obter o melhor resultado, assim chegando a um modelo de XGboost com um excelente resultado.