-
Notifications
You must be signed in to change notification settings - Fork 187
/
Copy pathquickstart_ja.Rmd
443 lines (329 loc) · 19.3 KB
/
quickstart_ja.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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
---
title: "クイック・スタートガイド"
output:
html_document:
toc: true
---
```{r, echo = FALSE}
knitr::opts_chunk$set(collapse = FALSE, comment = "##")
```
本ページは[Quick Start Guide](../quickstart.html)の日本語訳であり,英語のテキスト分析を通じて**quanteda**の基本的な使い方を説明する.日本語の分析法に関しては,以下のページを参照.
* [事例: 衆議院外務委員会の議事録](examples/japanese_speech_ja.html)
* [事例: 2017年総選挙に関するツイート](examples/japanese_twitter_ja.html)
# パッケージのインストール {#installing-the-package}
**quanteda**は[CRAN](https://CRAN.R-project.org/package=quanteda)からインストールできる.GUIのRパッケージインストーラを使用してインストールするか,次のコマンドを実行する.
```{r, eval = FALSE}
install.packages("quanteda")
```
GitHubから最新の開発バージョンをインストールする方法については,https://github.com/quanteda/quanteda を参照.
## インストールが推奨されるパッケージ {#additional-recommended-packages}
**quanteda**には連携して機能を拡張する一連のパッケージがあり,それらをインストールすることが推奨される.
* [**readtext**](https://github.com/quanteda/readtext):多くの入力形式からテキストデータをRに簡単に読み込むパッケージ
* [**spacyr**](https://github.com/kbenoit/spacyr):Pythonの[spaCy](https://spacy.io)ライブラリを使用した自然言語解析のためのパッケージで,品詞タグ付け,固有表現抽出,および係り受け関係の解析などができる
* [**quanteda.corpora**](https://github.com/quanteda/quanteda.corpora):**quanteda**の本記事内の説明で使用する追加のテキストデータ
```{r eval = FALSE}
devtools::install_github("quanteda/quanteda.corpora")
```
* [**LIWCalike**](https://github.com/kbenoit/quanteda.dictionaries): [Linguistic Inquiry and Word Count](http://liwc.wpengine.com) (LIWC) アプローチによるテキスト分析のR実装
```{r eval = FALSE}
devtools::install_github("kbenoit/quanteda.dictionaries")
```
# コーパスの作成 {#creating-a-corpus}
まず,**quanteda**を読み込んで,パッケージの関数とデータにアクセスできるようにする.
```{r, message = FALSE}
library(quanteda)
```
## 利用可能なコーパス {#currently-available-corpus-sources}
**quanteda**にはテキストを読み込むためのシンプルで強力なパッケージ,[**readtext**](https://github.com/kbenoit/readtext)があります.このパッケージの`readtext()`は,ローカス・ストレージやインターネットからファイル読み込み,`corpus()`にデータ・フレームを返す.
`readtext()`で利用可能なファイルやデータの形式:
* テキスト(`.txt`)ファイル
* コンマ区切り値(`.csv`)ファイル
* XML形式のデータ
* JSON形式のFacebook APIのデータ
* JSON形式のTwitter APIのデータ
* 一般的なJSONデータ
**quanteda**のコーパスを生成する関数である `corpus()`は,以下の種類のデータを読み込むことができる.
* 文字列ベクトル(例:**readtext**以外のツールを使用して読み込んだテキスト)
* **tm**パッケージの `VCorpus`コーパスオブジェクト
* テキスト列と他の文書に対応したメタデータを含むデータ・フレーム
### 文字列からコーパスを作成 {#building-a-corpus-from-a-character-vector}
コーパスを作成する最も簡単な方法は,`corpus()`を用いて,すでにRに読み込まれた文字列ベクトル作成することである.文字列ベクトルをRに取り込む方法はさまざまなので,高度なRユーザーは,コーパスをいろいろな方法で作り出せる.
次の例では,**quanteda**パッケージに含まれているイギリスの政党が2010年の総選挙のために発行したマニフェストのテキストデータ(`data_char_ukimmig2010`)からコーパスを作成している.
```{r}
corp_uk <- corpus(data_char_ukimmig2010) # テキストからコーパスを作成
summary(corp_uk)
```
コーパスを作成したあとでも,`docvars`を用いると,必要に応じて文書に対応した変数をこのコーパスに追加することができる.
たとえば,Rの`names()`関数を使って文字ベクトル(`data_char_ukimmig2010`)の名前を取得し,これを文書変数(`docvar()`)に追加することができる.
```{r}
docvars(corp_uk, "Party") <- names(data_char_ukimmig2010)
docvars(corp_uk, "Year") <- 2010
summary(corp_uk)
```
### readtextパッケージを用いたファイルの読み込み {#loading-in-files-using-the-readtext-package}
```{r, eval=FALSE}
require(readtext)
# Twitter json
dat_json <- readtext("~/Dropbox/QUANTESS/social media/zombies/tweets.json")
corp_twitter <- corpus(dat_json)
summary(corp_twitter, 5)
# generic json - needs a textfield specifier
dat_sotu <- readtext("~/Dropbox/QUANTESS/Manuscripts/collocations/Corpora/sotu/sotu.json",
textfield = "text")
summary(corpus(dat_sotu), 5)
# text file
dat_txtone <- readtext("~/Dropbox/QUANTESS/corpora/project_gutenberg/pg2701.txt", cache = FALSE)
summary(corpus(dat_txtone), 5)
# multiple text files
dat_txtmultiple1 <- readtext("~/Dropbox/QUANTESS/corpora/inaugural/*.txt", cache = FALSE)
summary(corpus(dat_txtmultiple1), 5)
# multiple text files with docvars from filenames
dat_txtmultiple2 <- readtext("~/Dropbox/QUANTESS/corpora/inaugural/*.txt",
docvarsfrom = "filenames", sep = "-",
docvarnames = c("Year", "President"))
summary(corpus(dat_txtmultiple2), 5)
# XML data
dat_xml <- readtext("~/Dropbox/QUANTESS/quanteda_working_files/xmlData/plant_catalog.xml",
textfield = "COMMON")
summary(corpus(dat_xml), 5)
# csv file
write.csv(data.frame(inaug_speech = texts(data_corpus_inaugural),
docvars(data_corpus_inaugural)),
file = "/tmp/inaug_texts.csv", row.names = FALSE)
dat_csv <- readtext("/tmp/inaug_texts.csv", textfield = "inaug_speech")
summary(corpus(dat_csv), 5)
```
## コーパスオブジェクトの使い方 {#how-a-quanteda-corpus-works}
### コーパスの原理 {#corpus-principles}
**quanteda**のコーパスは,元の文書をユニコード(UTF-8)に変換し,文書に対するメタデータと一緒に格納しすることで、ステミングや句読点の削除などの処理よって変更されないテキストデータの静的な保管庫になるように設計されている.これによって,コーパスから文書を抽出して新しいオブジェクトを作成した後でも,コーパスには元のデータが残り,別の分析を,同じコーパスを用いて行うことができる.
コーパスから文書を取り出すためには,`as.character()`と呼ばれる関数を使用する.
```{r}
as.character(data_corpus_inaugural)[2]
```
`summary()`により,コーパス内のテキストの要約を行うことができる.
```{r}
data(data_corpus_irishbudget2010, package = "quanteda.textmodels")
summary(data_corpus_irishbudget2010)
```
`summary()`の出力をデータ・フレームとして保存し,基本的な記述統計を描画することができる.
```{r, fig.width = 8}
tokeninfo <- summary(data_corpus_inaugural)
if (require(ggplot2))
ggplot(data = tokeninfo, aes(x = Year, y = Tokens, group = 1)) +
geom_line() +
geom_point() +
scale_x_continuous(labels = c(seq(1789, 2017, 12)), breaks = seq(1789, 2017, 12)) +
theme_bw()
# Longest inaugural address: William Henry Harrison
tokeninfo[which.max(tokeninfo$Tokens), ]
```
## コーパスに対する操作 {#tools-for-handling-corpus-objects}
### コーパスの結合 {#adding-two-corpus-objects-together}
`+`演算子を用いると,簡単に二個のコーパスを連結できます.コーパスが異なる構造を持つ場合でも,文書変数が失われることはなく,コーパスのメタデータも引き継がれる.
```{r}
library(quanteda)
corp1 <- corpus(data_corpus_inaugural[1:5])
corp2 <- corpus(data_corpus_inaugural[53:58])
corp3 <- corp1 + corp2
summary(corp3)
```
### コーパスから文書を抽出 {#subsetting-corpus-objects}
`corpus_subset()`により,文書変数に適用される論理条件に基づいて文書を抽出することができる.
```{r}
summary(corpus_subset(data_corpus_inaugural, Year > 1990))
summary(corpus_subset(data_corpus_inaugural, President == "Adams"))
```
## コーパス内の文書の探索 {#exploring-corpus-texts}
`kwic()`(keywords-in-context)は単語の検索を行い,その単語が現れる文脈を表示する.
```{r}
toks <- tokens(data_corpus_inaugural)
kwic(toks, pattern = "terror")
```
```{r}
kwic(toks, pattern = "terror", valuetype = "regex")
```
```{r}
kwic(toks, pattern = "communist*")
```
上記の要約では,"Year"と"President"は各文書に結び付けられた変数であり,`docvars()`によってそれらにアクセスできる.
```{r}
head(docvars(data_corpus_inaugural))
```
[**quanteda.corpora**](https://github.com/quanteda/quanteda.corpora)をインストールすることで,より多くのコーパスを試すことができる.
# コーパスから特長を抽出 {#extracting-features-from-a-corpus}
文書のスケーリングなどの統計分析を行うためには,それぞれの文書の特長をまとめた行列を作成する必要があり,**quanteda**では,このような行列を生成するために `dfm()`を使いる. dfmは*document-feature matrix*の略で,行が文書(document),列が特長(feature)となる行列である.行と列をこのように定義する理由は,データ分析では行が分析単位になり,各列が分析対象になる変数となるのが一般的だからである.多くのソフトウェアでは,この行列を*document-term matrix*と呼ぶが,**quanteda**が語(term)でなはく特長(feature)という用語を使うのは,特長のほうが一般性を持つからで,テキスト分析では,単語,語幹,単語の集合,Nグラム,品詞など様々なものが文書の特長となる.
## 文書のトークン化 {#tokenizing-texts}
テキストを簡単にトークン化するために,**quanteda**は `tokens()`と呼ばれる強力なコマンドを提供する.この関数は,文字ベクトルのトークンのリストからなるオブジェクトを生成する.このオブジェクトでは,リストの一つ一つの要素は入力された文書に対応している.
`tokens()`は保守的に設計されており、ユーザーが明示的に指示を与えないかぎりは,要素を削除しない.
```{r}
txt <- c(text1 = "This is $10 in 999 different ways,\n up and down; left and right!",
text2 = "@kenbenoit working: on #quanteda 2day\t4ever, http://textasdata.com?page=123.")
tokens(txt)
tokens(txt, remove_numbers = TRUE, remove_punct = TRUE)
tokens(txt, remove_numbers = FALSE, remove_punct = TRUE)
tokens(txt, remove_numbers = TRUE, remove_punct = FALSE)
tokens(txt, remove_numbers = FALSE, remove_punct = FALSE)
tokens(txt, remove_numbers = FALSE, remove_punct = FALSE, remove_separators = FALSE)
```
また,`tokens()`には個々の文字をトークン化するオプションもある.
```{r}
tokens("Great website: http://textasdata.com?page=123.", what = "character")
tokens("Great website: http://textasdata.com?page=123.", what = "character",
remove_separators = FALSE)
```
もしくは,一文ごとにトークン化するオプションもある.
```{r}
# sentence level
tokens(c("Kurt Vongeut said; only assholes use semi-colons.",
"Today is Thursday in Canberra: It is yesterday in London.",
"En el caso de que no puedas ir con ellos, ¿quieres ir con nosotros?"),
what = "sentence")
```
## 文書行列の作成 {#constructing-a-document-feature-matrix}
データからすぐに文書行列を作成したい場合は、`dfm()`に直接文字列ベクトルもしくはコーパスを渡すと、自動的にトークン化が行われ。`dfm()`は、デフォルトで大文字から小文字への置換や,句読点を除去などの操作を適用する.また,`dfm()`から`tokens()`の全てのオプションを利用できる.
```{r}
corp_inaug_post1990 <- corpus_subset(data_corpus_inaugural, Year > 1990)
# make a dfm
dfmat_inaug_post1990 <- dfm(tokens(corp_inaug_post1990))
dfmat_inaug_post1990[, 1:5]
```
以下の例では`dfm()`の追加のオプションを用いて、ストップワードの削除(`remove`)と語のステミング(`stem`)を行っている.
```{r}
# make a dfm, removing stopwords and applying stemming
dfmat_inaug_post1990 <- tokens(corp_inaug_post1990, remove_punct = TRUE) |>
tokens_remove(stopwords("english")) |>
tokens_wordstem() |>
dfm()
dfmat_inaug_post1990[, 1:5]
```
`remove`によって,文書行列から除外するトークンを指定する.`stopwords()`は,幾つかの言語で定義されたストップワードのリストを返す.
```{r}
head(stopwords("en"), 20)
head(stopwords("ru"), 10)
head(stopwords("ar", source = "misc"), 10)
```
### 文書行列の表示 {#viewing-the-document-feature-matrix}
RStudioの"Environment"パネル,またはRの`View()`を用いることで,dfmに格納された値を見ることができる.
```{r fig.width = 8, fig.height = 8}
dfmat_uk <- data_char_ukimmig2010 |>
tokens(remove_punct = TRUE) |>
tokens_remove(stopwords("english")) |>
dfm()
dfmat_uk
```
頻度が最も高い特長を見るには,`topfeatures()`を用いる.
```{r}
topfeatures(dfmat_uk, 20) # 20 most frequent words
```
dfmを`textplot_wordcloud()`に渡すことで,ワードクラウドを描画できる.この関数は,オブジェクトや引数を**wordcloud**パッケージの`wordcloud()`に渡すので,ワードクラウドの表示を変更できる.
```{r warning=FALSE, fig.width = 7, fig.height = 7}
set.seed(100)
library("quanteda.textplots")
textplot_wordcloud(dfmat_uk, min_count = 6, random_order = FALSE,
rotation = .25,
color = RColorBrewer::brewer.pal(8, "Dark2"))
```
### 変数による文書のグループ化 {#grouping-documents-by-document-variable}
**quanteda**では,dfmを作成する際に,文書変数の値によって文書をグループ化するすることができる.
```{r}
dfmat_ire <- tokens(data_corpus_irishbudget2010, remove_punct = TRUE) |>
tokens_remove(stopwords("en")) |>
tokens_group(groups = party) |>
dfm()
```
また、以下のように,dfmを語の頻度順に並べ替えて,中身を確かめられる.
```{r}
dfm_sort(dfmat_ire)[, 1:10]
```
### 辞書による語のグループ化 {#grouping-words-by-dictionary-or-equivalence-class}
キーワードがあらかじめ分かっている場合,`dictionary()`によって辞書を作成し、語の出現回数を測定できる。次の例では,テロリズムに関連する言葉や経済に関連する言葉が,クリントン以降の大統領演説でどのように異なるかを示している.
```{r}
corp_inaug_post1991 <- corpus_subset(data_corpus_inaugural, Year > 1991)
```
テロリズムと経済という2つのリストからなる辞書を作成する.
```{r}
dict <- dictionary(list(terror = c("terrorism", "terrorists", "threat"),
economy = c("jobs", "business", "grow", "work")))
```
文書行列を作成するときに,この辞書を`dfm()`の`dictionary`に渡す.
```{r}
dfmat_inaug_post1991_dict <- tokens(corp_inaug_post1991) |>
tokens_lookup(dict) |>
dfm()
dfmat_inaug_post1991_dict
```
`dictionary()`は,LIWCやWordstatなどの一般的な辞書ファイルを読み込むことができる.以下では,LIWCの辞書を大統領就任演説に適用している.
```{r, eval = FALSE}
dictliwc <- dictionary(file = "~/Dropbox/QUANTESS/dictionaries/LIWC/LIWC2001_English.dic",
format = "LIWC")
dfmat_inaug_subset <- dfm(data_corpus_inaugural[52:58], dictionary = dictliwc)
dfmat_inaug_subset[, 1:10]
```
# 追加の事例 {#further-examples}
## 文書の類似性 {#similarities-between-texts}
```{r fig.width = 6}
dfmat_inaug_post1980 <- data_corpus_inaugural |>
corpus_subset(Year > 1980) |>
tokens(remove_punct = TRUE) |>
tokens_remove(stopwords("english")) |>
tokens_wordstem() |>
dfm()
library("quanteda.textstats")
tstat_obama <- textstat_simil(dfmat_inaug_post1980,
dfmat_inaug_post1980[c("2009-Obama", "2013-Obama"), ],
margin = "documents", method = "cosine")
tstat_obama
# dotchart(as.list(tstat_obama)$"2009-Obama", xlab = "Cosine similarity")
```
上記の文書間の類似性から樹形図を作成して,大統領を階層的に分類することができる.
```{r, fig.width = 10, fig.height = 7, eval = TRUE}
data_corpus_sotu <- readRDS(url("https://quanteda.org/data/data_corpus_sotu.rds"))
dfmat_sotu <- data_corpus_sotu |>
corpus_subset(Date > as.Date("1980-01-01")) |>
tokens(remove_punct = TRUE) |>
tokens_remove(stopwords("english")) |>
tokens_wordstem() |>
dfm()
dfmat_sotu <- dfm_trim(dfmat_sotu, min_termfreq = 5, min_docfreq = 3)
# hierarchical clustering - get distances on normalized dfm
library("quanteda.textstats")
tstat_dist <- textstat_dist(dfm_weight(dfmat_sotu, scheme = "prop"))
# hiarchical clustering the distance object
pres_cluster <- hclust(as.dist(tstat_dist))
# label with document names
pres_cluster$labels <- docnames(dfmat_sotu)
# plot as a dendrogram
plot(pres_cluster, xlab = "", sub = "",
main = "Euclidean Distance on Normalized Token Frequency")
```
文書間と同様に用語間の類似性も測定できる.
```{r}
tstat_sim <- textstat_simil(dfmat_sotu, dfmat_sotu[, c("fair", "health", "terror")],
method = "cosine", margin = "features")
lapply(as.list(tstat_sim), head, 10)
```
## 文書のスケーリング {#scaling-document-positions}
**quanteda**には多数のテキスト分析のためのモデルが含まれている.ここでは,ワードフィッシュ(`textmodel_wordfish()`)による教師なしの文書のスケーリングを2010年のアイルランドの予算討論の分析に用いている.
```{r}
library("quanteda.textmodels")
dfmat_ire <- dfm(tokens(data_corpus_irishbudget2010))
tmod_wf <- textmodel_wordfish(dfmat_ire, dir = c(2, 1))
# plot the Wordfish estimates by party
textplot_scale1d(tmod_wf, groups = docvars(dfmat_ire, "party"))
```
## トピックモデル {#topic-models}
`convert()`を用いると,dfmを**topicmodels**の`LDA()`形式のデータに転換し,簡単にトピックモデルを適用できる.
```{r}
dfmat_ire2 <- data_corpus_irishbudget2010 |>
tokens(remove_punct = TRUE, remove_numbers = TRUE) |>
tokens_remove(stopwords("english")) |>
tokens_wordstem() |>
dfm()
dfmat_ire2 <- dfm_trim(dfmat_ire2, min_termfreq = 4, max_docfreq = 10)
dfmat_ire2
set.seed(100)
if (require(topicmodels)) {
my_lda_fit20 <- LDA(convert(dfmat_ire2, to = "topicmodels"), k = 20)
get_terms(my_lda_fit20, 5)
}
```