Introdução

O TalkingData é a maior plataforma de big data da China, ela chega a cobrir cerca de 70% de todos os dispositivos móveis ativos do país. Ela dispõe de diversos serviços para a população. Por ser de grande porte o risco de fraude é alto, o que pode acarretar em um prejuizo financeiro considerável. Este trabalho vai se basear em um caso específico, de download de aplicativos. Funciona da seguinte maneira, um usuário pode anunciar seu aplicativo através da plataforma digital, e ele só recebe retorno financeiro da empresa de acordo com os acessos obtidos. A fraude pode ocorrer quando o usuário, em busca de ter um lucro maior, cria um meio de seu aplicativo receber um grande número de visitas, mas sem realmente instalar o aplicativo.

Objetivo

O objetivo do trabalho é a detecção de possiveis fraudes do ‘TalkingData’, com base no histórico de informações fornecindas. Portanto, o desafio inicial é a criação de um algoritmo que consiga prever a possibilidade do usuário fazer o download depois de clicar em um anúncio do aplicativo para dispositivos móveis.

Metodologia

Em busca de solucionar o problema, serão utilizadas ferramentas capazes de fazer uma estimação precisa e segura com big data. O método de estimação consiste em utilizar maior parte dos dados para aprendizado e a parte restante para validação. Onde a métrica a ser utilizada é a Área sob a Curva ROC, mais comumente chamada de AUC. As técnicas a serem utilizadas serão:

Área sob a Curva ROC (AUC)

Essa é uma das métricas mais utilizadas quando o assunto é a previsão de modelos através de Machine Learning. A Curva ROC é expressa através de vários pontos de corte, onde em cada um deles é visto o quanto o modelo acertou com relação ao “sucesso” (Sensibilidade) e quanto acertou com relação ao “fracasso” (Especificidade), e o melhor ponto de corte é determinado pelo ponto que maximiza os valores de sensibilidade e especificidade. O interesse é que quanto maior a curva, ou seja, o quão mais próximo de 1, maior será o poder de previsão do modelo.
A referência de precisão utilizada para identificar se o modelo tem a capacidade de identificar corretamente uma fraude usando curva ROC, é medida por:

  • Acima de 0,9 — Excelente

  • 0,8 – 0,9 — Bom

  • 0,7 – 0,8 — Regular

  • 0,6 – 0,7 — Ruim

  • 0,5 – 0,6 — Péssimo

Regressão Logística

O modelo de regressão logística se assemelha ao modelo de regressão linear, a principal diferença entre eles é que no modelo logístico a variável resposta assume apenas valores dicotômicos, simbolizando “sucesso” ou “fracasso”, ou seja, 0 ou 1. Portanto a variável resposta segue uma distribuição binomial, \(( Y_i \sim B(m_i,\pi_i))\) Com função densidade de probabilidade:

\[P[Y_i=y_i]=\binom{m_i}{y_i}\pi_i^{y_i}(1-\pi_i)^{m_i-y_i}.\] Onde:

\(m_i\) é o número de ensaios;

\(y_i\) número de ocorrência de um evento em \(m_i\) ensaios; e

\(n\) é o tamanho da amostra.

A função de ligação que geralmente é utilizada para deixar o valor da resposta semelhante ao modelo linear, é a função logito e pode ser expressada através da fórmula:

\[\pi(x_i)=\frac{e^{\beta_0+\beta_1x_i}}{1+e^{\beta_0+\beta_1x_i}},\, i=1, \ldots, n,\] que também pode ser escrita como :

\[\ln\left(\frac {\pi_i} {1 - \pi_i}\right)= \beta_0+\beta_1x_i.\]

Gradiente Boosting Machine (GBM)

O Gradiente Boosting é uma técnica de maching learn utilizada para resolver problemas e regressão e classificação. Também pode ser utilizada para fazer predições, essa técnica baseia-se nas árvores de decisão, ou seja, observa por vários meios diferentes o comportamento dos dados em determinadas regiões para assim conseguir obter padrões coerentes que facilitam na hora de fazer a previsão de um valor.

