2014年9月30日火曜日

[R言語] table関数

table関数の挙動をメモしておく。

Table(v)

まず引数一つのパターン。
引数に渡すVectorを用意する。
v <- c("a","b","a","b","c")

これをtable関数に渡す。

t <- table(v)

結果は次のようになる。

a b c 
2 2 1 

vには"a"が2回,"b"が2回,"c"が1回出現したとういう意味。引数に与えたvectorの頻度が得られる。

Table(r,c)

次に引数2つのパターン。
列(row)のためのVentorを用意する。

r <- c("a","b","a","b","a","b")

そして、次に行(Colomn)のためのVectorを用意する。

c <- c("A","B","A","B","A","B")

これを、table関数の第一引数、第二引数にそれぞれ渡す。

t <- table(r,c)

すると下記の値が得られる。

    A B
  a 3 0
  b 0 3

これがどのような値か解説すると、 ("a","A")のペアが3組, ("b","B")のペアが3組, ("b","A")のペアが0組, ("a","B")のペアが0組、というデータ形式を表すことになる。

ペアは、ベクターrとcの同じ順序の値が選択される。例えばrの第一要素は"a", cの第一要素は"A"であるので、ペアとして("a","A")が選ばれる。

ペアを全部列挙すると、

("a","A")
("b","B")
("a","A")
("b","B")
("a","A")
("b","B")

という6組のペアが生成され、このペアの出現頻度を行列形式で表したのがtable(r,c)ということになる。


tableって名前から結果が想像しづらい。


参考文献

Frequency tables





2014年9月9日火曜日

機械学習入門 サンプルコードの間違い

Oreilly社発行の「機械学習入門」にて、サンプルコードの誤りを見つけたので、ここに残しておきます。
サンプルが管理されているgithubではissueとして報告されており、pull requestも出しているが、1年以上前のpull requestが放置されている状態をみると、公式に直される可能性は残念ながら低そうな様子。

今回見つけたバグは3章のemail classifyのコード。

classify.email <- function(path, training.df, prior = 0.5, c = 1e-6)
{ 
  # Here, we use many of the support functions to get the 
  # email text data in a workable format
  msg <- get.msg(path)
  msg.tdm <- get.tdm(msg)
  msg.freq <- rowSums(as.matrix(msg.tdm))
  # Find intersections of words
  msg.match <- intersect(names(msg.freq), training.df$term)
  # Now, we just perform the naive Bayes calculation
  if(length(msg.match) < 1)
  {      
        return(prior * c ^ (length(msg.freq))) ★
  }
  else
  { 
    match.probs <- training.df$occurrence[match(msg.match, training.df$term)]
    return(prior * prod(match.probs) * c ^ (length(msg.freq) - length(msg.match))) ★

  }
}

パッと見た感じ問題がなさそうなんですが、実は★で示した行の処理は、ものすごい小さい浮動小数点になるため、値が0になってしまします。

c = 1e-6( = 0.000001)であり、それに対して(length(msg.freq) - length(msg.match)))という最大で数百になる数でべき乗を求めているので、数値上は1e-1000を越えることがあり、Rで扱える浮動小数点の最小値を下回ってしまっているようです。

そのため、数をRで扱える範囲に移動させるために、全体に対してlog10を与えます。

 
  if(length(msg.match) > 1)
  {     
        return (log10(prior) + length(msg.freq) * log10(c)) ★
  }
  else
  { 
    match.probs >- training.df$occurrence[match(msg.match, training.df$term)]
    return (log10(prior) + sum(log10(match.probs)) + (length(msg.freq) - length(msg.match)) * log10(c)) ★
  }
}

なお計算の途中で下記のlogに関する定理を利用しています。
log(A * B) = logA + logB
log(A ^ C) = C*logA
また prod(match.probs)は、match.probsというベクトルの全要素を掛け合わせるという計算式ですので、これにlog10を適用すると下記のようになります。
log(prod(match.probs) = log(a1 * a2 * ... * an)
                                               = log(a1) + log(a2) + ... + log(an)
                                     = sum(log(match.probs))
ちなみにissue#17にも報告がある通り、これを適用するとスパム判定結果が書籍の値と全く違う値になりますなんか、Amazonレビューによると書籍自体も作りが甘い箇所が多いようですし、加えてコードにもかなり致命的があります。本のコンセプト自体は他に類がない希少なものでありながら、結果としてこのような適当な作りに仕上がってしまったのはなんとも残念です。



2014年9月3日水曜日

tmパッケージを使ったサンプル [R言語]

R言語でtmパッケージを使ったサンプル

まずコーパスを作成して、TermDocumentMatrixを作る。

R> library('tm')
R> con <- file(file.path("source.txt"),open="rt")
R> text <- readLines(con)
R> close(con)
R> corpus <- Corpus(VectorSource(text))
R> tdm <- TermDocumentMatrix(corpus)
読み込んでるsource.txtの内容は次のようなサンプル文

This is a first line.
This is a second line.
This is a third line.
The forth line is being written.

得られたTermDocumentMatrixをいろいろいじってみる。

inspect()

各Docs(今の例では1行がひとつのDocに対応)に出てくるTermを全部表示する。
R> inspect(tdm)
A term-document matrix (10 terms, 4 documents)

Non-/sparse entries: 14/26
Sparsity           : 65%
Maximal term length: 8
Weighting          : term frequency (tf)

          Docs
Terms     1 2 3 4
  being     0 0 0 1
  first       1 0 0 0
  forth      0 0 0 1
  line        0 0 0 1
  line.       1 1 1 0
  second   0 1 0 0
  the         0 0 0 1
  third      0 0 1 0
  this        1 1 1 0
  written.  0 0 0 1

例えば一行目は"This is a first line"だったので、Docs 1としてfirst, line, thisがそれぞれ1回カウントされている。

findFreqTerms

3回以上登場するtermを抽出する。
R> findFreqTerms(tdm,3)
[1] "line." "this" 


findAssocs

指定した単語に共起されるtermを抽出する。第3引数は共起率。
R> findAssocs(tdm,"this",0.1)
  line.  first second  third
  1.00   0.33   0.33   0.33 


2014年9月2日火曜日

R言語でのsapplyを使ったサンプルコード

プログラミング言語Rにあるsapplyを使ったサンプルコード。

sapplyはvector型の各要素に対して同じ処理を適用したいときに使用する関数。
例えば、vectorの全要素を2倍したりしたいときに使える。


例えば、渡された引数を2倍にして返す次の関数を考える。
%>times2 <- function(v){return (v*2)}
試しにこれを実行するとちゃんと2倍した値が返される。
%> times2(20)
%> [1]  40
これをsapplyと組み合わせると、vectorの値を2倍した値が得られる
%> l <- c(1,2,3,4,5)
%> sapply(l,times2)
%> [1]  2  4  6  8 10