我无法在任何地方找到答案,所以这是我的解决方案。
问题是:如何计算R中的功率?
可以使用库“sets”使用命令2^as.set(c(1,2,3,4))
执行此操作,这将生成输出{{}, {1}, {2}, {3}, {4}, {1, 2}, {1, 3}, {1, 4}, {2, 3}, {2,
4}, {3, 4}, {1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}, {1,
2, 3, 4}}
。但是,这使用了递归算法,这种算法相当慢。
这是我提出的算法。
它是非递归的,所以它比其他一些解决方案快得多(在我的机器上比“sets”包中的算法快约100倍)。速度仍为O(2 ^ n)。
该算法的概念基础如下:
for each element in the set:
for each subset constructed so far:
new subset = (subset + element)
这是R代码:
编辑:这是同一概念的更快版本;我原来的算法是在这篇文章的第三条评论中。对于一组19的长度,这台机器在我的机器上快30%。powerset = function(s){
len = length(s)
l = vector(mode="list",length=2^len) ; l[[1]]=numeric()
counter = 1L
for(x in 1L:length(s)){
for(subset in 1L:counter){
counter=counter+1L
l[[counter]] = c(l[[subset]],s[x])
}
}
return(l)
}
此版本通过在开始时使用其最终长度启动向量来保存时间,并使用保存新子集的位置的“计数器”变量进行跟踪。也可以通过分析计算位置,但这稍微慢一些。
答案 0 :(得分:11)
可以将子集视为布尔向量,指示元素是否在not的子集中。
那些布尔向量可以看作是用二进制写的数字。
枚举1:n
的所有子集
因此,相当于枚举从0
到2^n-1
的数字。
f <- function(set) {
n <- length(set)
masks <- 2^(1:n-1)
lapply( 1:2^n-1, function(u) set[ bitwAnd(u, masks) != 0 ] )
}
f(LETTERS[1:4])
答案 1 :(得分:4)
包powerset
中有一个函数HapEstXXR
,它似乎比你的函数和另一个答案中的函数更快。请参阅下文(您的函数称为your.powerset
)
require('microbenchmark')
require('HapEstXXR')
microbenchmark(powerset(LETTERS[1:10]), f(LETTERS[1:10]), your.powerset(LETTERS[1:10]), times=100)
Unit: microseconds
expr min lq median uq max neval
powerset(LETTERS[1:10]) 314.845 388.4225 594.2445 686.6455 857.513 100
f(LETTERS[1:10]) 7144.132 7937.6040 8222.1330 8568.5120 17805.335 100
your.powerset(LETTERS[1:10]) 5016.981 5564.2880 5841.9810 6025.0690 29138.763 100
由于powerset
似乎非常快,您可能需要查看HapEstXXR
包中函数的代码。
答案 2 :(得分:2)
这是另一种似乎对小型套装表现相当不错的简单方法。随着数据基数的增加,这种方法存在明显的内存问题。
getPowSet <- function(set) {
n <- length(set)
keepBool <- sapply(2^(1:n - 1), function(k)
rep(c(FALSE, TRUE), each=k, times=(2^n / (2*k))))
lapply(1:2^n, function(j) set[keepBool[j, ]])
}
n=10
的速度比较:
microbenchmark(powerset(LETTERS[1:10]), f(LETTERS[1:10]), getPowSet(LETTERS[1:10]))
Unit: milliseconds
expr min lq mean median uq max neval
powerset(LETTERS[1:10]) 2.466167 2.551928 2.656964 2.581211 2.637358 3.676877 100
f(LETTERS[1:10]) 2.923339 3.029928 3.115222 3.104413 3.175931 4.033136 100
getPowSet(LETTERS[1:10]) 2.415290 2.490522 2.574131 2.547115 2.617198 3.664040 100
但是对于n=15
,原始函数似乎表现得更好:
microbenchmark(powerset(LETTERS[1:15]), f(LETTERS[1:15]), getPowSet(LETTERS[1:15]))
Unit: milliseconds
expr min lq mean median uq max neval
powerset(LETTERS[1:15]) 81.48276 88.50272 94.88927 91.61366 94.8262 174.0636 100
f(LETTERS[1:15]) 110.86208 118.08736 124.38501 122.35872 126.7830 189.3131 100
getPowSet(LETTERS[1:15]) 86.16286 93.32314 98.14936 96.85443 100.6075 159.1030 100
答案 3 :(得分:1)
下面应该创建一个功率集,减去空的set元素。
powerset <- function(x) {
sets <- lapply(1:(length(x)), function(i) combn(x, i, simplify = F))
unlist(sets, recursive = F)
}