Extreme Gradiente Boosting (XGB)

A técinica de XGB, se trata de uma versão que garante o aumento do Gradiente, implicando em uma versão de que aprimora as técnicas de árvore de decisão tornando a precisão do modelo maior quanto o poder de previsão. Esse método também busca reduzir o tempo de estimação e a memória utilizada pela máquina.

Validação Cruzada

A validação cruzada é uma técnica que pode ser utilizada para fazer uma espécie de generalização do modelo a partir de uma base de dados. Um dos principais objetivos dessa técnica é fazer a modelagem dos dados, afim de ser feita uma predição mais precisa. O método utilizado para fazer o particionamento dos dados é o \(método\) \(k-fold\) que consiste em dividir os dados em, por exemplo, k subconjuntos de mesmo tamanho e iguais proporções, fazendo k interações entre elas e utilizando sempre k-1 partes para treinar o modelo, ou seja, observar o comportamento dos dados e “aprender” com isso, e deixando a parte restante para validação, podendo assim medir se a estimação dos parâmetros está coerente.

Variáveis Originiais:

VAOr <- data.frame(Variável=c("ip", "app", "device", "os", "channel", "click_time", "attributed_time", "is_attributed"),
                   Descrição = c("Endereço ip de clique", "id do aplicativo para marketing", "id tipo de dispositivo do telefone móvel do usuário (por exemplo, iphone 6 plus, iphone 7, huawei mate 7, etc.)", "id da versão do telefone celular do usuário", "ID do canal do editor de anúncios para celular", "timestamp de clique (UTC)", "se o usuário fizer o download do aplicativo depois de clicar em um anúncio, essa é a hora do download do aplicativo", " o alvo a ser previsto, indicando que o aplicativo foi baixado" ))

kable(VAOr) %>%
  kable_styling(bootstrap_options = "striped", full_width = F)
Variável Descrição
ip Endereço ip de clique
app id do aplicativo para marketing
device id tipo de dispositivo do telefone móvel do usuário (por exemplo, iphone 6 plus, iphone 7, huawei mate 7, etc.)
os id da versão do telefone celular do usuário
channel ID do canal do editor de anúncios para celular
click_time timestamp de clique (UTC)
attributed_time se o usuário fizer o download do aplicativo depois de clicar em um anúncio, essa é a hora do download do aplicativo
is_attributed o alvo a ser previsto, indicando que o aplicativo foi baixado

Variáveis Calculadas:

Em busca de um melhor resultado, foram criadas algumas variáveis tendo como base as variáveis fornecidas inicialmente pelo desafio.

VACriada <- data.frame(Variáveis = c("Hora_cont","Dia", "App_2", "App_3 ", "App_9 ", "App_12 ",  "App_15 ", "OutrosApp", "Device0", "Device1", "Device2", "Device3032", "Device3543",  "Outrosdevice"),
                       Descrição = c("Valor contínuo da hora em que o aplicativo foi acessado", "Dia em que o aplicativo foi acessado", "Flag para indicar quando o aplicativo 2 foi acessado", "Flag para indicar quando o aplicativo 3 foi acessado", "Flag para indicar quando o aplicativo 9 foi acessado", "Flag para indicar quando o aplicativo 12 foi acessado", "Flag para indicar quando o aplicativo 15 foi acessado", "Flag para indicar quando outros aplicativos exceto os informados acima, foram acessados", "Flag para indicar o id do celular = 0 utilizado para acessar o aplicativo", "Flag para indicar o id do celular = 1 utilizado para acessar o aplicativo", "Flag para indicar o id do celular = 2 utilizado para acessar o aplicativo", "Flag para indicar id do celular = 3032 utilizado para acessar o aplicativo", "Flag para indicar id do celular = 3543 utilizado para acessar o aplicativo", "Flag para indicar que foi utilizado um celular com outro numero de id para acessar o aplicativo" ))


kable(VACriada) %>%
  kable_styling(bootstrap_options = "striped", full_width = F)
