这可能很容易解决。我有一个包含500行×335列的2D矩阵mat
和一个包含120425行的data.frame dat
。 data.frame dat
有两列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
的子矩阵,而不是我预期的单维数组值,即:
> 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矩阵以获取值的正确方法是什么?
答案 0 :(得分:39)
几乎。需要提供“[”作为两列矩阵:
dat$matval <- mat[ cbind(dat$I, dat$J) ] # should do it.
有一点需要注意:虽然这也适用于数据帧,但它们首先被强制转换为矩阵类,如果有非数字,整个矩阵将成为“最低分母”类。
答案 1 :(得分:10)
使用矩阵索引为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)
部分将二维指数转换为一维指数。 1L
是指定整数而不是double值的方法。这避免了一些强制。
...我也试过gsk3基于应用的解决方案。它的速度差了近500倍:
system.time( apply( dat, 1, function(x,mat) mat[ x[1], x[2] ], mat=mat ) ) # 212
答案 2 :(得分:1)
这是使用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
答案 3 :(得分:0)
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)