R: RのBroadcast
RのBroadcast
RのBroadcast(ベクトル、行列などの型や次元を自動で合わせて演算する)でたまに混乱するのでまとめる。結論だけ書くとRではベクトルを行列にBroadcastするとき、列方向で埋め合わせるという事だけを忘れないようにすればOK
基本原理
デフォルトでは列方向で要素を埋めていく
まず基本原理把握のため、ベクトルから行列を生成してみる。Rではベクトルから行列を生成する際、デフォルトでは列方向(bycol)優先にで要素を埋めていく。 例えば、\( (1, 2, \cdots ,20) \)のベクトルから、5x4行列を生成する過程を考える
# ベクトル生成 (v <- 1:20) #> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # ベクトルから行列を生成 (何も指定しないと、列方向で要素が埋められていく) (X <- matrix(v, nrow=4, ncol=5)) #> [,1] [,2] [,3] [,4] [,5] #>[1,] 1 5 9 13 17 #>[2,] 2 6 10 14 18 #>[3,] 3 7 11 15 19 #>[4,] 4 8 12 16 20
行方向で埋め合わせたい場合はbyrowオプションを入れる
要素を行方向で使う場合にはbyrow=TRUEを指定すれば良い
# ベクトルから行列を生成 (byrowオプションを指定することで要素を行方向で埋めることもできる) (X <- matrix(v, nrow=4, ncol=5, byrow=TRUE)) #> [,1] [,2] [,3] [,4] [,5] #>[1,] 1 2 3 4 5 #>[2,] 6 7 8 9 10 #>[3,] 11 12 13 14 15 #>[4,] 16 17 18 19 20
デフォルトではベクトルから行列を生成する際、列方向に使うという事。この基本原理でBroadcastも行われるのだろうと想像できる
実際にBroadcastしてみる
実際にベクトルと行列を演算してBroadcastしてみる
# 4×5の0行列を生成 (A <- matrix(0, nrow=4, ncol=5)) #> [,1] [,2] [,3] [,4] [,5] #>[1,] 0 0 0 0 0 #>[2,] 0 0 0 0 0 #>[3,] 0 0 0 0 0 #>[4,] 0 0 0 0 0 # 行列とベクトルの足し算(element wise)でBroadcastしてみる (A + v) #> [,1] [,2] [,3] [,4] [,5] #>[1,] 1 5 9 13 17 #>[2,] 2 6 10 14 18 #>[3,] 3 7 11 15 19 #>[4,] 4 8 12 16 20
よくある危険な例(中心化する場合)
よくある処理の例で見ていきます。 行列を各変数(列)ごとに中心化してみましょう。よくやる \( {\bf X} - {\bf E}({\bf X}) \) です。
# 0-50のランダムな数で、5x5行列を生成 set.seed(0) (X <- matrix(sample(0:50, 25, replace=TRUE), nrow=5, dimnames = list(NULL,paste0('x', as.character(1:5))))) #> x1 x2 x3 x4 x5 #>[1,] 45 10 3 39 39 #>[2,] 13 45 10 25 47 #>[3,] 18 48 9 36 10 #>[4,] 29 33 35 50 33 #>[5,] 46 32 19 19 6 # 列の平均値を取る (X.center <- colMeans(X)) #> x1 x2 x3 x4 x5 #> 30.2 33.6 15.2 33.8 27.0
ダメな例
もとの行列から平均値を引いていくのですが、そのまま引くと意図と異なる値が出ます。以下は間違いです
# 普通に引き算してしまうと列方向でBroadcastされるのでNG (X - X.center) #> x1 x2 x3 x4 x5 #>[1,] 14.8 -20.2 -27.2 8.8 8.8 #>[2,] -20.6 11.4 -23.6 -8.6 13.4 #>[3,] 2.8 32.8 -6.2 20.8 -5.2 #>[4,] -4.8 -0.8 1.2 16.2 -0.8 #>[5,] 19.0 5.0 -8.0 -8.0 -21.0
正しい例
正しくは行方向でBroadcastしてもらわないとダメです。例えば以下のような方法があります
# 1.明示的に行方向で行列に変換 (X - matrix(X.center, nrow=5, ncol=5, byrow=TRUE)) #> x1 x2 x3 x4 x5 #>[1,] 14.8 -23.6 -12.2 5.2 12 #>[2,] -17.2 11.4 -5.2 -8.8 20 #>[3,] -12.2 14.4 -6.2 2.2 -17 #>[4,] -1.2 -0.6 19.8 16.2 6 #>[5,] 15.8 -1.6 3.8 -14.8 -21 # 2. 一度転置(transpose)して、戻す t(t(X) - X.center) #> x1 x2 x3 x4 x5 #>[1,] 14.8 -23.6 -12.2 5.2 12 #>[2,] -17.2 11.4 -5.2 -8.8 20 #>[3,] -12.2 14.4 -6.2 2.2 -17 #>[4,] -1.2 -0.6 19.8 16.2 6 #>[5,] 15.8 -1.6 3.8 -14.8 -21