配列に関する Tips 大全

配列に関する操作は、R をマスターする基本です。関連する Tips を脈絡なくできるだけ集めたいと思います。お気づきの正統派・裏技テクニックを お寄せください。一部重複はむしろ好ましいと思います。


要素ベクトルから配列を作る

> arr <- array(1:8, c(2, 2, 2))
> dim(arr) 
[1] 2 2 2       # 次元は3
> arr[, , 1]    # 要素は規則「一番左の添字がもっとも早く変化する」に従い並べられる
     [,1] [,2]
[1,]    1    3
[2,]    2    4
> arr[, , 2]
     [,1] [,2]
[1,]    5    7
[2,]    6    8

行列は次元属性 dim が長さ2の配列に他ならない

配列についていえることは、行列に対しても有効

> mm <- array(1:12, dim=c(3, 4))   # 配列としての行列(列主導で並べられる)
> mm <- array(1:12, c(3, 4))
> dim(mm)
[1] 3 4

配列のあるマージンに関数を適用 apply()

> x <- matrix(1:12, ncol=3)
> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> apply(x, 1, max) # 各行の最大値を求める
[1]  9 10 11 12
> apply(x, 2, max) # 各列の最大値を求める
[1]  4  8 12

複雑な場合の結果もよく吟味して利用すべし(2004/08/14)

> x <- array(1:12, c(2, 2, 3))
> x
, , 1

     [,1] [,2]
[1,]    1    3
[2,]    2    4

, , 2

     [,1] [,2]
[1,]    5    7
[2,]    6    8

, , 3

     [,1] [,2]
[1,]    9   11
[2,]   10   12

> apply(x, c(1, 2), sum)
     [,1] [,2]
[1,]   15   21
[2,]   18   24
> apply(x, c(1, 3), sum)
     [,1] [,2] [,3]
[1,]    4   12   20
[2,]    6   14   22
> apply(x, c(2, 3), sum)
     [,1] [,2] [,3]
[1,]    3   11   19
[2,]    7   15   23

配列の添字順序の変更 aperm()

x <- array(runif(5^4), c(5, 5, 5, 5))          # 4次元配列
y <- aperm(x, perm=c(2, 1, 3, 4))              # 添字順序の変更
# (y <- aperm(x, c(2, 1, 3, 4)) でも同じ)          
z <- aperm(x, perm=match(1:4, c(2, 1, 3, 4)))   # 添字順序の変更
zz <- aperm(y, perm=c(2, 1, 3, 4))             # 添字順序の変更

とすると x[i1, i2, i3, i4] は y[i2, i1, i3, i4] となる z[i1, i2, i3, i4] は x[i2, i1, i3, i4] となる。 zz と z は同じ

perm 引数を省略すると添字順序が逆順になる。つまり perm=rev(seq(length(dim(x)))) としたのと同じ

x <- matrix(runif(5^2), ncol=5)
y <- aperm(x, c(2, 1))

と置くと y は t(x) と一致

配列のベクトルとしての x 番目の要素の配列添字を取り出す関数

解--その1

Richard A. O'Keefe による r-help 記事(2003.7.31) より

   index.decode <- function (index, array) { # 3次元までの配列に対応
	jndex <- index - 1
	dimarr <- dim(array)
	ndims <- length(dimarr)
	if (ndims == 1) {
	    rbind(index)
	} else
	if (ndims == 2) {
	    rbind(jndex %% dimarr[1] + 1, jndex %/% dimarr[1] + 1)
	} else
	if (ndims == 3) {
	    rbind(jndex %% dimarr[1] + 1,
	          (jndex %/% dimarr[1]) %% dimarr[2] + 1,
	          jndex %/% (dimarr[1]*dimarr[2]) + 1)
       } else {
           stop("length(dims(array)) > 3 not yet implemented")
	}
   }
> arr <- array(rnorm(27), c(3, 3,3 )) # 3次元配列
> index.decode(3, arr)
     [,1]
[1,]    3
[2,]    1
[3,]    1
 > arr[3]           # ベクトルとしての arr の三番目の要素
[1] 0.929989
> arr[3,1,1]      # 配列としての対応添字は 3,1,1 
[1] 0.929989
> index.decode(c(3, 17, 13, 5), arr)
     [,1] [,2] [,3] [,4]
[1,]    3    2    1    2  # ベクトルとしての 3, 17, 13, 5 番目の要素の添字
[2,]    1    3    2    2
[3,]    1    2    2    1

解--その2

次元数に関係なく添え字を求める関数は,簡単に書ける(ダサイかもしれないが確実;青木繁伸 2004/08/15)

> index.decode <- function(index, x)
+ {
+ 	indx <- as.integer(n <- length(dimn <- rev(cumprod(dim(x)))))
+ 	index <- index-1
+ 	for (i in 2:n) {
+ 		indx[i-1] <- (index %/% dimn[i])
+ 		index <- index %% dimn[i]
+ 	}
+ 	indx[length(dimn)] <- index
+ 	rev(indx)+1
+ }
> x <- array(1:prod(2:8), 2:8) # 順に 1 〜 40320 を持つ配列
> index.decode(35, x) # 35 番目の要素の添え字は
[1] 1 3 2 2 1 1 1
> x[1, 3, 2, 2, 1, 1, 1] # 確かにその添え字の要素は 35 である
[1] 35
> index.decode(12345, x) # 以下同じ
[1] 1 2 2 5 1 4 3
> x[1, 2, 2, 5, 1, 4, 3]
[1] 12345
> index.decode(40320, x)
[1] 2 3 4 5 6 7 8
> x[2,3,4,5,6,7,8]
[1] 40320
> index.decode(40319, x)
[1] 1 3 4 5 6 7 8
> x[1, 3, 4, 5, 6, 7, 8]
[1] 40319