Variáveis Descrição
Hora_cont Valor contínuo da hora em que o aplicativo foi acessado
Dia Dia em que o aplicativo foi acessado
App_2 Flag para indicar quando o aplicativo 2 foi acessado
App_3 Flag para indicar quando o aplicativo 3 foi acessado
App_9 Flag para indicar quando o aplicativo 9 foi acessado
App_12 Flag para indicar quando o aplicativo 12 foi acessado
App_15 Flag para indicar quando o aplicativo 15 foi acessado
OutrosApp Flag para indicar quando outros aplicativos exceto os informados acima, foram acessados
Device0 Flag para indicar o id do celular = 0 utilizado para acessar o aplicativo
Device1 Flag para indicar o id do celular = 1 utilizado para acessar o aplicativo
Device2 Flag para indicar o id do celular = 2 utilizado para acessar o aplicativo
Device3032 Flag para indicar id do celular = 3032 utilizado para acessar o aplicativo
Device3543 Flag para indicar id do celular = 3543 utilizado para acessar o aplicativo
Outrosdevice Flag para indicar que foi utilizado um celular com outro numero de id para acessar o aplicativo

Frequência relativa da variável ip

knitr::opts_chunk$set(echo = TRUE)


# Esse comando deixa a tabela ocupando a folha toda

 #Dados_TRN %>% group_by(ip) %>% count() %>% arrange(-n) %>% ungroup() %>%  top_n(20) %>% kable() %>%
  #kable_styling(bootstrap_options = c("striped", "hover", "condensed"))

# Esse comando comprime os espaços
 Dados_TRN %>% group_by(ip) %>% count() %>% arrange(-n) %>% ungroup() %>%  top_n(20) %>% kable() %>%
  kable_styling(bootstrap_options = "striped", full_width = F)
ip n
5348 669
5314 616
73487 439
73516 399
53454 280
114276 219
26995 218
95766 205
17149 186
100275 173
105475 167
105560 149
111025 137
43793 135
86767 134
137052 128
5178 117
49602 116
48170 112
48282 112

A tabela acima mostra os 20 endereços de ip que obtiveram uma maior frequência de acessos nesse período analisado. Com isso é visto que o endereço de ip referente a 5348 foi o mais acessado, totalizando 669 click’s.

Frequência relativa da variável Data

knitr::opts_chunk$set(echo = TRUE)

 VA_DATA <- data.frame(Data =c("06/11/2017", "07/11/2017", "08/11/2017",  "09/11/2017 " ),
                       Frequência =c(5011, 32393, 34035, 28561) )
   
 
 

VA_DATA %>%
    ggplot(aes(x = Data, y= Frequência)) +
    geom_bar(stat = "identity",fill="#003366", colour="black") +
guides(fill = "none") + #tirou a legenda
    labs(x = "Data", y = "Frequência", title = "Frequência dos dias de acesso") 

A base de dados utilizada contém informações apenas entre as datas de 06/11/2017 a 09/11/2017. Como pode ser visto no gráfico os dias que relataram maior frequência de acesso foram os dias 07/11/2017 e 08/11/2017, apresentando respectivameente 32393 e 34035 click’s.

Frequência do risco de Fraude

knitr::opts_chunk$set(echo = FALSE)


TopFraude <- Dados_TRN_4 %>% group_by(is_attributed) %>% count() %>% arrange(-n) %>%  ungroup() 


TopFraude %>%
    ggplot(aes(x = reorder(is_attributed, -n), y= n)) +
    geom_bar(stat = "identity",fill="#003366", colour="black") +
guides(fill = "none") + #tirou a legenda
    labs(x = "Número do Aplicativo", y = "Frequência", title = "Frequência dos 10 aplicativos mais acessados") +
   geom_label(aes(label = paste(round(n), sep = "")))

Sabendo que a fraude é definida pelo número 1, e como pode ser visto no gráfico acima a proporção de fraude é muito mais baixa com relação a não fraude, representando apenas 2% de toda a base.

Frequência relativa da variável app

