Mat*_*lli 5 binary combinations r
我想创建一个由固定数字0和1组成的二进制向量的所有可能组合.例如:dim(v)= 5x1; N1 = 3; N0 = 2; 在这种情况下,我希望有类似的东西:
1,1,1,0,0
1,1,0,1,0
1,1,0,0,1
1,0,1,1,0
1,0,1,0,1
1,0,0,1,1
0,1,1,1,0
0,1,1,0,1
0,1,0,1,1
0,0,1,1,1
Run Code Online (Sandbox Code Playgroud)
我找到了一些帮助阅读这篇文章 创建所有可能的0,1或2"1"的长度为n的二进制向量 的组合,但我想只生成我需要的组合,避免任何浪费空间(我认为问题会随着n)而呈指数增长
您可以尝试这种方法:
f <- function(n=5,m=3)
t(apply(combn(1:n,m=m),2,function(cm) replace(rep(0,n),cm,1)))
f(5,3)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 1 1 0 0
# [2,] 1 1 0 1 0
# [3,] 1 1 0 0 1
# [4,] 1 0 1 1 0
# [5,] 1 0 1 0 1
# [6,] 1 0 0 1 1
# [7,] 0 1 1 1 0
# [8,] 0 1 1 0 1
# [9,] 0 1 0 1 1
# [10,] 0 0 1 1 1
Run Code Online (Sandbox Code Playgroud)
这个想法是生成 1 的所有索引组合,然后使用它们产生最终结果。
相同方法的另一种风格:
f.2 <- function(n=5,m=3)
t(combn(1:n,m,FUN=function(cm) replace(rep(0,n),cm,1)))
Run Code Online (Sandbox Code Playgroud)
第二种方法大约快两倍:
library(rbenchmark)
benchmark(f(16,8),f.2(16,8))
# test replications elapsed relative user.self sys.self user.child sys.child
# 2 f.2(16, 8) 100 5.706 1.000 5.688 0.017 0 0
# 1 f(16, 8) 100 10.802 1.893 10.715 0.082 0 0
Run Code Online (Sandbox Code Playgroud)
基准
f.akrun <- function(n=5,m=3) {
indx <- combnPrim(1:n,m)
DT <- setDT(as.data.frame(matrix(0, ncol(indx),n)))
for(i in seq_len(nrow(DT))){
set(DT, i=i, j=indx[,i],value=1)
}
DT
}
benchmark(f(16,8),f.2(16,8),f.akrun(16,8))
# test replications elapsed relative user.self sys.self user.child sys.child
# 2 f.2(16, 8) 100 5.464 1.097 5.435 0.028 0 0
# 3 f.akrun(16, 8) 100 4.979 1.000 4.938 0.037 0 0
# 1 f(16, 8) 100 10.854 2.180 10.689 0.129 0 0
Run Code Online (Sandbox Code Playgroud)
@akrun 的解决方案 ( f.akrun) 比 快约 10% f.2。
[编辑] 另一种方法,更快更简单:
f.3 <- function(n=5,m=3) t(combn(n,m,tabulate,nbins=n))
Run Code Online (Sandbox Code Playgroud)
Marat答案的稍快版本:
f.roland <- function(n, m) {
ind <- combn(seq_len(n), m)
ind <- t(ind) + (seq_len(ncol(ind)) - 1) * n
res <- rep(0, nrow(ind) * n)
res[ind] <- 1
matrix(res, ncol = n, nrow = nrow(ind), byrow = TRUE)
}
all.equal(f.2(16, 8), f.roland(16, 8))
#[1] TRUE
library(rbenchmark)
benchmark(f(16,8),f.2(16,8),f.roland(16,8))
# test replications elapsed relative user.self sys.self user.child sys.child
#2 f.2(16, 8) 100 5.693 1.931 5.670 0.020 0 0
#3 f.roland(16, 8) 100 2.948 1.000 2.929 0.017 0 0
#1 f(16, 8) 100 8.287 2.811 8.214 0.066 0 0
Run Code Online (Sandbox Code Playgroud)