集合知プログラミングの勉強(4)
集合知プログラミングの続き。R で図を書いてみた。
まずは、タブ区切り形式でデータファイルを作成した。存在しない値は空白にしている。この形式ではデータ(映画タイトル)が増えると横に巨大になって扱いがたい気がするが、とりあえずは扱いが簡単なので、この形式でいく。
Person Night Listener Dupree Superman Just My Luck Snakes Lady Rose 3.0 2.5 3.5 3.0 3.5 2.5 Seymour 3.0 3.5 5.0 1.5 3.5 3.0 Phillips 4.0 3.5 3.0 2.5 Puig 4.5 2.5 4.0 3.0 3.5 LaSalle 3.0 2.0 3.0 2.0 4.0 3.0 Matthews 3.0 3.5 5.0 4.0 3.0 Toby 1.0 4.0 4.5
次に、R で読み込んで図にする。‥ここまでで見かけ以上にとても苦労した。だいたい本と同じような図が書けたつもり。ただし点が重なっているところは文字も重なってしまっている。(まだ良くわかっていないので、こういった処理に詳しい方にコメントを寄せて頂けると嬉しいです。)
処理としては、
- fig01: データフレームを作って、特定の列だけプロット
- fig02, fig03: データフレームを作って、特定の行を選択し、転置してからプロット
fig01 <- function() { data1 <- read.table("/Users/cranebird/Documents/rep.pci/critics3.tsv", header=T, sep="\t") # Dupree vs Snakes plot (data1[,3], data1[,6], type="n", xlim=c(1,5), ylim=c(1,5), xlab="Dupree", ylab="Snakes", main="Fig 2-1") persons <- data1[,1] text (data1[,3], data1[,6], persons) } fig02 <- function() { data1 <- read.table("/Users/cranebird/Documents/rep.pci/critics3.tsv", header=T, sep="\t") # LaSalle vs Seymour LaSalle <- t(data1[5, 2:7]) # todo; ugly. Seymour <- t(data1[2, 2:7]) plot (LaSalle, Seymour, xlim=c(1,5), ylim=c(1,5), xlab="Mick LaSalle", ylab="Gene Seymour", main="Fig 2-2", type="n") titles <- colnames(data1)[2:7] text (LaSalle, Seymour, titles) } fig03 <- function() { data1 <- read.table("/Users/cranebird/Documents/rep.pci/critics3.tsv", header=T, sep="\t") # LaSalle vs Seymour Matthews <- t(data1[6, 2:7]) # todo; ugly. Rose <- t(data1[1, 2:7]) plot (Matthews, Rose, xlim=c(1,5), ylim=c(1,5), xlab="Jack Matthews", ylab="Lisa Rose", main="Fig 2-3", type="n") titles <- colnames(data1)[2:7] text (Matthews, Rose, titles) }
おっと、書いてみて気付いたけど、 p.12 の 図2-3 は Dupree の点が p.8 のデータと合っていないような。Jack Matthews の Dupree のスコアは 3.5, Lisa Rose の Dupree のスコアは 2.5。これは errata 行きだろうか?
そして R ならば実に素敵なことに、そもそも相関係数用関数なんて作る必要がない。最初っから関数 cor が用意されている。以下 R の対話環境(Emacs ESS)。
> data1 <- data1.load() > data1 Person Night.Listener Dupree Superman Just.My.Luck Snakes Lady 1 Rose 3.0 2.5 3.5 3.0 3.5 2.5 2 Seymour 3.0 3.5 5.0 1.5 3.5 3.0 3 Phillips 4.0 NA 3.5 NA 3.0 2.5 4 Puig 4.5 2.5 4.0 3.0 3.5 NA 5 LaSalle 3.0 2.0 3.0 2.0 4.0 3.0 6 Matthews 3.0 3.5 5.0 NA 4.0 3.0 7 Toby NA 1.0 4.0 NA 4.5 NA > rose <- scores.for(data1, "Rose") > rose Rose Night.Listener 3.0 Dupree 2.5 Superman 3.5 Just.My.Luck 3.0 Snakes 3.5 Lady 2.5 > seymour <- scores.for(data1, "Seymour") > seymour Seymour Night.Listener 3.0 Dupree 3.5 Superman 5.0 Just.My.Luck 1.5 Snakes 3.5 Lady 3.0 > cor(rose, seymour) Seymour Rose 0.396059 > rose <- scores.for(data1, "Rose") > matthews <- scores.for(data1, "Matthews") > rose Rose Night.Listener 3.0 Dupree 2.5 Superman 3.5 Just.My.Luck 3.0 Snakes 3.5 Lady 2.5 > matthews Matthews Night.Listener 3.0 Dupree 3.5 Superman 5.0 Just.My.Luck NA Snakes 4.0 Lady 3.0 > cor(matthews, rose) Rose Matthews NA > cor(matthews, rose, use="complete.obs") Rose Matthews 0.7470179 >
定義した関数は以下の通り。まだ全然洗練はされていないけど、動いたのでとても嬉しい。R も楽しいなぁ。
data1.load <- function() { read.table("/Users/cranebird/Documents/rep.pci/critics3.tsv", header=T, sep="\t") } scores.for <- function(data, person) { x <- t(subset(data, data$Person == person)[2:length(data)]) colnames(x) <- person x }
topMatches も実装。本当はもっとエレガントに書けるはず。そのうち http://www.okada.jp.org/RWiki/?R%A5%B3%A1%BC%A5%C9%BA%C7%C5%AC%B2%BD%A4%CE%A5%B3%A5%C4%A4%C8%BC%C2%CE%E3%BD%B8
Rコード最適化のコツと実例集 を参考に書き換えたい。特に for ループは R では不自然らしい。
top.matches <- function(prefs, person, n=5) { v <- c() others <- prefs[, "Person"] others <- others [ others != person] s1 <- scores.for(prefs, person) for (i in 1:length(others)) { other <- others[i] s2 <- scores.for(prefs, other) sim <- cor(s1, s2, use="complete.obs") v <- append(v, sim) } d <- data.frame(Score=v, Person=others) sorted <- order(d$Score, decreasing=TRUE) d[sorted,] }
こんな感じに使う。R のデータフレームっていいなぁ。
> top.matches(data1, "Toby") Score Person 1 0.9912407 Rose 5 0.9244735 LaSalle 4 0.8934051 Puig 6 0.6628490 Matthews 2 0.3812464 Seymour 3 -1.0000000 Phillips >