Vários id’s de aplicativos são encontrados na base de dados, o gráfico acima é referente aos 10 aplicativos que obtiveram mais acesso, através dele é possivel ver que o aplicativo cujo id = 3 é o que possui um número de acessos superior aos demais, com 18279 click’s esse é o número de aplicativo que mais se destaca com relação a frequência.

Frequência dos Aplicativos com relação ao risco de Fraude

knitr::opts_chunk$set(echo = FALSE)


Top10_App_F <- Dados_TRN_4 %>% filter(app == 3 | app == 12 | app == 2 |app == 9 | app == 3 |app == 18 |app == 14 |app == 1 |app == 13 |app == 8)

Top10_App_F$app = as.factor(Top10_App_F$app)
Fraude <- as.factor(Top10_App_F$is_attributed)

ggplot(Top10_App_F, aes(x=app, fill=Fraude)) +
  geom_bar(position = position_dodge(), colour="black")+
 labs(x = "Sobrevivencia", y = "Contagem", title = "Frequência sobre Satisfação", color = "Satisfação") +
  labs(x = "Número do Aplicativo", y = "Frequência", title = "Frequência dos 10 aplicativos mais acessados")

Dentre os 10 aplicativos mais acessados, os aplicativos que apresentaram um risco de fraude são dados pelos id’s referente aos números 12, 18, 3, 8 e 9.

Frequência relativa da variável device

knitr::opts_chunk$set(echo = TRUE)

Top10_Device <- Dados_TRN_4 %>% group_by(device) %>% count() %>% ungroup() %>%  arrange(-n) %>%  top_n(10, n)




#barplot(Top10_Device$n,names.arg = Top10_Device$device, main = "Frequência dos 10 id's de telefone mais utilizados", ylab = "Frequência", xlab = "Número do Aplicativo", ylim = c(0, 95000))


Top10_Device %>%
    ggplot(aes(x = reorder(device, -n), y= n)) +
    geom_bar(stat = "identity",fill="#003366", colour="black") +
guides(fill = "none") + #tirou a legenda
    labs(x = "Número do ID", y = "Frequência", title = "Frequência dos 10 id's de telefone mais utilizados")  +
    geom_label(aes(label = paste(round(n), sep = "")))

Através do gráfico acima é possivel ver que id de celular utilizado com mais frequência na realização dos click’s é dado pelo id = 1, esse tipo de dispositivo móvel representa cerca de 94% da base, totalizando 94338 click’s. Ou seja, 94% dos acessos feitos através de dispositivo móvel foi a partir de um dispositivo cujo id é representado pelo número 1.

Frequência dos Devices com relação ao risco de Fraude

knitr::opts_chunk$set(echo = FALSE)


Top10_device_F <- Dados_TRN_4 %>% filter(device == 1 | device == 2 | device == 0 |device == 3032 | device == 3543 |device == 3866 |device == 59 |device == 6 |device == 16 |device == 40)

Top10_device_F$device = as.factor(Top10_device_F$device)
Fraude <- as.factor(Top10_device_F$is_attributed)

ggplot(Top10_device_F, aes(x=device, fill=Fraude)) +
  geom_bar(position = position_dodge(), colour="black")+
 labs(x = "Sobrevivencia", y = "Contagem", title = "Frequência sobre Satisfação", color = "Satisfação") +
  labs(x = "Número do ID", y = "Frequência", title = "Frequência dos 10 id's de telefone mais utilizados")

Observando os dez números de id’s referentes ao tipo do celular é possível observar que todos eles apresentam risco de fraude.

Desenvolvimento

A base de treinamento será dividida em duas partes tais que, uma conterá 80% de toda a base, chamada de base de treinamento, e a outra conterá os 20% restantes, a qual será chamada de base de validação. O objetivo é fazer um ajuste do modelo, estimando os parâmetros através da base de treinamento e para confirmar se o modelo está fazendo uma previsão correta será utilizada a base de validação para comparar respostas. A métrica utilizada para avaliar o poder de predição dos modelos será dada através valor da AUC, ou seja, a área sob a curva ROC. O modelo que apresentar maior valor de AUC, será considerado o melhor modelo, implicando um maior poder de predição.

Regressão Logística

