これはおそらく簡単に解決できます。 500行×335列の2D行列mat
と、120425行のdata.frame dat
があります。 data.frame dat
には2つの列I
とJ
があります。これらは、mat
の行と列にインデックスを付けるための整数です。 mat
の値をdat
の行に追加したいと思います。
これが私の概念的な失敗です:
> dat$matval <- mat[dat$I, dat$J]
Error: cannot allocate vector of length 1617278737
(私はWin32でR 2.13.1を使用しています)。もう少し掘り下げてみると、マトリックスインデックスを誤用していることがわかります。これは、mat
のサブマトリックスのみを取得しており、期待どおりの値の1次元配列を取得していないように見えるためです。 :
> str(mat[dat$I[1:100], dat$J[1:100]])
int [1:100, 1:100] 20 1 1 1 20 1 1 1 1 1 ...
int [1:100] 20 1 1 1 20 1 1 1 1 1 ...
のようなものを期待していました。行、列のインデックスを使用して2D行列にインデックスを付け、値を取得する正しい方法は何ですか?
ほとんど。 「[」に2列の行列として提供する必要があります。
dat$matval <- mat[ cbind(dat$I, dat$J) ] # should do it.
注意点があります。これはデータフレームでも機能しますが、最初に行列クラスに強制変換され、数値以外の場合は、行列全体が「最小公分母」クラスになります。
DWinが示唆するように、マトリックスを使用してインデックスを作成する方がもちろんはるかにクリーンですが、奇妙な理由で、1-Dインデックスを使用して手動でインデックスを作成する方が実際にはわずかに高速です。
_# Huge sample data
mat <- matrix(sin(1:1e7), ncol=1000)
dat <- data.frame(I=sample.int(nrow(mat), 1e7, rep=T),
J=sample.int(ncol(mat), 1e7, rep=T))
system.time( x <- mat[cbind(dat$I, dat$J)] ) # 0.51 seconds
system.time( mat[dat$I + (dat$J-1L)*nrow(mat)] ) # 0.44 seconds
_
dat$I + (dat$J-1L)*nrow(m)
部分は、2次元インデックスを1次元インデックスに変換します。 _1L
_は、double値の代わりに整数を指定する方法です。これにより、一部の強制が回避されます。
... gsk3の適用ベースのソリューションも試しました。ただし、ほぼ500倍遅くなります。
_system.time( apply( dat, 1, function(x,mat) mat[ x[1], x[2] ], mat=mat ) ) # 212
_
これは、apply
の行ベースの操作を使用したワンライナーです。
> dat <- as.data.frame(matrix(rep(seq(4),4),ncol=2))
> colnames(dat) <- c('I','J')
> dat
I J
1 1 1
2 2 2
3 3 3
4 4 4
5 1 1
6 2 2
7 3 3
8 4 4
> mat <- matrix(seq(16),ncol=4)
> mat
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
> dat$K <- apply( dat, 1, function(x,mat) mat[ x[1], x[2] ], mat=mat )
> dat
I J K
1 1 1 1
2 2 2 6
3 3 3 11
4 4 4 16
5 1 1 1
6 2 2 6
7 3 3 11
8 4 4 16
n <- 10
mat <- cor(matrix(rnorm(n*n),n,n))
ix <- matrix(NA,n*(n-1)/2,2)
k<-0
for (i in 1:(n-1)){
for (j in (i+1):n){
k <- k+1
ix[k,1]<-i
ix[k,2]<-j
}
}
o <- rep(NA,nrow(ix))
o <- mat[ix]
out <- cbind(ix,o)