-
Notifications
You must be signed in to change notification settings - Fork 3
/
webscraping_tutorial07.Rmd
227 lines (162 loc) · 7.43 KB
/
webscraping_tutorial07.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# Tutorial 7 - Análise de texto no R - pacote _tidytext_
## Uma abordagem "tidy" para texto
Corpora são os objetos clássicos para processamento de linguagem natural. No R, porém, há uma tendência a deixar tudo "tidy". Vamos ver uma abordagem "tidy", ou seja, com data frames no padrão do _tidyverse_, para texto.
Vamos fazer uma rápida introdução, mas recomendo fortemente a leitura do livro [Text Mininig with R](http://tidytextmining.com/), disponível o formato "bookdown".
Comecemos carregando os seguintes pacotes:
```{r}
library(tidytext)
library(dplyr)
library(ggplot2)
library(tidyr)
```
Vamos recriar o data frame com os discursos:
```{r}
discursos_df <- data_frame(id_discurso = 1:length(discursos),
text = discursos)
glimpse(discursos_df)
```
### Tokens
A primeira função interessante do pacote _tidytext_ é justamente a tokenização de um texto:
```{r}
discursos_token <- discursos_df %>%
unnest_tokens(word, text)
glimpse(discursos_token)
```
Note que a variável _id\_discurso, criada por nós, é mantida. "text", porém, se torna "words", na exata sequência do texto. Veja que o formato de um "tidytext" é completamnte diferente de um Corpus.
Como excluir stopwords nessa abordagem? Precisamos de um data frame com stopwords. Vamos recriar um vetor stopwords_pt, que é a versão ampliada das stopwords disponíveis no R, e criar um data frame com tal vetor:
```{r}
stopwords_pt <- c(stopwords("pt"), "presidente", "é", "sr", "sra", "luiza",
"erundina", "oradora", "revisão", "sp", "v.exa")
stopwords_pt_df <- data.frame(word = stopwords_pt)
```
Com _anti\_join_ (lembra dessa função?) mantemos em "discursos\_token" apenas as palavras que não estao em "stopwords\_pt\_df"
```{r}
discursos_token <- discursos_token %>%
anti_join(stopwords_pt_df, by = "word")
```
Para observarmos a frequência de palavras nos discursos, usamos _count_, do pacote _dplyr_:
```{r}
discursos_token %>%
count(word, sort = TRUE)
```
Com _ggplot_, podemos construir um gráfico de barras dos temos mais frequêntes, por exemplo, com frequência maior do que 500. Neste ponto do curso, nada do que estamos fazendo abaixo deve ser novo a você:
```{r}
discursos_token %>%
count(word, sort = TRUE) %>%
filter(n > 500) %>%
mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n)) +
geom_col() +
xlab(NULL) +
coord_flip()
```
Incorporando a função _wordcloud_ a nossa análise:
```{r}
discursos_token %>%
count(word, sort = TRUE) %>%
with(wordcloud(word, n, max.words = 50))
```
A abordagem "tidy" para texto nos mantém no território confortável da manipulação de data frames e, particularmente, me parece mais atrativa do que a abordagem via Corpus para um conjunto grande de casos.
### Bigrams
Já produzimos duas vezes a tokenização do texto, sem, no entanto, refletir sobre esse procedimento. Tokens são precisam ser formados por palavras únicas. Se o objetivo for, por exemplo, observar a ocorrência conjunta de termos, convém trabalharmos com bigrams (tokens de 2 palavras) ou ngrams (tokens de n palavras). Vejamos como:
```{r}
discurso_bigrams <- discursos_df %>%
unnest_tokens(bigram, text, token = "ngrams", n = 2)
```
Note que, ao tokenizar o texto, automaticamente foram excluídas as as pontuações e as palavras foram alteradas para minúscula (use o argumento "to_lower = FALSE" caso não queira a conversão). Vamos contar os bigrams:
```{r}
discurso_bigrams %>%
count(bigram, sort = TRUE)
```
Como, porém, excluir as stopwords quando elas ocorrem em bigrams? Em primeiro, temos que separar os bigrams e duas palavras, uma em cada coluna:
```{r}
bigrams_separated <- discurso_bigrams %>%
separate(bigram, c("word1", "word2"), sep = " ")
```
E, a seguir, filter o data frame excluindo as stopwords (note que aproveitamos o vetor "stopwords_pt"):
```{r}
bigrams_filtered <- bigrams_separated %>%
filter(!word1 %in% stopwords_pt) %>%
filter(!word2 %in% stopwords_pt)
```
ou, usando _anti\_join_, como anteriormente:
```{r}
bigrams_filtered <- bigrams_separated %>%
anti_join(stopwords_pt_df, by = c("word1" = "word")) %>%
anti_join(stopwords_pt_df, by = c("word2" = "word"))
```
Produzindo a frequência de bigrams:
```{r}
bigram_counts <- bigrams_filtered %>%
count(word1, word2, sort = TRUE)
```
Reunindo as palavras do bigram que foram separadas para excluirmos as stopwords:
```{r}
bigrams_united <- bigrams_filtered %>%
unite(bigram, word1, word2, sep = " ")
```
A abordagem "tidy" traz uma tremenda flexibilidade. Se, por exemplo, quisermos ver com quais palavras a palavra "poder" é antecedida:
```{r}
bigrams_filtered %>%
filter(word2 == "poder") %>%
count(word1, sort = TRUE)
```
Ou precedida:
```{r}
bigrams_filtered %>%
filter(word1 == "poder") %>%
count(word2, sort = TRUE)
```
Ou ambos:
```{r}
bf1 <- bigrams_filtered %>%
filter(word2 == "poder") %>%
count(word1, sort = TRUE) %>%
rename(word = word1)
bf2 <- bigrams_filtered %>%
filter(word1 == "poder") %>%
count(word2, sort = TRUE) %>%
rename(word = word2)
bind_rows(bf1, bf2) %>%
arrange(-n)
```
Super simples e legal, não?
### Ngrams
Repetindo o procedimento para "trigrams":
```{r}
discursos_df %>%
unnest_tokens(trigram, text, token = "ngrams", n = 3) %>%
separate(trigram, c("word1", "word2", "word3"), sep = " ") %>%
anti_join(stopwords_pt_df, by = c("word1" = "word")) %>%
anti_join(stopwords_pt_df, by = c("word2" = "word")) %>%
anti_join(stopwords_pt_df, by = c("word3" = "word")) %>%
count(word1, word2, word3, sort = TRUE)
```
"sociedade civil organizada" é o "trigram" mais frequente no discurso da deputada.
### Redes de palavras
Para encerrar, vamos a um dos usos mais interessantes do ngrams: a construção de redes de palavras. Precisaremos de dois novos pacotes, _igraph_ e _ggraph_. Instale-os se precisar:
```{r}
library(igraph)
library(ggraph)
```
Em primeiro lugar, transformaremos nosso data frame em um objeto da classe _igraph_, do pacote de mesmo nome, usado para a presentação de redes no R:
```{r}
bigram_graph <- bigram_counts %>%
filter(n > 20) %>%
graph_from_data_frame()
```
A seguir, com o pacote _ggraph_, faremos o grafo a partir dos bigrams dos discursos da deputada:
```{r}
ggraph(bigram_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)
```
Note que são formadas pequenas associações entre termos que, par a par, caminham juntos. Novamente, não vamos explorar aspectos analíticos da mineração de texto, mas estas associações são informações de grande interessa a depender dos objetivos da análise.
## Para além do tutorial
No tutorial, vimos o básico da preparação de textos para mineração, como organizar um Corpus e criar tokens. Além disso, vimos várias utilidades do pacote _stringr_, que serve para além da mineração de texto e pode ser útil na organização de bases de dados que contém variáveis "character".
Se houver tempo em sala de aula e você quiser se aprofundar no assunto, leia alguns dos capítulos de [Text Mininig with R](http://tidytextmining.com/):
- [Capítulo 2 - Análise de Sentimento (com textos em inglês)](http://tidytextmining.com/sentiment.html)
- [Capítulo 3 - Análise de frequência de palavras](http://tidytextmining.com/tfidf.html)
- [Capítulo 4 - Relacionamento entre palavras, n-gramas e correlação](http://tidytextmining.com/ngrams.html)
- [Capítulo 6 - Topic Modeling](http://tidytextmining.com/topicmodeling.html)