Ajustando o modelo de regressão logística, onde a variável resposta é is_attributed e as variáveis que se mostraram estatisticamente significativas para o modelo, são: Dia, App_2, App_3, App_9, App_12, App_15, OutrosApp, Device0, Device1, Device2, Device3032, Device3543 e Outrosdevice.

Com base nisso é possível ajustar modelo completo e um reduzido apenas com as variáveis significativas e assim buscar um modelo com melhor previsão. Sendo:

\(Y_i\) = is_attributed;

\(X_1\) = Dia;

\(X_2\) = App_2;

\(X_3\) = App_3;

\(X_4\) = App_9;

\(X_5\) = App_12;

\(X_6\) = App_15;

\(X_7\) = OutrosApp;

\(X_8\) = Device0;

\(X_9\) = Device1;

\(X_{10}\) = Device2;

\(X_{11}\) = Device3032;

\(X_{12}\) = Device3543;

\(X_{13}\) = Outrosdevice;

\(\epsilon_i\) = Erro associado.

Uma proposta inicial para o modelo pode ser representado como:

\(Y_i = \beta_1 X_1 + \beta_2 X_2 + \beta_3 X_3 + \beta_4 X_4 + \beta_5 X_5 + \beta_6 X_6 + \beta_7 X_7 + \beta_8 X_8 + \beta_9 X_9 + \beta_{10} X_{10} + \beta_{11} X_{11} + \beta_{12} X_{12} + \beta_{13} X_{13} + \epsilon_i\)

onde,

\(p_i = \frac 1 { 1 + exp ^ -{\beta_1 X_1 + \beta_2 X_2 + \beta_3 X_3 + \beta_4 X_4 + \beta_5 X_5 + \beta_6 X_6 + \beta_7 X_7 + \beta_8 X_8 + \beta_9 X_9 +\beta_{10} X_{10} + \beta_{11} X_{11} + \beta_{12} X_{12} + \beta_{13} X_{13} + \epsilon_i }}\)

Modelo Reduzido

Após varios testes, e combinações de parâmetros o modelo que apresentou uma melhor previsão é dado por:

\(Y_i = \beta_1 X_1 +\beta_2 X_2 +\beta_3 X_3 +\beta_4 X_4 + \beta_5 X_5 +\beta_6 X_6 +\beta_7 X_7 +\beta_8 X_8 +\beta_9 X_9 +\beta_{10} X_{10} +\beta_{11}X_{11} +\beta_{12} X_{12} +\beta_{13} X_{13} + \epsilon_i\)

knitr::opts_chunk$set(echo = TRUE)


Ajuste_Reduzido_Base_TRN_80 <- glm(is_attributed ~  Hora_Cont + Dia + Device2 + App_3 + Device1 + App_12 +
                                     App_15 + App_9 + OutrosApp - 1
                                   ,data = Base_TRN_80, family=binomial(link="logit")) 
knitr::opts_chunk$set(echo = TRUE)

roc_curve(resultado,truth, estimate) %>% 
 ggplot(aes(x = 1 - specificity, y = sensitivity)) +
  geom_path() +
  geom_abline(lty = 3) +
  coord_equal() +
  annotate("text", x=0.35, y=0.65, label= "AUC = 0.86") +
  ggtitle( "Curva ROC - Regressão Logística")

Para o modelo ajustado, que foi apresentado foi encontrado um valor de \(AUC = 0.86\) o que pode ser considerado como sendo uma boa predição do modelo. Já a matriz de confusão tem a finalidade de identificar o quanto o modelo confundiu uma classe com outra, como por exemplo quantos casos ele acertou quem realmente é fraude ou disse que era fraude, dado que não era uma fraude. O ideal é minimizar ao máximo confundimento do modelo. Com base nisso é possível admitir que a medida que o modelo se torna mais acertivo, aumenta o valor de \(AUC\) a ser obtido.

Gradiente Boosting

Na tentativa de melhorar a acertividade do modelo, foi utilizado um método conhecido como Gradiente Boosting, onde serão utilizadas as mesmas bases do modelo anterior, com a diferença que o modelo agora será ajustado utilizando essa nova metodologia.

