这是基础 R 解决方案:
funEmil <- function(obj, n) {
myDim <- dim(obj)
vec <- 1:n
if (is.null(myDim))
return(obj[vec])
nr <- myDim[1]
nc <- myDim[2]
vec1 <- vec - 1L
rem <- vec1 %% nc
quot <- vec1 %/% nc
obj[quot + (rem * nr + 1L)]
}
它依赖于基本的向量化模运算%% 和整数除法%/%。它也非常快:
set.seed(42)
MBig <- matrix(sample(10^7, 10^6, replace = TRUE), nrow = 10^4)
funOP = function(obj,n){
if(is.matrix(obj)) res = c(t(obj))[1:n]
if(is.vector(obj)) res = obj[1:n]
res
}
funRyan <- function(x, n){
if(is.vector(x)) i <- 1:n
if(is.matrix(x))
i <- cbind(ceiling(1:n/ncol(x)), rep_len(seq(ncol(x)), n))
x[i]
}
n <- 25000
## Returns same results
all.equal(funRyan(MBig, n), funEmil(MBig, n))
[1] TRUE
all.equal(funOP(MBig, n), funEmil(MBig, n))
[1] TRUE
library(microbenchmark)
microbenchmark(funOP(MBig, n), funRyan(MBig, n), funWoody(MBig, n), unit = "relative")
Unit: relative
expr min lq mean median uq max neval
funOP(MBig, n) 6.154284 5.915182 5.659250 5.880826 9.140565 1.0344393 100
funRyan(MBig, n) 1.015332 1.030278 1.028644 1.018446 1.032610 0.8330967 100
funEmil(MBig, n) 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000 100
以下是使用@Ryan 示例和 OP 修改后的解决方案的基准:
n <- 1e4
mat <- matrix(runif(n^2), n)
s <- floor(n*2.3)
microbenchmark(funOP(mat, s), funRyan(mat, s),
funWoody(mat, s), funOPmod(mat, s), unit = "relative", times = 10)
Unit: relative
expr min lq mean median uq max neval
funOP(mat, s) 6189.449838 5558.293891 3871.425974 5139.192594 2443.203331 2222.778805 10
funRyan(mat, s) 2.633685 3.032467 2.155205 2.863710 1.445421 1.537473 10
funEmil(mat, s) 2.654739 2.714287 1.969482 2.642673 1.277088 1.326510 10
funOPmod(mat, s) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 10
新修改的速度更快,并且仍然给出正确的结果..非常令人印象深刻!
identical(funOPmod(mat, s), funRyan(mat, s))
[1] TRUE