4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rでdensity mapをプロットしたい

Last updated at Posted at 2013-11-29

もう何度挫折したか分かりませんが、懲りずにRに再挑戦。

こういう関数があって、

# 二次元正規分布の密度関数
multivariate_normal_distribution_2 <- function(x, mu, Sigma) {
  return ((1/2/pi) / sqrt(det(Sigma)) * exp(-1/2 * t(x - mu) %*% solve(Sigma) %*% (x - mu)))
}

# パラメータ
alpha <- 2.0
mu <- c(0,0)
Sigma <- rbind(
  c(alpha, 0),
  c(0, alpha)
)

density mapをプロットしたい。

定義域を決めて、

M <- 100
w0 <- seq(-1,1,length=M)
w1 <- seq(-1,1,length=M)

この範囲で値を求めておいて、

density <- matrix(1:(M*M), nrow=M)
for (i in 1:M) {
  for (j in 1:M) {
    density[j,i] <- multivariate_normal_distribution_2( c(w0[i], w1[j]), mu, Sigma )    
  }
}

filled.contourを使えば良いらしい。

filled.contour(w0, w1, density)

kobito.1385725081.921758.png

ベクトル化

二重for文を書くなんてRっぽくないと思ったら、outerというのがあった。2つのベクトルの交点で任意の関数を評価する外積を作れる。

ただし、マニュアルを見ると、

X and Y must be suitable arguments for FUN. Each will be extended by rep to length the products of the lengths of X and Y before FUN is called.

FUN is called with these two extended vectors as arguments. Therefore, it must be a vectorized function (or the name of one), expecting at least two arguments.

XとYはそれぞれのデータ点座標に対応するベクトルとして渡されるので、関数をベクトル化しないといけないよ、と書いてある。

multivariate_normal_distribution_2_vector <- function(x, y, mu, Sigma) {
  xx <- cbind(x,y) - matrix( rep(mu, times=length(x)), ncol=2 )
  return (
    (1/2/pi) / sqrt(det(Sigma)) *
      exp(-1/2 * rowSums((xx %*% solve(Sigma)) * xx))
  )
}

density <- outer(w0, w1, multivariate_normal_distribution_2_vector, mu, Sigma)

これで二重forループが無くなった。が、ベクトル化すると元の数式が想像できなくなるほど違った式になってしまうのが辛い。

調べたところ、これをやってくれるdmvnormという関数があるらしい。

library(mvtnorm)

density <- outer(w0, w1, function(x, y) dmvnorm(cbind(x,y), mean=mu, sigma=Sigma))

outerには無名関数を渡すこともできるので、これでだいぶコードが減った。

filled.contourではなくggplotを使う

ググって最初に出てきたのがfilled.contourを使う方法だったので上のようにしたが、ggplotを勉強中なのでggplotでもできないか調べた。

geom_tileというのを使えばいいらしい。ggplotを使うにはmatrixではなくdata.frameにしないといけないので、outerの代わりにexpand.gridを使うことにした。

grid <- expand.grid(w0=w0, w1=w1)
grid$density <- dmvnorm(grid, mean=mu, sigma=Sigma)
p3 <- ggplot(grid, aes(x=w0, y=w1, fill=density)) + geom_tile()
print(p3)

kobito.1385724488.011567.png

参考サイト

(追記)imageを使う

imageという関数を使うこともできるらしい。

density <- outer(w0, w1, function(x, y) dmvnorm(cbind(x,y), mean=mu, sigma=Sigma))

image(w0, w1, density)

kobito.1385757148.889115.png

まさにPRMLの同じ箇所を演習してる人の記事がQiitaのサイドバーに出てきて知った。Qiitaすばらしい。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?