knitr::opts_chunk$set(echo = TRUE)

roc_curve(resultado_gbm,truth_gbm, estimate_gbm) %>%  #Gráfico da Curva ROC
ggplot(aes(x = 1 - specificity, y = sensitivity)) +
  geom_path() +
  geom_abline(lty = 3) +
  coord_equal() +
  annotate("text", x=0.38, y=0.65, label= "AUC = 0.86") +
  ggtitle( "Curva ROC - Gradiente Boosting")

Através do ajuste a partir do Gradiente Boosting é observado um valor de \(AUC = 0.86\), ou seja, é possível concluir que o valor da área sob a curva ROC é a mesma para ambos os casos, implicando consistencia no modelo.

Importância das Variáveis

O gráfico acima mostra a importância das variáveis utilizadas nesse modelo, de forma decrescente. Através desse gráfico é possível destacar a variável Device0 como sendo a variável que possui maior importância, seguida de Outrosdevice e OutrosApp, ou seja, elas apresentam uma maior contribuição para o resultado da predição.

Extreme Gradient Boosting (XGB)

knitr::opts_chunk$set(echo = TRUE)

roc_curve(resultado_xgb,truth_xgb, estimate_xgb) %>% #Gráfico da Curva ROC%>% 
 ggplot(aes(x = 1 - specificity, y = sensitivity)) +
  geom_path() +
  geom_abline(lty = 3) +
  coord_equal() +
  annotate("text", x=0.35, y=0.65, label= "AUC = 0.86") +
  ggtitle( "Curva ROC - XGB")

Ajustando o modelo através do Extreme Gradiente Boosting é observado um valor de \(AUC = 0.86\), ou seja, é possível concluir que o valor da área sob a curva ROC permanece igual, implicando consistencia no modelo.

Validação Cruzada

knitr::opts_chunk$set(echo = TRUE)

roc_curve(resultado_cv,truth_cv, estimate_cv) %>% #Gráfico da Curva ROC
ggplot(aes(x = 1 - specificity, y = sensitivity)) +
  geom_path() +
  geom_abline(lty = 3) +
  coord_equal() +
  annotate("text", x=0.38, y=0.65, label= "AUC = 0.87") +
  ggtitle( "Curva ROC - Validação Cruzada")

Ajustando o modelo através do método de Validação Cruzada pode ser observado um valor de \(AUC = 0.87\), ou seja, é possível notar um pequeno aumento no valor da área sob a curva roc o que pode implicar que esse método pode ser um pouco mais preciso em termos de previsão.

Comparação entre os Modelos

knitr::opts_chunk$set(echo = TRUE)

Mod_RL <- roc_curve(resultado,truth, estimate)
Mod_RL$Modelo <- "Reg Logística"


Mod_GB <- roc_curve(resultado_gbm,truth_gbm, estimate_gbm)
Mod_GB$Modelo <- "GBM"

Mod_XGB <- roc_curve(resultado_xgb,truth_xgb, estimate_xgb)
Mod_XGB$Modelo <- "XGB"

Mod_CV <- roc_curve(resultado_cv,truth_cv, estimate_cv)
Mod_CV$Modelo <- "CV"



base <- bind_rows(Mod_RL, Mod_GB) %>% bind_rows(Mod_XGB) %>% bind_rows(Mod_CV)
base %>% ggplot(aes(x = 1 - specificity, y = sensitivity, color = Modelo)) +
geom_path() +
geom_abline(lty = 3) +
coord_equal() +
ggtitle( "Curva ROC - Comparação dos Modelos")

A previsão do modelo é semelhante independente do método utilizado, isso é um bom sinal pois implica que o poder de predição do modelo é consistente, ou seja, qualquer técnica utilizada trará bons resultados. Entretanto como visto anteriormente a previsão através da “Validação cruzada” teve um pequeno aumento no valor da AUC, o que pode tornar essa técnica como sendo considerada a melhor para esse problema de detecção de fraude.

Referências Bibliográficas