IT & Engineering

Machine learning para tarefas do dia a dia

Costuma-se pensar que o machine learning é complexo demais para as tarefas de desenvolvimento do dia a dia. É comum associá-lo a conceitos como big data, mineração de dados, ciência de dados e inteligência artificial. Às vezes, a sensação é mais ou menos assim:
Imagem para Machine learning para tarefas do dia a dia

Costuma-se pensar que o machine learning é complexo demais para as tarefas de desenvolvimento do dia a dia. É comum associá-lo a conceitos como big data, mineração de dados, ciência de dados e inteligência artificial. Às vezes, a sensação é mais ou menos assim:

A brain made up of electrical points

Machine learning é difícil

Sempre achei que podemos nos beneficiar do uso do machine learning em tarefas simples que realizamos regularmente.

Exemplo da vida real

No Mailgun, trabalhamos com e-mail e, como parte da nossa oferta, fazemos a análise de citações em HTML. Isso permite capturar a última resposta em vez de toda a conversa, que é retornada como parte da resposta do nosso webhook. Você pode ler mais sobre como lidamos com o processamento de mensagens de entrada em nosso documentação.

Para quem não sabe, é assim que funciona a análise de HTML da internet pública:

Dirty Jeep stuck in the mud

Análise de HTML da internet pública

É confuso e, às vezes, os processos ficam travados.

Mudar a biblioteca de análise pode ajudar, mas não resolverá o problema completamente, pois toda biblioteca tem suas limitações. É necessário restringir a análise a algo razoável.

Análise de clusters como solução

Mas quais devem ser os critérios e o limite? Devemos limitar pelo tamanho do HTML ou pela contagem de tags? Talvez ambos? Talvez por outra coisa? O objetivo, obviamente, é processar o máximo de mensagens possível sem dar um tiro no próprio pé, mas o caminho não é tão óbvio.

É aí que a análise de clusters e a classificação estatística se tornam úteis. Para a pesquisa, usei &nbsp, mas, dependendo da sua tarefa e das preferências pessoais, você pode usar outra coisa – scikit-learnWekaMOA, etc.

Coletar um conjunto de dados

Primeiro, registramos o tamanho do HTML, a contagem de tags, o tempo de processamento da mensagem e os colocamos em um arquivo CSV:

                                

                                    htmllen,tagscount,took rn2893762,85527,34.300139904 rn31378,518,0.0368919372559 rn19105,413,0.0545339584351 rn...
                                
                            

A grande maioria das mensagens leva frações de segundo para ser processada. Portanto, ao coletar o conjunto de dados, precisávamos garantir que teríamos mensagens “lentas” suficientes.

Acabamos com dois arquivos CSV, coletados em dias diferentes. Um tinha 13.831 linhas e foi reservado para análise e treinamento de modelo (o conjunto de dados de treino). Outro tinha 12.149 linhas e foi reservado para a validação do modelo (o conjunto de dados de validação).

Geralmente, você quer ter pelo menos dois conjuntos de dados – um para treino e outro para validação. Caso contrário, você pode enfrentar o problema de overfitting, quando o modelo se ajusta bem aos dados de treino, mas falha no mundo real.

Determinar o número de clusters

Para visualizar os dados e procurar padrões, a clusterização k-means foi a primeira tentativa:

                                

                                    messages <- read.csv(file="messages080816.csv", sep=",", head=TRUE) rn    mydata <- matrix(messages$took, ncol=1) rnrn    ## Determine the number of clusters rn    wss <- (nrow(mydata)-1)*sum(apply(mydata,2,var)) rn    for (i in 2:15) wss[i] <- sum(kmeans(mydata, rn        centers=i)$withinss) rn    plot(1:15, wss, type="b", xlab="Number of Clusters", rn        ylab="Within groups sum of squares")
                                
                            

Como você pode ver, há uma melhoria significativa no desempenho com até 4 clusters. Depois disso, não há um ganho real.

