## Loading required package: NLP
## 未加工のコーパスを読み込む
corpus.raw <- VCorpus(DirSource(directory = "federalist", pattern = "fp"))
## 小文字にする
corpus.prep <- tm_map(corpus.raw, content_transformer(tolower))
## スペースを取り除く
corpus.prep <- tm_map(corpus.prep, stripWhitespace)
## 句読点を取り除く
corpus.prep <- tm_map(corpus.prep, removePunctuation)
## 数字を取り除く
corpus.prep <- tm_map(corpus.prep, removeNumbers)
## ストップワードを取り除く
corpus <- tm_map(corpus.prep, removeWords, stopwords("english"))
## 残った単語を語幹化する
corpus <- tm_map(corpus, stemDocument)
## 文書-用語行列
dtm <- DocumentTermMatrix(corpus)
## matrixオブジェクトに変換
dtm.mat <- as.matrix(dtm)単語の出現頻度の分析は、一般に用いられる単語の袋 (bag-of-words) に依存している。
文法や語順を無視することを意味するこの分析で、テキストの繊細な意味が発見されることはおそらくない。
しかし、用語頻度 (tf) の分布を用いれば、文章で論じられているトピック (topic) を推測することはできる。
頻繁に用いられる単語ほど大きなフォントで表示するワードクラウド (word could) は、用語頻度の分布をビジュアル化するために一般的に用いられる。
ワードクラウドは wordcloud パッケージの wordcloud() 関数によって作成される。
文書-用語行列は視覚的に調べるには大きすぎることが多いので、ワードクラウドは有効なビジュアル化の手段となる。
トピックの発見は、トピックの割当に関する真の情報にアクセスできないため、教師なし学習 (unsupervised learning) の1例である。
つまり、事前にどのトピックがコーパスに存在し、それぞれの文書を特徴づけているかについて知らず、文書ないや複数の文書間で用語の頻度分布を分析することでトピックを発見する。
対照的に、教師あり学習 (supervised learning) では、結果変数と予測変数との関係を学習させるために、研究者は観察された結果変数を含む標本を用いる。
例えば、いくつかの文書を読ませて割り当てさせたトピックを用いて、まだ読まれていない別の文書のトピックを予測させる。
結果変数に関する情報が欠如している教師なし学習問題の方が、教師あり学習問題よりも明らかに難しい。
まずは『フェデラリ・ペーパー』の第12篇と第24篇をワードクラウドを使ってビジュアル化し、それらのトピックを推測する。
wordcould パッケージの wordcould() 関数では、主に2つの引数を指定する。
words:単語のベクトル
freq:単語の頻度
図が煩雑になるのを避けるため、以下の引数を指定する。
scale:単語の大きさの範囲
max.words:表示される最大の単語数を制限
## Loading required package: RColorBrewer
2つのワードクラウドを比較する。
第12篇:revenu (revenue), commerc (commerce), trade, tax, land など経済に関係のある単語が並ぶ。
第24篇:power, peac (peace), garrison, armi (army) など安全保障に関する単語をより多く含んでいる。
stemCompletion() 関数を使って、語幹化された単語を元の完全形に戻すことができる。
最初の引数:語幹化された1つあるいは複数の単語
2番目の引数:候補となる完全形の単語リスト
corpus.prep を用いる。## revenu commerc peac army
## "revenue" "commerce" "peace" "army"
これらの発見されたトピックは、実際の論文の内容と確かに一致している。
第12篇は「歳入に関する連合国家の有用性 (The utility of the Union in respect to revenue)」で、建国当初の13の植民地が1つの国家を形成した場合の経済的便益について論じている。
第24篇は「共同防衛のための権力についての追考 (The powers necessary to the common defense further considered)」で、国軍の創設や立法府と連邦軍との関係性について論じている。
上の分析では、それぞれの文書における用語の出現頻度の分布ビジュアル化した。
しかし、コーパス内のすべての文書で頻出する用語はトピックの発見において意味がないから、重要性を下げなければならない。
そのためには用語頻度-逆文書頻度 (term frequency-inverse document frequency, tf-idf) という統計量を計算すればよい。
tf-idf 統計量は、ある文書内の各用語の重要性を測定する尺度の一種である。
ある文書 \(d\) の用語 \(w\) について、\(\mbox{tf-idf}(w,d)\) は次のように定義される。
\[ \mbox{tf-idf}(w,d) = \mbox{tf}(w,d) \times \mbox{idf}(w) \]
\(\mbox{tf}(w,d)\) は用語頻度、つまり文書 \(d\) における用語 \(w\) の出現数を表す。
\(\mbox{idf}(w)\) は逆文書頻度 (inverse document frequency) と呼ばれ、次のように定義される。
\[ \mbox{idf}(w) = \log \frac{N}{\mbox{df}(w)} \]
ここで、
\(N\):文書の数
\(\mbox{df}(w)\):文書頻度 (document frequency) つまり用語 \(w\) を含む文書の数
\(\mbox{df}(w)\)で割ることは \(w\) が多くの文書で頻繁に使用されるほど \(\mbox{idf}(w)\) は小さい値をとることを意味する。
結果として、複数の文書に共通の用語は tf-idf ではより小さい重み付けがなされる。
tf-idf 尺度は weightTfIdf() 関数を用いて計算することができる。
DocumentTermMatrix() 関数で生成された文書-用語行列の出力を入力とする。
引数 normalize はデフォルトでは TRUE で、用語頻度 \(\mbox{tf}(w,d)\) は文書 \(d\) に含まれるすべての単語の数によって除されて標準化 (normalize) される。
FALSE に設定されれば、標準化されない。## <<DocumentTermMatrix (documents: 5, terms: 8)>>
## Non-/sparse entries: 4/36
## Sparsity : 90%
## Maximal term length: 7
## Weighting : term frequency - inverse document frequency (normalized) (tf-idf)
## Sample :
## Terms
## Docs abandon abat abb abet abhorr abil abject abl
## fp01.txt 0 0 0 0 0 0.000000000 0 0.001367034
## fp02.txt 0 0 0 0 0 0.003588854 0 0.000000000
## fp03.txt 0 0 0 0 0 0.000000000 0 0.002833074
## fp04.txt 0 0 0 0 0 0.000000000 0 0.001336496
## fp05.txt 0 0 0 0 0 0.000000000 0 0.000000000
## <<DocumentTermMatrix (documents: 5, terms: 8)>>
## Non-/sparse entries: 4/36
## Sparsity : 90%
## Maximal term length: 7
## Weighting : term frequency - inverse document frequency (tf-idf)
## Sample :
## Terms
## Docs abandon abat abb abet abhorr abil abject abl
## fp01.txt 0 0 0 0 0 0.000000 0 1.017074
## fp02.txt 0 0 0 0 0 2.824428 0 0.000000
## fp03.txt 0 0 0 0 0 0.000000 0 2.034147
## fp04.txt 0 0 0 0 0 0.000000 0 1.017074
## fp05.txt 0 0 0 0 0 0.000000 0 0.000000
以下では、tf-idf 尺度を用いて『フェデラリスト・ペーパー』の第12篇と第24篇の論文で最も重要な10個の用語をリスト化する。
sort() 関数を使って tf-idf の値が大きい順に並べる。
引数 decreasing を TRUE に指定して、降順(大きい順)でソートする。
FALSE に指定すると昇順(小さい順)にソートできる。この時点では dtm.tfidf は DocumentTermMatrix なので、sort() 関数を使う前に行列へ変換する。
dtm.tfidf.mat <- as.matrix(dtm.tfidf) # 行列へ変換
## 論文第12篇で最も重要な10語
head(sort(dtm.tfidf.mat[12, ], decreasing = TRUE), n = 10)## revenu contraband patrol excis coast trade per
## 0.01905877 0.01886965 0.01886965 0.01876560 0.01592559 0.01473504 0.01420342
## tax cent gallon
## 0.01295466 0.01257977 0.01257977
## garrison dockyard settlement spain armi frontier arsenal
## 0.02965511 0.01962294 0.01962294 0.01649040 0.01544256 0.01482756 0.01308196
## western post nearer
## 0.01306664 0.01236780 0.01166730
分析の結果、『フェデラリスト・ペーパー』の第12篇で最も重要な用語は経済に関するものである一方で、第24篇では安全保障政策に関するものであることが明快に示されている。
用語頻度に基づくテキスト分析は、語順は無視してもよいという単語の袋の仮定に基づいている。
ある用語のある文書内における相対的な重要性を測定するには、用語頻度-逆文書頻度を計算する。
用語頻度-逆文書頻度は、ある用語が、その用語が出現した文書の数(文書頻度)の逆数で重み付けされた場合の相対的な頻度を表す。
トピック発見の別のアプローチに、tf-idf 尺度に基づいて似た論文の集合(クラスター)を特定するという方法がある。
ここでは、ハミルトンによって書かれた論文に焦点を当てる。
重み付け文書-用語行列に \(k\) 平均法アルゴリズムを適用する。
\(k\) 平均法の目的はデータを \(k\) 個の似たようなグループに分割することである。
\(k\) 平均法は、あらかじめ決められた数( \(k\) 個)のクラスターを生成するアルゴリズムで、以下のステップからなる。
\(k\) 個のクラスターの初期中心点を選択する。
上記1で決められた中心点に基づき、各観察を、その観察にとって(ユークリッド距離で)最も近い中心点をもつクラスターに割り当てる。
各クラスターの新しい中心点を、対応する変数のクラスター内の平均に等しい座標をもつように選ぶ。
クラスターへの割り当てが変化しなくなるまで、上記2と3を繰り返す。
R では、kmeans() 関数が \(k\) 平均法を実行する。
最初の引数 x:\(k\) 平均法を適用する観察の行列
centers:クラスターの数
iter.max:繰り返しの上限数
nstart:ランダムに選ばれる初期中心点の数
異なる初期値で何回かアルゴリズムが実行されるようにしたほうがよい。
kmeans() 関数は最もよい結果を報告してくれる。
通常、クラスターの数は試行錯誤して決定するが、ここでは4に設定する。
収束までにかかった繰り返しの回数がデフォルトの最大値である 10 を超えていないかどうかも確認する。
k <- 4 # クラスターの数
## ハミルトンによって書かれた『フェデラリスト・ペーパー』を部分集合化する
hamilton <- c(1, 6:9, 11:13, 15:17, 21:36, 59:61, 65:85)
dtm.tfidf.hamilton <- dtm.tfidf.mat[hamilton, ]
## k平均法を実行
km.out <- kmeans(dtm.tfidf.hamilton, centers = k)
km.out$iter # 収束したかをチェック(繰り返しの回数は異なる場合がある)## [1] 3
できあがったそれぞれのクラスターの中心で最も重要な10の用語を出力することで、結果を要約する。
また、『フェデラリスト・ペーパー』に収録されているどの論文がどのクラスターに属するかも示す。
ここでは同じ作業を各クラスターに対して行うのでループを用いる。
cat() 関数は "" で括った文字列を出力する。
"\n" は改行を表す。print 関数はコンソール(R の出力画面)に表示されるようにオブジェクトの要素(数値や文字列など)を出力する。
## 各中心点に対応する用語でラベルをつける
colnames(km.out$centers) <- colnames(dtm.tfidf.hamilton)
for (i in 1:k) { # 各クラスターでループ
cat("CLUSTER", i, "\n")
cat("Top 10 words:\n") # 各中心点で最も重要な10語
print(head(sort(km.out$centers[i, ], decreasing = TRUE), n = 10))
cat("\n")
cat("Federalist Papers classified: \n") # 分類された論文を抽出
print(rownames(dtm.tfidf.hamilton)[km.out$cluster == i])
cat("\n")
}## CLUSTER 1
## Top 10 words:
## court juri appel jurisdict trial tribun
## 0.045553185 0.031679369 0.014610450 0.014398568 0.013826016 0.012963605
## suprem impeach cogniz inferior
## 0.012739302 0.010427215 0.010077710 0.008663789
##
## Federalist Papers classified:
## [1] "fp65.txt" "fp81.txt" "fp82.txt" "fp83.txt"
##
## CLUSTER 2
## Top 10 words:
## vacanc recess claus senat session fill appoint
## 0.06953047 0.04437713 0.04082617 0.03408008 0.03313305 0.03101140 0.02211662
## presid expir unfound
## 0.01852025 0.01738262 0.01684465
##
## Federalist Papers classified:
## [1] "fp67.txt"
##
## CLUSTER 3
## Top 10 words:
## militia armi militari pardon governor treason
## 0.014639288 0.014493183 0.010024167 0.007643664 0.007114050 0.005833538
## disciplin peac presid garrison
## 0.005567509 0.005053636 0.004940856 0.004717510
##
## Federalist Papers classified:
## [1] "fp08.txt" "fp24.txt" "fp25.txt" "fp26.txt" "fp28.txt" "fp29.txt" "fp69.txt"
## [8] "fp74.txt"
##
## CLUSTER 4
## Top 10 words:
## senat upon tax revenu claus land
## 0.004103736 0.003886908 0.003028980 0.002766801 0.002750835 0.002726462
## taxat presid offic court
## 0.002711544 0.002695284 0.002404103 0.002184164
##
## Federalist Papers classified:
## [1] "fp01.txt" "fp06.txt" "fp07.txt" "fp09.txt" "fp11.txt" "fp12.txt"
## [7] "fp13.txt" "fp15.txt" "fp16.txt" "fp17.txt" "fp21.txt" "fp22.txt"
## [13] "fp23.txt" "fp27.txt" "fp30.txt" "fp31.txt" "fp32.txt" "fp33.txt"
## [19] "fp34.txt" "fp35.txt" "fp36.txt" "fp59.txt" "fp60.txt" "fp61.txt"
## [25] "fp66.txt" "fp68.txt" "fp70.txt" "fp71.txt" "fp72.txt" "fp73.txt"
## [31] "fp75.txt" "fp76.txt" "fp77.txt" "fp78.txt" "fp79.txt" "fp80.txt"
## [37] "fp84.txt" "fp85.txt"
CLUSTER 1
Top 10 words:
trade merchant northern navig manufactur revenu commerc
0.013962253 0.012890018 0.010487956 0.010283154 0.009795735 0.009754859 0.009501991
southern market confederaci
0.009303222 0.009179588 0.006984902
Federalist Papers classified:
[1] "fp11.txt" "fp12.txt" "fp13.txt" "fp35.txt"
CLUSTER 2
Top 10 words:
vacanc recess claus senat session fill appoint
0.06953047 0.04437713 0.04082617 0.03408008 0.03313305 0.03101140 0.02211662
presid expir unfound
0.01852025 0.01738262 0.01684465
Federalist Papers classified:
[1] "fp67.txt"
CLUSTER 3
Top 10 words:
court senat upon juri presid claus jurisdict
0.006979236 0.004317092 0.003983231 0.003385189 0.002751280 0.002750835 0.002649711
offic tax impeach
0.002566185 0.002526463 0.002294396
Federalist Papers classified:
[1] "fp01.txt" "fp06.txt" "fp07.txt" "fp09.txt" "fp15.txt" "fp16.txt" "fp17.txt"
[8] "fp21.txt" "fp22.txt" "fp23.txt" "fp27.txt" "fp30.txt" "fp31.txt" "fp32.txt"
[15] "fp33.txt" "fp34.txt" "fp36.txt" "fp59.txt" "fp60.txt" "fp61.txt" "fp65.txt"
[22] "fp66.txt" "fp68.txt" "fp70.txt" "fp71.txt" "fp72.txt" "fp73.txt" "fp75.txt"
[29] "fp76.txt" "fp77.txt" "fp78.txt" "fp79.txt" "fp80.txt" "fp81.txt" "fp82.txt"
[36] "fp83.txt" "fp84.txt" "fp85.txt"
CLUSTER 4
Top 10 words:
militia armi militari pardon governor treason disciplin
0.014639288 0.014493183 0.010024167 0.007643664 0.007114050 0.005833538 0.005567509
peac presid garrison
0.005053636 0.004940856 0.004717510
Federalist Papers classified:
[1] "fp08.txt" "fp24.txt" "fp25.txt" "fp26.txt" "fp28.txt" "fp29.txt" "fp69.txt"
[8] "fp74.txt"
上記の結果例からは次のようなことがわかる。
第1クラスターは経済に関係している。
第2クラスターは1つの論文しか含まれない。
第3クラスターでは司法制度や制度設計について論じられている。
第4クラスターは戦争と関係している。
これらのトピックを実際の『フェデラリスト・ペーパー』と比較すると、\(k\) 平均法に基づくクラスター化の結果がある程度妥当であることがわかる。
ここまで、『フェデラリスト・ペーパー』を題材に、テキスト分析によってどのようにトピックを明らかにできるかを見てきた。
『フェデラリスト・ペーパー』は比較的短いので、自動化されたテキスト分析は必要ないかもしれない。
しかし、同様の(より高度な)手法を、人間が短い時間で通読するのが困難な、より大きなコーパスに使うこともできる。
そのような場合、自動化されたテキスト分析は研究者がテキスト・データから意味のある情報を抽出するのに不可欠となり得る。
『フェデラリスト・ペーパー』の論文のいくつかは著者が不明である。
ここでは、ハミルトンかマディソンのいずれかが書いた66篇の論文を用いて、11篇の著者不明の論文の著者を予測する。
『フェデラリスト・ペーパー』の各論文は異なるトピックを取り扱っているため、形容詞、前置詞、接続詞に着目する。
特に、参考文献3に示されている分析を基に「although, always, commonly, consequently, considerable, enough, there, upon, while, whilst」の10語の頻度を分析する。
結果的に、語幹化されていないコーパス corpus.prep を使わなければならない。
まずは次のような準備を行う。
1000語あたりの用語の出現頻度を各用語について文書ごとに計算
得られた用語頻度行列がこれらの10語のみを含むように部分集合化
## 操作のため行列へ文書-用語行列行列を行列へ変換
dtm1 <- as.matrix(DocumentTermMatrix(corpus.prep))
tfm <- dtm1 / rowSums(dtm1) * 1000 # 1000語あたりの用語頻度
## 関心のある単語
words <- c("although", "always", "commonly", "consequently",
"considerable", "enough", "there", "upon", "while", "whilst")
## これらの単語のみを選択
tfm <- tfm[, words]
tfm[1:5, ]## Terms
## Docs although always commonly consequently considerable enough
## fp01.txt 0.0000000 0.8410429 0.8410429 0.000000 0 0.8410429
## fp02.txt 0.0000000 0.7593014 0.0000000 0.000000 0 0.0000000
## fp03.txt 0.8952551 3.5810206 0.8952551 2.685765 0 0.0000000
## fp04.txt 0.7763975 0.0000000 0.0000000 0.000000 0 0.0000000
## fp05.txt 0.9191176 0.9191176 0.0000000 0.000000 0 0.0000000
## Terms
## Docs there upon while whilst
## fp01.txt 1.6820858 5.0462574 0.0000000 0
## fp02.txt 0.0000000 0.7593014 0.7593014 0
## fp03.txt 0.8952551 0.0000000 0.0000000 0
## fp04.txt 2.3291925 0.0000000 0.0000000 0
## fp05.txt 0.0000000 0.0000000 0.0000000 0
## ハミルトンによって書かれた論文(再掲)
hamilton <- c(1, 6:9, 11:13, 15:17, 21:36, 59:61, 65:85)
## マディソンによって書かれた論文
madison <- c(10, 14, 37:48, 58)
## ハミルトンとマディソンの論文の各平均(1行目ハミルトン、2行目マディソン)
tfm.ave <- rbind(colSums(tfm[hamilton, ]) / length(hamilton),
colSums(tfm[madison, ]) / length(madison))
tfm.ave## although always commonly consequently considerable enough
## [1,] 0.01756975 0.7527744 0.2630876 0.02600857 0.5435127 0.3955031
## [2,] 0.27058809 0.2006710 0.0000000 0.44878468 0.1601669 0.0000000
## there upon while whilst
## [1,] 4.417750 4.3986828 0.3700484 0.007055719
## [2,] 1.113252 0.2000269 0.0000000 0.380113114
この結果から、次のことがわかる。
ハミルトンが相対的によく使う単語:there, upon
マディソンが相対的によく使う単語:consequently, whilst
結果変数を各論文の著者、予測変数を「there, upon, consequently, whilst」の4語の出現頻度とした線形回帰モデルを用いて、次のように著者を予測する。
著者がわかっている66篇の論文について線形回帰モデルを当てはめ、回帰係数を推定する。
当てはめられたモデルを使って4語の出現頻度に基づいて11篇の論文の著者を予測する。
まずは次のように準備を行う。
ハミルトンが著者の論文で 1、マディソンが著者の論文で -1 を取るようにコード化された結果変数を作成する。
著者がわかっている全ての論文について、著者を表す変数と用語頻度行列 tfm を含む、データフレーム・オブジェクトを作成する。
author <- rep(NA, nrow(dtm1)) # 欠損値をもつベクトル
author[hamilton] <- 1 # ハミルトンであれば1
author[madison] <- -1 # マディソンであれば-1
## 回帰分析のためのデータフレーム
author.data <- data.frame(author = author[c(hamilton, madison)],
tfm[c(hamilton, madison), ])作成した author を結果変数、「there, upon, consequently, whilst」の用語頻度を予測変数とした線形回帰モデルを当てはめる。
上で作成したデータフレーム・オブジェクトには、これらの4語を含む10語の用語頻度が含まれている。
lm() 関数では欠損値 NA は無視されるので、回帰係数は著者のわかっている66の論文を用いて推定される。
##
## Call:
## lm(formula = author ~ upon + there + consequently + whilst, data = author.data)
##
## Coefficients:
## (Intercept) upon there consequently whilst
## -0.26288 0.16678 0.09494 -0.44012 -0.65875
分析の結果は、先に行った予備分析の結果と一致している。
upon と there の係数の推定値は正で、ハミルトンの著作と関連している。
consequently と whilst の係数の推定値は負で、マディソンの著作と関連している。
他の3語の用語頻度を一定とすれば、whilst が(1000語あたり)1回多く使用されるごとに著者スコアの予測値(1に近いほどハミルトンの可能性が高く、-1に近いほどマディソンの可能性が高い)は0.66減少する。
この数字を解釈するために、fitted() 関数と sd() 関数を用いて予測値(当てはめ値)の標準偏差を計算する。
## [1] 0.7180769
whilst の係数は予測値の1標準偏差に迫るほど(絶対値が)大きいことがわかる。
つまり、whilst を(1000語あたり)1回多く使うかどうかで著者スコアの予測値の約1標準偏差分の変動が説明される。
ここでは、モデルがデータにどの程度上手く当てはまっているかを検証する。
そのために、先ほどの予測値を用いてそれぞれの論文を分類し、分類誤差 (classification error) を次のように計算する。
ハミルトンによって著された論文で正の予測値をもつものの割合を計算する。
同様にマディソンによって著された論文で負の予測値をもつものの割合を計算する。
これらの割合は、分類成功率を表している。
結果がどのカテゴリやクラスに属するかを予測する問題は分類 (classification) 問題と呼ばれる。
分類問題では予測は完全に正しいか誤りかのどちらかであり、誤った予測は誤分類 (misclassification) と呼ばれる。
ここでは、正(負)の予測値をもつものをハミルトン(マディソン)の論文として分類されたものとして、正しく分類された割合を計算している。
## [1] 1
## [1] 1
結果は、モデルが論文の著者を完璧に分類していることを示している。
この予測精度の尺度は、回帰の決定係数のように、サンプル内予測 (in-sample prediction) に基づいている。
すなわち、モデルの当てはめに用いたのと同じデータが再び予測精度を評価するのに用いられている。
これはモデルを手許のデータにオーバーフィット (overfit) させることがあるため、必ずしも良い解決策とはいえない。
オーバーフィッティングは、モデルがある特定の標本に特有の特徴の影響を受けるために起こる。
オーバーフィッティングが起こると、様々な標本に存在する体系的なパターンがわからなくなってしまう。
例えば、手許のデータがほとんどハミルトンの論文のものだった場合、モデルの大部分はハミルトンの論文の特徴を捉えるものとなってしまい、マディソンの論文を予測するのには不適切である。
代わりに、サンプル外予測 (out-of-sample prediction) を行うことができる。
これは新しい観察を用いてモデルの予測パフォーマンスを評価するものである。
ここでは1個抜き交差検証 (leave-one-out cross validation) と呼ばれる手法を用いる。
具体的には、観察の1つを標本から除外し、残りの観察でモデルを当てはめた後に除外しておいた観察の結果変数の値を予測する。
この手続きを標本内のそれぞれの観察について繰り返し、分類誤差を計算する。
交差検証は、モデル予測の正確性を、しばしばオーバーフィッティングに繋がるサンプル内予測に頼ることなく評価する手法である。
\(n\) 個の観察を含む標本があるとき、1個抜き交差検証では \(i=1,\ldots,n\) のそれぞれの観察について次のステップを繰り返す。
\(i\) 番目の観察を除外し分析に含めないでおく。
残りの \(n-1\) 個の観察を用いてモデルを当てはめる。
当てはめられたモデルを使って \(i\) 番目の観察の結果を予測し、予測誤差を計算する。
最後に、予測精度の尺度として \(n\) 個の観察の平均予測誤差(分類問題の場合は分類成功率)を計算する。
R では、ループを使って次のように交差検証を行うことができる。
各繰り返し家庭で1つの観察を除いてモデルをデータに当てはめ、除外された結果変数の値を予測する。
マイナス記号を用いて、特定の行をデータフレームから除外できる。
-i とする。予測値の計算には predict() 関数を用いる。
newdata には関心のある観察の行だけを含むデータフレームを指定する。n <- nrow(author.data)
hm.classify <- rep(NA, n) # 欠損値をもつベクトル(ループで値を入れる容器)
for (i in 1:n) {
## i番目の観察を除いたデータをモデルに当てははめる
sub.fit <- lm(author ~ upon + there + consequently + whilst,
data = author.data[-i, ]) # i番目の行を除く
## i番目の観察について著者を予測する
hm.classify[i] <- predict(sub.fit, newdata = author.data[i, ])
}## [1] 1
## [1] 1
最後に、この当てはめられたモデルを用いて著者不明の11篇の論文の著者を予測する。
predict() 関数を予測に使うときは、as.data.frame() 関数を使って用語頻度行列をデータフレームに変換する。
as.data.frame() 関数は、データフレームを生成する data.frame() 関数とは異なるので注意する。disputed <- c(49, 50:57, 62, 63) # 著者をめぐる論争のある11篇の論文
tf.disputed <- as.data.frame(tfm[disputed, ])
## 論争中の著者の予測
pred <- predict(hm.fit, newdata = tf.disputed)
pred # 予測値## fp49.txt fp50.txt fp51.txt fp52.txt fp53.txt fp54.txt
## -0.99831799 -0.06759254 -1.53243206 -0.26288400 -0.54584900 -0.56566555
## fp55.txt fp56.txt fp57.txt fp62.txt fp63.txt
## 0.04376632 -0.57115610 -1.22289415 -1.00675456 -0.21939646
結果を見やすくするために、次のように予測値をプロットする。
ハミルトンによって著されたことがわかっている論文:赤い四角形
マディソンによって著されたことがわかっている論文:青い丸
著者不明の論文:黒い三角形
縦軸の0を表す水平な波線の上(下)にある記号は、ハミルトン(マディソン)によって書かれたと分類された論文となる。
## ハミルトンによって著された論文の当てはめ値:赤い四角形
plot(hamilton, hm.fitted[author.data$author == 1], pch = 15,
xlim = c(1, 85), ylim = c(-2, 2), col = "red",
xlab = "Federalist Papers", ylab = "Predicted values")
abline(h = 0, lty = "dashed")
## マディソンによって著された論文の当てはめ値:青い丸
points(madison, hm.fitted[author.data$author == -1],
pch = 16, col = "blue")
## 著者不明の論文の予測値:黒い三角形
points(disputed, pred, pch = 17) モデルは11篇ある論文のうち10篇の論文をマディソンが著した(予測値が負)と予測している。
残りの1篇の論文の予測値は0に近く、かろうじてハミルトンによって書かれたと分類されている。
今回は下巻の第5章の内容に基づく。
原著 Quantitative Social Science (Princeton University Press) のウェブ・ページでデータなどをダウンロードできる。