任意オフセットの行列・配列 (アドオンパッケージ Oarray)

Rの行列・配列は添字が1から始まるが、場合により0等の添字を使いたいこともある。アドオンパッケージ Oarray は任意のオフセットの行列・配列を定義することを可能にする。主な使い方は添字に0を含める、添字が例えば A[i,j], 3 <= i, j <= 10, しか必要ないとき不要なメモリーを消費しない、等が考えられる。Oarray を使うにはあらかじめパッケージをインストールし、library(Oarray) で読み込んでおく必要がある

注意: R では負の添字は「除外」を意味するので、問題が起きる。真の負の添字を使いたければ drop.negative=FALSE にする。base パッケージ中の関数 as.array は as.array.Oarray() 関数で置き換えられる

一般形

Oarray(data=NA, dim=length(data), dimnames=NULL, offset=NA,
       drop.negative=TRUE)
as.Oarray(x, offset=NA, drop.negative=TRUE)
as.array(x)
print(x)
x[i]
x[i, j, ...]
x[i, j, ..., drop=TRUE]

引数

data, dim, dimnames: array 関数と同じ意味
offset: 各添字組に対する最初の添字値のベクトル (既定値はすべて1)
drop.negative: 論理値。負の添字が「除外」を意味するかどうか (既定値はTRUEで除外)
x: 配列で、クラス Oarray でも良い
i, j, ...: x への添字引数

返り値

典型的にはクラス Oarray  を持つ、もしくは持たない配列。副配列を抽出すると単なる配列になる。Oarray オブジェクトを
指定すると Oarray  に再びなる。print 関数は Oarray オブジェクトを適切に表示する
> A <- Oarray(1:16, c(4, 4), offset=c(-2, -1))
> A
      [,-1] [, 0] [, 1] [, 2]
[-2,]     1     5     9    13
[-1,]     2     6    10    14
[ 0,]     3     7    11    15
[ 1,]     4     8    12    16
> A[-2, 0]  # 負の添字が除外を意味しないことを注意
[1] 5
> A[-2, -1]
[1] 1
> A[(-2):0, -1]
[1] 1 2 3
> A[(-2):0, (-1):1] # 副配列を取り出すと通常の配列になる (drop=FALSE をつけても同様 ?)
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11

配列にダミー次元を加える (2003.12.31)

次元の異なる二つの配列 x[i, j, k], y[i, j] に対し z[i, j, k]=x[i, j, k]+y[i, j] を計算したい時、配列の次元が異なるため z <- x + y とは出来ない。yy[i, j, k] が y[i, j] であるような仮の配列 yy を作れば z <- x + yy として(for ループなしで高速に)計算できる。

> a <- matrix(1:12, ncol=4)
> dim(a)
[1] 3 4
 
# a に長さ2の第3次元を付加する
> aa <- a%o%rep(1, 2)  
> dim(aa)
[1] 3 4 2
> aa[, , 1]              # aa[i, j, k] (k=1, 2) の値は a[i, j]
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
> aa[, , 2]
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
 
# 第1,2次元の真中に長さ2のダミー次元を挿入する (aperm 関数で次元順序を変更)
> aaa <- aperm(a%o%rep(1, 2), c(1, 3, 2))  # つまり aaa <- aperm(aa, c(1, 3, 2))
> dim(aaa)
[1] 3 2 4
> aaa[, 1,]  # aaa[i, j, k] (j=1, 2) の値は aa[i, k, j]、つまり a[i, k] と等しい
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
> aaa[, 2,]
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12

配列を3次元からrbindで2次元にする(2007.09.20)

3次元のデータが扱いにくいので全部まとめたい、csvや表計算などにwrite.tableしたいときなどに、あると便利なのでつくってみました。あとで解析に使うことを前提に3次元目の値(dimname)を1列目にもつようにしてあります。変な部分やもっといい方法があったら、ご指摘ください。

ch.arr.3d2d <- function(ARR) {
if (length(dimnames(ARR)[[3]]) == 0) { #行列名なしの場合
	for (t in 1:(length(ARR[1, 1, ])-1)) {
		if (t == 1) {
			x <- cbind(rep(t, nrow(ARR)), ARR[, , t])
		}
		ARR.no <- cbind(rep(t+1, nrow(ARR)), ARR[, , t+1])
		x <- rbind(x,A RR.no)
	}
} else {
	if (length(dimnames(ARR)[[3]]) >= 1) { #行列名がある場合
		for (t in 1:(length(ARR[1,1,])-1)) {
			if (t == 1) {
				x <-  cbind(rep(dimnames(ARR)[[3]][t], nrow(ARR)), ARR[, , t])
			}
			ARR.no <-  cbind(rep(dimnames(ARR)[[3]][t+1], nrow(ARR)), ARR[, , t+1])
			x <- rbind(x, ARR.no)
		}
	} else {
		for (t in 1:(length(ARR[1, 1, ])-1)) { #行列名が不正な場合
			if(t==1){
				x <- cbind(rep(t, nrow(ARR)), ARR[, , t])
			}
			ARR.no <- cbind(rep(t+1, nrow(ARR)), ARR[, , t+1])
			x <- rbind(x, ARR.no)
		}
	paste("waring: dimnames data does not much")
	}
}
return(x)
}
arr <- array(1:8, c(2, 2, 2))
ch.arr.3d2d(arr)

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2023-03-25 (土) 11:19:16