Clusterização

A próxima etapa foi descobrir como os pontos de dados são distribuídos entre os clusters:

                                

                                     ## K-Means Clustering with 4 clustersrn    fit <- kmeans(mydata, 4) rnrn    ## Cluster Plot against 1st 2 principal components rn    ## vary parameters for most readable graph rn    library(cluster) rn        clusplot(mydata, fit$cluster, color=TRUE,rn           shade=TRUE, labels=2, lines=0)
                                
                            
A clusplot graph

E você já pode antecipar um pouco o problema: os clusters se formam isolando os pontos de dados que estão distantes, enquanto o intervalo que nos interessa (1 a 20 s) fica bem no meio. O problema persiste com o aumento do número de clusters.

Além disso, há uma sobreposição significativa entre os clusters no intervalo:

                                

                                     ## get clusters mean, min, max rn    mean <- aggregate(mydata,by=list(fit$cluster),FUN=mean) rn    min <- aggregate(mydata,by=list(fit$cluster),FUN=min) rn    max <- aggregate(mydata,by=list(fit$cluster),FUN=max)
                                
                            
A list of clusters code

Compare os clusters 1 e 4. O problema persiste com o aumento do número de clusters.

Nesse ponto, decidimos tentar uma abordagem diferente e observar os percentis do tempo de processamento das mensagens:

                                

                                     percentiles <- quantile(messages$took, seq(0.5, 0.99, 0.01)) rn    plot(seq(0.5, 0.99, 0.01), percentile)
                                
                            
A graph of percentiles

Como você pode ver, após o percentil 78, o tempo de processamento sobe rapidamente. Aqui estava nosso primeiro limite: o percentil 78, que correspondia a 6,5 segundos.

Todos os pontos de dados que levaram menos de 6,5 s foram marcados como “rápidos” e os demais como “lentos”.

Classificação

Para a classificação, testamos o SVM (Máquinas de Vetores de Suporte), Random Forests e CART(Árvore de Classificação e Regressão).

O CART apresentou resultados ligeiramente melhores para essa tarefa, mas sua principal vantagem é que ele gera uma árvore de decisão fácil de entender, explicar e implementar, em comparação com o SVM ou as Random Forests, que funcionam como uma caixa-preta e exigem o uso de bibliotecas pesadas de ML na produção.

Veja como você classifica usando o CART:

                                

                                    x <- subset(messages, select=-took) rnlibrary(rpart) rnrn# grow tree rnfit <- rpart(x$cls ~., method="class", data=x) rnrn## display the results rnprintcp(fit)rnrn# detailed summary of splits rnsummary(fit) rnrn# plot tree rnplot(fit, uniform=TRUE, rn    main="Classification Tree for message processing time") rntext(fit, use.n=TRUE, all=TRUE, cex=.8) 
                                
                            

Aqui está a árvore de decisão:

Classification tree for message processing time

E é assim que fica a implementação:

                                

                                    def html_too_big(s): rn    return s.count('<') > _MAX_TAGS_COUNT
                                
                            

Não é lindo? Toda a complexidade da pesquisa em uma única linha!

Validação

Para a avaliação, pegamos o conjunto de dados de validação e tentamos prever a classificação usando o nosso modelo:

                                

                                     validate <- read.csv(file="messages080916.csv", sep=",", head=TRUE) rn    validate <- subset(validate, select=-took) rn    xv <- subset(validate, select=-cls) rn    y <- predict(fit, xv, type="class") rn    table(validate$cls, y)
                                
                            

Aqui está a matriz de confusão e algumas métricas comuns de classificação:

Evaluation code

Lições aprendidas

O machine learning não é apenas para cientistas de dados. Mesmo decisões simples impulsionadas por ML podem beneficiar você. Conheça seus dados. Não confie cegamente em modelos e algoritmos científicos.

Divirta-se com o machine learning e a mineração de dados!