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を使ってみたかっただけだし、いっか。