n-gram が簡単にできそう
http://www.okada.jp.org/RWiki/?R%A4%CE%B4%F0%CB%DC%A5%D1%A5%C3%A5%B1%A1%BC%A5%B8%C3%E6%A4%CE%BB%FE%B7%CF%CE%F3%A5%AA%A5%D6%A5%B8%A5%A7%A5%AF%A5%C8%B0%EC%CD%F7 を見てると、embed というのがあった。
> example(embed) embed> x <- 1:10 embed> embed (x, 3) [,1] [,2] [,3] [1,] 3 2 1 [2,] 4 3 2 [3,] 5 4 3 [4,] 6 5 4 [5,] 7 6 5 [6,] 8 7 6 [7,] 9 8 7 [8,] 10 9 8
ruby の each_cons っぽい感じ。n-gram が簡単にできそう、と思ったら数値しかだめだった。
文字列で行うなら、apply とアクセスを利用して次みたいにやればよさそう。
> str <- strsplit("日本語でも大丈夫","")[[1]] > apply(embed(seq_along(str),3), 1, function(x) str[rev(x)]) [,1] [,2] [,3] [,4] [,5] [,6] [1,] "日" "本" "語" "で" "も" "大" [2,] "本" "語" "で" "も" "大" "丈" [3,] "語" "で" "も" "大" "丈" "夫"
という感じかな。そのうちマルコフ連鎖で文を生成してみるかな。
時系列データの線形フィルタ
Filter が vector から要素を取り出す関数なら filter は何だろう?と思ったので調べてみた。
> ?filter Linear Filtering on a Time Series Description: Applies linear filtering to a univariate time series or to each series separately of a multivariate time series. Usage: filter(x, filter, method = c("convolution", "recursive"), sides = 2, circular = FALSE, init) ...
時系列データの線形フィルタを実行するらしい。
recursive と convolution でそれぞれ以下の式が実行された結果が返ってくる。
- recursive
- y[i] = x[i] + f[1]*y[i-1] + ... + f[p]*y[i-p]
- convolution
- sides=1: y[i] = f[1]*x[i] + ... + f[p]*x[i-(p-1)]
- sides=2: y[i] = f[1]*x[i] + f[2]*x[i+1] + ... + f[p]*x[i-1^(p/2)p/2]
あまり使うこともなさそうだけど、おもしろそう。
convolution の sides1 はマルコフ性で sides2 は対象点の前後から集めてきてる感じ。
ついでに、recursive を使うとフィボナッチ数列ができるな。
> filter(c(0,1,rep(0,10)), c(1,1), "re") Time Series: Start = 1 End = 12 Frequency = 1 [1] 0 1 1 2 3 5 8 13 21 34 55 89
function を書かずに済む Filter
Filter 関数で function を書かずに済むようにしてみた。
デフォルトの引数を「.」にして、Bool値のベクトル返すような式を第一引数に入れる。
fi <- function(f, .) { ind <- as.logical(eval(substitute(f))) .[!is.na(ind) & ind] } > fi(3 < . & . < 7, 1:10) [1] 4 5 6
けど、これを http://d.hatena.ne.jp/arbores/20080521/1211463230 のS3に組み込もうとすると、
`[.call` <- function(x,f)Filter(eval(substitute(function(.)X, list(X=f))), x) > q <- quote > (1:10)[q(. > 3)] [1] 4 5 6 7 8 9 10
みたいに無駄な q が入るなぁ。けどこれなしではうまく動かないしな。
順列を作ってみる
R には combn という組み合わせを作ってくれる関数がある。
> combn(1:3,2) [,1] [,2] [,3] [1,] 1 1 2 [2,] 2 3 3 > combn(letters[1:3],2) [,1] [,2] [,3] [1,] "a" "a" "b" [2,] "b" "c" "c"
けど順列を作ってくれる関数はなかったので、つくってみた。
permu <- function(x, n) { iter <- function(n, x, ls) { if(n == 0){ ls } else{ sapply(x, function(xs) iter(n-1, x[x!=xs], rbind(ls, xs))) } } r <- iter(n, x, NULL) dim(r) <- c(n, length(r) / n) r } > permu(1:3, 2) [,1] [,2] [,3] [,4] [,5] [,6] [1,] 1 1 2 2 3 3 [2,] 2 3 1 3 1 2 > permu(letters[1:3], 2) [,1] [,2] [,3] [,4] [,5] [,6] [1,] "a" "a" "b" "b" "c" "c" [2,] "b" "c" "a" "c" "a" "b"
再帰を使って書いてあるから、あまり大きな数を指定できないな。
dim で形を整えてるとこも、ちと気に入らない。
再帰をループにして、apply系を使う方がいいのだろうけど、面倒なのでやめる。
S3 メソッドを使ってみる
http://d.hatena.ne.jp/syou6162/20080521/1211321228
をみて、Filter も で使えた方が一貫性があるし、Filter って書くよりも短いよね、と思ったので書いてみた。
演算子の動作を定義するには [ 関数を書き換えればいい。
[ 関数は呼び出す時には
"["(1:10,3)
と書けば呼べるけど、アクセスするときは ` を使って
> `[` .Primitive("[")
と書かないといけない。
関数かどうかの判定に class 関数を使って書くとこんな感じ。
`[` <- function(x,i,...) { if(class(i)=="function") Filter(i,x) else (.Primitive("["))(x,i,...) }
動作確認
> (1:10)[function(x) x > 4] [1] 5 6 7 8 9 10 > x <- 1:10 > x[x > 4] [1] 5 6 7 8 9 10
これでも動くけど、どうせなら最近覚えた S3 とやらを使ってみる。
この S3 は print や plot なんかで、与えられたデータに合わせた関数を呼び出す仕組みのようだ。
仕組みは簡単で UseMethod(generic, object) 関数を使うと「"generic"."objectのクラス名"」の関数を呼び出してくれる。
`[` <- function(x, i, ...) UseMethod("[", i) `[.default` <- .Primitive("[") `[.function` <- function(x,f) Filter(f,x) > (1:10)[function(x) x > 5 && x < 7] [1] 6 > x <- 1:10; x[x > 5 & x < 7] [1] 6
関数は function クラスなので、上の場合 i が関数だと [.function それ以外では [.default を呼び出す。
作ってはみたけど、function て書くのが長いな。単にS3を使ってみたかっただけだし、いっか。