我从List All Combinations With combn 被重定向到这里,因为这是被骗的目标之一。这是一个老问题,@RichScriven 提供的答案非常好,但我想为社区提供一些可以说更自然、更有效的选择(最后两个)。
我们首先注意到输出与Power Set 非常相似。从rje 包中调用powerSet,我们看到我们的输出确实匹配幂集中的每个元素,除了第一个元素等效于Empty Set:
x <- c("red", "blue", "black")
rje::powerSet(x)
[[1]]
character(0) ## empty set equivalent
[[2]]
[1] "red"
[[3]]
[1] "blue"
[[4]]
[1] "red" "blue"
[[5]]
[1] "black"
[[6]]
[1] "red" "black"
[[7]]
[1] "blue" "black"
[[8]]
[1] "red" "blue" "black"
如果您不想要第一个元素,您可以轻松地将 [-1] 添加到函数调用的末尾,如下所示:rje::powerSet(x)[-1]。
接下来的两个解决方案来自较新的包arrangements 和RcppAlgos(我是作者),这将为用户带来极大的效率提升。这两个包都能够生成Multisets 的组合。
为什么这很重要?
可以证明有一个one-to-one mapping从A的幂集到多重集c(rep(emptyElement, length(A)), A)的所有组合选择length(A),其中emptyElement是空集的表示(比如零或空白)。考虑到这一点,请注意:
## There is also a function called combinations in the
## rje package, so we fully declare the function with
## scope operator
library(arrangements)
arrangements::combinations(x = c("",x), k = 3, freq = c(2, rep(1, 3)))
[,1] [,2] [,3]
[1,] "" "" "red"
[2,] "" "" "blue"
[3,] "" "" "black"
[4,] "" "red" "blue"
[5,] "" "red" "black"
[6,] "" "blue" "black"
[7,] "red" "blue" "black"
library(RcppAlgos)
comboGeneral(c("",x), 3, freqs = c(2, rep(1, 3)))
[,1] [,2] [,3]
[1,] "" "" "red"
[2,] "" "" "blue"
[3,] "" "" "black"
[4,] "" "red" "blue"
[5,] "" "red" "black"
[6,] "" "blue" "black"
[7,] "red" "blue" "black"
如果您不喜欢处理空白元素和/或矩阵,您还可以返回一个使用lapply 的列表。
lapply(seq_along(x), comboGeneral, v = x)
[[1]]
[,1]
[1,] "red"
[2,] "blue"
[3,] "black"
[[2]]
[,1] [,2]
[1,] "red" "blue"
[2,] "red" "black"
[3,] "blue" "black"
[[3]]
[,1] [,2] [,3]
[1,] "red" "blue" "black"
lapply(seq_along(x), function(y) arrangements::combinations(x, y))
[[1]]
[,1]
[1,] "red"
[2,] "blue"
[3,] "black"
[[2]]
[,1] [,2]
[1,] "red" "blue"
[2,] "red" "black"
[3,] "blue" "black"
[[3]]
[,1] [,2] [,3]
[1,] "red" "blue" "black"
现在我们证明最后两种方法效率更高(注意,我从@RichSciven 提供的答案中删除了do.call(c, 和simplify = FALSE,以便比较相似输出的生成。我还包括rje::powerSet 好测量):
set.seed(8128)
bigX <- sort(sample(10^6, 20)) ## With this as an input, we will get 2^20 - 1 results.. i.e. 1,048,575
library(microbenchmark)
microbenchmark(powSetRje = powerSet(bigX),
powSetRich = lapply(seq_along(bigX), combn, x = bigX),
powSetArrange = lapply(seq_along(bigX), function(y) arrangements::combinations(x = bigX, k = y)),
powSetAlgos = lapply(seq_along(bigX), comboGeneral, v = bigX),
unit = "relative")
Unit: relative
expr min lq mean median uq max neval
powSetRje 64.4252454 44.063199 16.678438 18.63110 12.082214 7.317559 100
powSetRich 61.6766640 43.027789 16.009151 17.88944 11.406994 7.222899 100
powSetArrange 0.9508052 1.060309 1.080341 1.02257 1.262713 1.126384 100
powSetAlgos 1.0000000 1.000000 1.000000 1.00000 1.000000 1.000000 100
更进一步,arrangements 配备了一个名为layout 的参数,它允许用户为他们的输出选择一种特定的格式。其中之一是layout = "l" 用于列表。它类似于在combn 中设置simplify = FALSE,并允许我们获得类似于powerSet 的输出。观察:
do.call(c, lapply(seq_along(x), function(y) {
arrangements::combinations(x, y, layout = "l")
}))
[[1]]
[1] "red"
[[2]]
[1] "blue"
[[3]]
[1] "black"
[[4]]
[1] "red" "blue"
[[5]]
[1] "red" "black"
[[6]]
[1] "blue" "black"
[[7]]
[1] "red" "blue" "black"
以及基准测试:
microbenchmark(powSetRje = powerSet(bigX)[-1],
powSetRich = do.call(c, lapply(seq_along(bigX), combn, x = bigX, simplify = FALSE)),
powSetArrange = do.call(c, lapply(seq_along(bigX), function(y) arrangements::combinations(bigX, y, layout = "l"))),
times = 15, unit = "relative")
Unit: relative
expr min lq mean median uq max neval
powSetRje 5.539967 4.785415 4.277319 4.387410 3.739593 3.543570 15
powSetRich 4.994366 4.306784 3.863612 3.932252 3.334708 3.327467 15
powSetArrange 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 15 15