[[Rの備忘録]] ''lsa''というパッケージがあるので,そちらを使うと便利. コサイン尺度は以下で定義される.要するに二つのベクトル間の角度である. #mimetex(cos(a,b) = \frac{\sum a_i \cdot b_i}{||a|| \cdot ||b||}) 二つのベクトルが直交しているのならば 0 となり,重なっているのなら 1 となる. さて上の式で分母の &mimetex(||a||); はベクトルの長さである.&mimetex(|\vec{a}|); と表記されていることもある.ベクトルの長さは,各要素を二乗して合計を求め,その平方根を取ることで求まる.R では次のように計算する.なお,この例は,『Rによるテキストマイニング入門』p.137から引用したものである. > TD <- matrix(c(1,0,0,0,1,0, 0,1,0,1,0,1, 0,1,0,0,0,0, 0,1,0,0,0,0, 0,0,1,0,0,1, 1,1,1,1,0,0, 0,0,1,2,1,0, 1,1,0,0,0,0), nrow=8, byrow=T) TD という行列の1列目(aとする)と2列目(bとする)のベクトルの長さを求めるには > a <- sum(TD[,1]^2) # ベクトル a > b <- sum(TD[,2]^2) # ベクトル b とする.それぞれの平方根の積が分母の値である. > sqrt(a) * sqrt(b) 一方,分子の &mimetex(\sum a_i \cdot b_i); は 1列目(aとする)と2列目(bとする)のベクトルのそれぞれの要素同士を掛け合わせ,その合計を求めたものである.Rでは次のように計算する. > TD[,1] %*% TD[,2] # 2 演算子は行列用の %*% を使うこと.通常の乗算演算子 * を使うと,各要素の積の一覧が表示されてしまう. > TD[,1] * TD[,2] # [1] 0 0 0 0 1 1 0 0 0 0 0 さて,一般には行列のすべての列のコサイン尺度を求めるのが普通なので,次のような関数を用意して実行する. > myCosine <- function(x){ ret <- matrix(0,ncol=ncol(x),nrow=ncol(x)) # for(i in 1:ncol(x)){# for(j in 1:ncol(x)){ ret[i,j] <- (x[,i] %*% x[,j]) / (sqrt(sum(x[,i]^2)) * sqrt(sum(x[,j]^2))) } } ret } > myCosine(TD) [,1] [,2] [,3] [,4] [,5] [,6] [1,] 1.00000 0.51639 0.33333 0.23570 0.40824 0.00000 [2,] 0.51639 1.00000 0.25819 0.36514 0.00000 0.31622 [3,] 0.33333 0.25819 1.00000 0.70710 0.40824 0.40824 [4,] 0.23570 0.36514 0.70710 1.00000 0.57735 0.28867 [5,] 0.40824 0.00000 0.40824 0.57735 1.00000 0.00000 [6,] 0.00000 0.31622 0.40824 0.28867 0.00000 1.00000 1列目と3列目のコサイン尺度は 0.33 と計算された. ただし R の機能を活かすには,apply() 関数と crossprod()関数を使うべきである.その場合は,直感的に理解しづらいコードだが,以下のようになる. > myCosine <- function(x){ apply(x, 2, function(y){ # 各列に次の関数を適用する apply(x, 2, function(z){ # 各列とのクロス積を求める crossprod(y, z) / (sqrt(crossprod(y) * crossprod(z))) }) }) } RjpWiki の初級者質問11に,コサイン距離の算出関数を河童さんが紹介していたので,上記の記述にあわせた変更を行った上で,以下に引用させてもらう. myCosine2 <- function(x) { x <- as.matrix(x) ss <- 1/sqrt(colSums(x^2)) col.similarity <- t(x) %*% x*outer(ss, ss) colnames(col.similarity) <- rownames(col.similarity) <- colnames(x) return(col.similarity) }