Pessoal, primeiramente, gostaria de dizer que é uma honra poder postar no dia do meu aniversário e falando de um tema tão interessante, pelo menos para um Cientista de Dados que trabalha com combate à corrupção: a famosa #LavaJato! Pois é, hoje vou aproveitar o conhecimento do meu último post para buscar tweets sobre a Lava Jato e mostrar como fazer uma simples nuvem de palavras para tentar entender o que está sendo discutido nas redes sociais.

Bom, quando comecei a escrever esse post (início da noite do dia 12/04/2017), um dos Trend Topics no Twitter era a hashtag #LavaJato, imagino que todos saibam o motivo. Por isso, comecei a noite buscando mil tweets sobre o tema para fazermos nossa primeira nuvem de palavras. Vamos relembrar como fazer?

Além de criar uma conexão com a API do Twitter (veja o último post para mais detalhes), a principal parte do código que precisei alterar foi a seguinte:

tema <- "#LavaJato"
quantidade.de.tweets <- 1000
lingua <- "pt"
tweets <- searchTwitter(tema, n=quantidade.de.tweets, lang=lingua)

Com esses mil tweets em mãos, começamos agora o trabalho de criar nossa nuvem de palavras. No entanto, antes de criar a nuvem propriamente dita, temos que trabalhar nosso texto para remover palavras indesejadas, links, entre outras coisas que não nos interessam acrescentar/ver na nuvem. Ah! Antes que me esqueça! O código que apresentarei aqui é uma adaptação de mais uma mega super hiper pesquisa avançada (#sqn) no Google, que nesse caso me trouxe os seguintes links: um tutorial sobre nuvem de palavras propriamente dito e outro tutorial sobre grafo de palavras [more on that later] que fala um pouco mais sobre pré-processamento de tweets, ambos do Gaston Sanchez, excelente Cientista de Dados e Professor da UC Berkeley.

Agora vamos ao que interessa?! Então vamos lá! Hoje, além dos pacotes twitterR e ROAuth que usamos na semana passada, vamos precisar dos pacotes tm (para contar a frequência de palavras por tweet), wordcloud (para desenhar a nuvem de palavras) e RColorBrewer (para recuperar um conjunto “interessante” de cores para usar na nuvem). Vejamos então como instalar e carregar esses pacotes:

install.packages('tm')
install.packages('wordcloud')
install.packages('RColorBrewer')
library(tm)
library(wordcloud)
library(RColorBrewer)

Agora vamos recuperar os textos de cada tweet. Aqui vamos basicamente usar a função sapply (que é tipo um for) para recuperar o texto (função getText) de cada tweet (que é o x dentro do sapply).

textos = sapply(tweets, function(x) x$getText())

Vamos dar uma curiada no conteúdo desses tweets? Que tal analisar as primeiras 10 ocorrências?

textos[1:10]
 [1] "Delação da Odebrecht: deputado João Paulo Papa é suspeito de receber repasses que totalizam R$ 600 mil… https://t.co/A9KhODDY0H"             
 [2] "RT @bhuoriescaussoy: A pergunta que não quer calar. Cadê os políticos honestos deste país? Isso é uma vergonha! #LavaJato https://t.co/T7vO…"
 [3] "RT @g1: Delação da Odebrecht: deputado José Carlos Aleluia é suspeito de corrupção passiva e ativa https://t.co/QkG7Dhw0lv #LavaJato #G1 ht…"
 [4] "Aprendi hoje com as revelações da #LavaJato que numa mochila cabem de 2 a 3 milhões de reais dependendo da cédula que for usada."            
 [5] "@dilmabr e @gleisi são exemplos brasileiros de mulheres empoderadas.\n\n#DomF #Odebrecht #lavajato"                                          
 [6] "RT @deltanmd: Diogo Castor: #LavaJato faz faxina no BR, mas Curitiba continua c quintal sujo - casos d corrupção acabaram em pizza https://…"
 [7] "E aehhh ? @Srta_Iozzi ??? #monicaiozzi #lavajato #moro #sergiomoro #dallagnol #euapoioalavajato https://t.co/zDXjVJ7gyz"                     
 [8] "RT @LariiAlmeid: Ex presidentes, atual e futuros candidatos a presidência todos sujos na lava jato. Como é Q faz agora ? #LavaJato #ListaDo…"
 [9] "RT @cartacapital: Chegamos ao naufrágio, o Brasil afunda\n#ListadoFachin #Odebrecht #LavaJato #DiretodaRedação https://t.co/ikjvc5Gxj1"      
[10] "Queria ser citada nessas delações da #Odebrecht precisava de milhões não... Só unzinho tava bão #lavaJato #lulanacadeia"     

Como vocês podem ver, temos algumas informações de retweets (RT @g1:), outras sobre usuários do Twitter (@dilmabr e @gleisi), algumas pontuações em excesso (???) e vários links (https://t.co/A9KhODDY0H), que para nosso objetivo de entender quais são as principais palavras mencionadas nos tweets, podem não fazer muito sentido. Por isso, nosso próximo passo é exatamente remover esses termos desnecessários (para nossa nuvem de palavras). Vejam como:

textos_tratados = textos
# remove entidades de retweets
textos_tratados = gsub("(RT|via)((?:\\b\\W*@\\w+)+)", "", textos_tratados)
# remove usuários do Twitter
textos_tratados = gsub("@\\w+", "", textos_tratados)
# remove pontuações
textos_tratados = gsub("[[:punct:]]", "", textos_tratados)
# remove links
textos_tratados = gsub("http\\w+", "", textos_tratados)

Vamos ver como ficaram os textos agora?

textos_tratados[1:10]
 [1] "Delação da Odebrecht deputado João Paulo Papa é suspeito de receber repasses que totalizam R 600 mil "                         
 [2] " A pergunta que não quer calar Cadê os políticos honestos deste país Isso é uma vergonha LavaJato "                            
 [3] " Delação da Odebrecht deputado José Carlos Aleluia é suspeito de corrupção passiva e ativa  LavaJato G1 ht"                    
 [4] "Aprendi hoje com as revelações da LavaJato que numa mochila cabem de 2 a 3 milhões de reais dependendo da cédula que for usada"
 [5] " e  são exemplos brasileiros de mulheres empoderadas\n\nDomF Odebrecht lavajato"                                               
 [6] " Diogo Castor LavaJato faz faxina no BR mas Curitiba continua c quintal sujo  casos d corrupção acabaram em pizza "            
 [7] "E aehhh    monicaiozzi lavajato moro sergiomoro dallagnol euapoioalavajato "                                                   
 [8] " Ex presidentes atual e futuros candidatos a presidência todos sujos na lava jato Como é Q faz agora  LavaJato ListaDo"        
 [9] " Chegamos ao naufrágio o Brasil afunda\nListadoFachin Odebrecht LavaJato DiretodaRedação "                                     
[10] "Queria ser citada nessas delações da Odebrecht precisava de milhões não Só unzinho tava bão lavaJato lulanacadeia"  

Ficou um pouco menos poluído, né? Provavelmente, ao ver o resultado, você já tenha pensado em outros tipos de tratamento. No entanto, para o post de hoje, vamos nos preocupar com apenas mais um: colocar tudo em letra minúscula para considerar LavaJato e lavaJato, por exemplo, como a mesma coisa! Aqui nós encontraremos um dos principais nightmares de quem trabalha com esses textos de Internet, a codificação da língua (encoding), como o uso de acentos. Ao tentar transformar tudo em letra minúscula, às vezes dá algum erro por conta dessa codificação. Por isso, vou mostrar como criar uma função alternativa que só transforma em minúsculo quando dá e quando dá erro, simplesmente ignora. Não se preocupem com essa função! Vou colocar aqui apenas para vocês poderem usar, mas o objetivo não é explicar como ela funciona (pelo menos não nesse post!), ok? Então aí vai a nova função para transformar tudo em minúsculo:

tryTolower = function(x)
{
   # cria um dado faltante
   y = NA
   # faz o tratamento do erro
   try_error = tryCatch(tolower(x), error=function(e) e)
   # se não der erro, transforma em minúsculo
   if (!inherits(try_error, "error"))
      y = tolower(x)
   # retorna o resultado
   return(y)
}

Agora é só usar a função e ver o resultado! Vamos lá?

## Usa a função que criamos
textos_tratados = sapply(textos_tratados, tryTolower)
## Remove o nome que foi criado para cada elemento da lista de textos
names(textos_tratados) = NULL
## Remove textos vazios, se existir algum
textos_tratados = textos_tratados[textos_tratados != ""]
## Apresenta o resultado final dos 10 primeiros textos
textos_tratados[1:10]
 [1] "delação da odebrecht deputado joão paulo papa é suspeito de receber repasses que totalizam r 600 mil "                         
 [2] " a pergunta que não quer calar cadê os políticos honestos deste país isso é uma vergonha lavajato "                            
 [3] " delação da odebrecht deputado josé carlos aleluia é suspeito de corrupção passiva e ativa  lavajato g1 ht"                    
 [4] "aprendi hoje com as revelações da lavajato que numa mochila cabem de 2 a 3 milhões de reais dependendo da cédula que for usada"
 [5] " e  são exemplos brasileiros de mulheres empoderadas\n\ndomf odebrecht lavajato"                                               
 [6] " diogo castor lavajato faz faxina no br mas curitiba continua c quintal sujo  casos d corrupção acabaram em pizza "            
 [7] "e aehhh    monicaiozzi lavajato moro sergiomoro dallagnol euapoioalavajato "                                                   
 [8] " ex presidentes atual e futuros candidatos a presidência todos sujos na lava jato como é q faz agora  lavajato listado"        
 [9] " chegamos ao naufrágio o brasil afunda\nlistadofachin odebrecht lavajato diretodaredação "                                     
[10] "queria ser citada nessas delações da odebrecht precisava de milhões não só unzinho tava bão lavajato lulanacadeia" 

Bom, está na hora de quebrar esses tweets em termos (ou palavras) e contar quantas vezes cada termo (palavra) aparece no tweet. Para isso, nós vamos usar algumas funções do pacote tm, mas não se preocupem! Por enquanto, façam o famoso copy and paste e apenas saibam que estamos criando uma matriz (uma espécie de tabela) de termos por documento (ou palavras por tweets). A única coisa importante que quero destacar nesse código é que vamos remover algumas palavras “inúteis”, que chamamos de stopwords, como “de”, “para”, “da”, etc. Vejam o código:

termo_por_documento = as.matrix(TermDocumentMatrix(Corpus(VectorSource(textos_tratados)),
                                control = list(stopwords = c(stopwords("portuguese")))))

Vamos agora dar uma olhada no conteúdo dessa matriz para entender melhor o que foi feito. Vejam que é bem simples, na verdade. Essa matriz mostra que o termo (palavra) “delação”, por exemplo, apareceu uma vez no documento (tweet) 1 e uma no 3, como pode ser conferido nos textos apresentados acima. Tranquilo, né?! 😀

## Apresentar apenas os primeiros 10 termos (linhas) com os primeiros 10 documentos (colunas)
termo_por_documento[1:10,1:10]
           Docs
Terms       1 2 3 4 5 6 7 8 9 10
  600       1 0 0 0 0 0 0 0 0  0
  delação   1 0 1 0 0 0 0 0 0  0
  deputado  1 0 1 0 0 0 0 0 0  0
  joão      1 0 0 0 0 0 0 0 0  0
  mil       1 0 0 0 0 0 0 0 0  0
  odebrecht 1 0 1 0 1 0 0 0 1  1
  papa      1 0 0 0 0 0 0 0 0  0
  paulo     1 0 0 0 0 0 0 0 0  0
  receber   1 0 0 0 0 0 0 0 0  0
  repasses  1 0 0 0 0 0 0 0 0  0

Como nós não estamos preocupados com a frequência dos termos (palavras) por documento (tweet) e sim dentro de todo o conjunto de documentos (tweets) que estamos analisando, precisamos fazer essa contagem, que no caso, é apenas somar quantas vezes cada termo (palavra) apareceu em cada documento (tweet), ou seja, somar todos os números linha a linha. Vamos lá?

## Recupera a frequência de cada termo ao somar cada linha e coloca em ordem decrescente
frequencia_dos_termos = sort(rowSums(termo_por_documento), decreasing=TRUE) 

## Cria uma tabela com o termo (palavra) e sua respectiva frequência 
tabela = data.frame(termo=names(frequencia_dos_termos), frequencia=frequencia_dos_termos) 

Finalmente podemos desenhar nossa nuvem de palavras! Antes disso, vamos só tomar um cuidado: como nós pesquisamos por tweets que tinham a hashtag #lavajato, esse termo será o mais frequente pois estará presente em todos tweets. No entanto, isso é óbvio e atrapalha a visualização do que importa, que é saber quais são as principais palavras mencionadas em tweets que falam sobre a #lavajato (fora a própria palavra lavajato, é claro!). Logo, vamos primeiro remover esse termo (palavra) de nossa tabela e aí sim vamos desenhar a nuvem de palavras usando o pacote wordcloud e usando diferente cores, dependendo da frequência de cada termo (palavra), com o pacote RColorBrewer.

## Remove o termo mais frequente (lavajato)
tabela = tabela[-1,]
## Desenha a nuvem de palavras
wordcloud(tabela$termo, tabela$frequencia, random.order=FALSE, colors=brewer.pal(8, "Dark2"))

Pronto, aí está sua primeira (ou não) nuvem de palavras feita do zero e usando apenas o R! Se você chegou até aqui, parabéns! Se não, espero que tenha passado para alguém da equipe de TI da sua instituição! rs Quem sabe no próximo post eu não mostro como agrupar essas palavras de tal forma que fique mais fácil entender os principais assuntos (e não só palavras) que estão sendo discutidos nesses diversos tweets?! Até lá!

Editado no dia 13/04/2017 às 18:10: Valeu por ter encontrado o bug no código, @augustofilhote. Mudei de:

frequencia_dos_termos = sort(rowSums(m), decreasing=TRUE) 

Para:

frequencia_dos_termos = sort(rowSums(termo_por_documento), decreasing=TRUE)