假设我有一个20 X 5矩阵,我想选择矩阵的子集并用它们做一些计算。进一步假设每个子矩阵是7 X 5.我当然可以做
ncomb <- combn(20, 7)
它给了我7个行索引的所有可能组合,我可以用它们来获得子矩阵。但是使用20×5的小型矩阵,已经有77520种可能的组合。所以我想随机抽取一些组合,例如5000个组合。
一种可能性如下:
ncomb <- combn(20, 7)
ncombsub <- ncomb[, sample(77520, 5000)]
换句话说,我获得了所有可能的组合,然后随机选择了5000种组合。但是我想如果我有一个更大的矩阵 - 例如100 X 7,那么计算所有可能的组合会有问题。
所以我想知道如果没有先获得所有可能的组合,是否有办法获得组合的子集。
答案 0 :(得分:3)
你的方法:
op <- function(){
ncomb <- combn(20, 7)
ncombsub <- ncomb[, sample(choose(20,7), 5000)]
return(ncombsub)
}
一种不同的策略,只需从原始矩阵中抽取七行5000次(用新样本替换任何重复样本,直到找到5000个唯一行组合):
me <- function(){
rowsample <- replicate(5000,sort(sample(1:20,7,FALSE)),simplify=FALSE)
while(length(unique(rowsample))<5000){
rowsample <- unique(rowsample)
rowsample <- c(rowsample,
replicate(5000-length(rowsample),
sort(sample(1:20,7,FALSE)),simplify=FALSE))
}
return(do.call(cbind,rowsample))
}
这应该更有效率,因为它可以防止您必须首先计算所有组合,这将随着矩阵变大而变得昂贵。
然而,一些基准测试显示事实并非如此。至少在这个矩阵上:
library(microbenchmark)
microbenchmark(op(),me())
Unit: milliseconds
expr min lq median uq max neval
op() 184.5998 201.9861 206.3408 241.430 299.9245 100
me() 411.7213 422.9740 429.4767 474.047 490.3177 100
答案 1 :(得分:3)
我最终通过修改combn()
来执行@Roland建议的操作,并对代码进行字节编译:
combn_sub <- function (x, m, nset = 5000, seed=123, simplify = TRUE, ...) {
stopifnot(length(m) == 1L)
if (m < 0)
stop("m < 0", domain = NA)
if (is.numeric(x) && length(x) == 1L && x > 0 && trunc(x) ==
x)
x <- seq_len(x)
n <- length(x)
if (n < m)
stop("n < m", domain = NA)
m <- as.integer(m)
e <- 0
h <- m
a <- seq_len(m)
len.r <- length(r <- x[a] )
count <- as.integer(round(choose(n, m)))
if( count < nset ) nset <- count
dim.use <- c(m, nset)
##-----MOD 1: Change the output matrix size--------------
out <- matrix(r, nrow = len.r, ncol = nset)
if (m > 0) {
i <- 2L
nmmp1 <- n - m + 1L
##----MOD 2: Select a subset of indices
set.seed(seed)
samp <- sort(c(1, sample( 2:count, nset - 1 )))
##----MOD 3: Start a counter.
counter <- 2L
while (a[1L] != nmmp1 ) {
if (e < n - h) {
h <- 1L
e <- a[m]
j <- 1L
}
else {
e <- a[m - h]
h <- h + 1L
j <- 1L:h
}
a[m - h + j] <- e + j
#-----MOD 4: Whenever the counter matches an index in samp,
#a combination of row indices is produced and stored in the matrix `out`
if(samp[i] == counter){
out[, i] <- x[a]
if( i == nset ) break
i <- i + 1L
}
#-----Increase the counter by 1 for each iteration of the while-loop
counter <- counter + 1L
}
}
array(out, dim.use)
}
library("compiler")
comb_sub <- cmpfun(comb_sub)