我有一个大型矩阵列表。所有这些矩阵都有相同的行数,我想“取消列出”它们并将所有列绑定在一起。下面是我写的一段代码,但我不确定这是否是我在计算效率方面能达到的最佳代码。
x=model.matrix(~. - 1, bank[, 1:6])
y=bank[, 7]
bank.knn <- train(x, y, method= "knn",
trControl = trainControl(method = "cv"))
答案 0 :(得分:6)
要处理列表并在所有对象上调用函数,do.call
是我通常的第一个想法,此处cbind
按列绑定所有对象。
对于n=100
(为了完整性,还有其他答案):
n <- 10
nr <- 24
nc <- 8000
test <- list()
set.seed(1234)
for (i in 1:n){
test[[i]] <- matrix(rnorm(nr*nc),nr,nc)
}
require(data.table)
ori <- function() { matrix( as.numeric( unlist(test) ) ,nr,nc*n) }
Tensibai <- function() { do.call(cbind,test) }
BrodieG <- function() { `attr<-`(do.call(c, test), "dim", c(nr, nc * n)) }
nicola <- function() { setattr(unlist(test),"dim",c(nr,nc*n)) }
library(microbenchmark)
microbenchmark(r1 <- ori(),
r2 <- Tensibai(),
r3 <- BrodieG(),
r4 <- nicola(), times=10)
结果:
Unit: milliseconds
expr min lq mean median uq max neval cld
r1 <- ori() 23.834673 24.287391 39.49451 27.066844 29.737964 93.74249 10 a
r2 <- Tensibai() 17.416232 17.706165 18.18665 17.873083 18.192238 21.29512 10 a
r3 <- BrodieG() 6.009344 6.145045 21.63073 8.690869 10.323845 77.95325 10 a
r4 <- nicola() 5.912984 6.106273 13.52697 6.273904 6.678156 75.40914 10 a
至于为什么(在评论中)@nicola确实给出了答案,那么副本比原始方法少。
所有方法都给出了相同的结果:
> identical(r1,r2,r3,r4)
[1] TRUE
答案 1 :(得分:4)
由于do.call
调用期间的副本,似乎matrix
击败了其他方法。有趣的是,您可以使用data.table::setattr
函数来避免该副本,该函数允许通过引用设置属性,从而避免任何副本。我也省略了as.numeric
部分,因为没有必要(unlist(test)
已经numeric
)。所以:
require(microbenchmark)
require(data.table)
f1<-function() setattr(unlist(test),"dim",c(nr,nc*n))
f2<-function() do.call(cbind,test)
microbenchmark(res <-f1(),res2 <- f2(),times=10)
#Unit: milliseconds
# expr min lq mean median uq max neval
# res <- f1() 4.088455 4.183504 7.540913 4.44109 4.988605 35.05378 10
#res2 <- f2() 18.325302 18.379328 18.776834 18.66857 19.100681 19.47415 10
identical(res,res2)
#[1] TRUE
答案 2 :(得分:4)
我想我有一个更好的。我们可以避免cbind
的一些开销,因为我们知道这些开销都具有相同数量的行和列。相反,我们使用c
知道矩阵的基础向量性质将允许我们将它们重新包装到正确的维度中:
microbenchmark(
x <- `attr<-`(do.call(c, test), "dim", c(nr, nc * n)),
y <- do.call(cbind, test)
)
# Unit: milliseconds
# expr min lq
# x <- `attr<-`(do.call(c, test), "dim", c(nr, nc * n)) 4.435943 4.699006
# y <- do.call(cbind, test) 19.339477 19.567063
# mean median uq max neval cld
# 12.76214 5.209938 9.095001 379.77856 100 a
# 21.64878 20.000279 24.210848 26.02499 100 b
identical(x, y)
# [1] TRUE
如果你有不同数量的列,你可能仍然可以在计算总列数时小心谨慎。