我想找到计算子集数量的最快方法
vec
从逻辑矩阵定义的cols all TRUE
:
mlgl <- structure(c(FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE,
FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE,
FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE,
TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE,
FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE,
TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE,
FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE), .Dim = c(15L, 5L
), .Dimnames = list(NULL, c("l1", "l2", "l3", "l4", "l5")))
mlgl
#> l1 l2 l3 l4 l5
#> [1,] FALSE FALSE FALSE FALSE FALSE
#> [2,] TRUE FALSE FALSE FALSE TRUE
#> [3,] FALSE TRUE FALSE FALSE FALSE
#> [4,] FALSE FALSE TRUE FALSE FALSE
#> [5,] TRUE TRUE FALSE FALSE TRUE
#> [6,] TRUE FALSE TRUE FALSE TRUE
#> [7,] TRUE FALSE FALSE TRUE TRUE
#> [8,] FALSE TRUE TRUE FALSE FALSE
#> [9,] FALSE TRUE FALSE TRUE FALSE
#> [10,] FALSE FALSE TRUE TRUE FALSE
#> [11,] TRUE TRUE TRUE FALSE TRUE
#> [12,] TRUE TRUE FALSE TRUE TRUE
#> [13,] TRUE FALSE TRUE TRUE TRUE
#> [14,] FALSE TRUE TRUE TRUE FALSE
#> [15,] TRUE TRUE TRUE TRUE TRUE
由vec
定义的子集的向量:
vec <- c("l1", "l3")
我想知道vec
中的所有变量都是TRUE
的次数。对于
这个vec的预期答案是4
(第6,11,13和15行)。最快的
我能想到这样做的方式是:
sum(rowSums(mlgl[,vec]) == length(vec))
#> [1] 4
compiler :: cpmfun对这两种方法都没有帮助:
microbenchmark(
sum(apply(mlgl[, vec], 1, all)),
sum(rowSums(mlgl[,vec]) == length(vec)),
unit = "eps"
)
#> Unit: evaluations per second
#> expr min lq mean
#> sum(apply(mlgl[, vec], 1, all)) 4416.649 14013.85 13696.17
#> sum(rowSums(mlgl[, vec]) == length(vec)) 27348.557 63477.96 67712.96
#> median uq max neval cld
#> 14210.30 14397.81 14766.03 100 a
#> 65017.46 75503.08 81175.42 100 b
我希望有一些替代解决方案或建议可以做得更好 这在R或RCpp。
更新:添加了一些有用的解决方案作为答案......但是另一个数量级会很好。
答案 0 :(得分:3)
我们可以通过使用整数向量来选择列而不是字符向量来提高速度。使用此方法,没有名称匹配或使用幕后发生的任何属性。我们会尝试fmatch()
和match()
。
标记为integer
的以下行只显示单独使用整数向量的速度。
library(fastmatch)
microbenchmark(
fmatch = sum(rowSums(mlgl[, fmatch(vec, colnames(mlgl))]) == length(vec)),
match = sum(rowSums(mlgl[, match(vec, colnames(mlgl))]) == length(vec)),
integer = sum(rowSums(mlgl[, c(1L, 3L)]) == length(vec)),
unit = "eps"
)
# Unit: evaluations per second
# expr min lq mean median uq max neval
# fmatch 16146.74 49468.25 50143.24 50823.34 52064.45 54404.00 100
# match 45108.03 58503.55 59741.99 59724.68 61135.91 64930.85 100
# integer 41023.96 80411.72 81827.19 83004.78 85429.93 88944.23 100
实际上我们似乎不需要加载 fastmatch ,因为match()
做得更好。总的来说,使用整数向量而不是字符名称匹配肯定会提高速度。
我很有信心很快会发布一个很快的Rcpp答案。
更新:使用which()
和length()
的另一种方法也非常好。
microbenchmark(
which = length(which(rowSums(mlgl[, vec]) == length(vec))),
unit = "eps"
)
# Unit: evaluations per second
# expr min lq mean median uq max neval
# which 26816.12 81502.91 81858.62 83156.76 84566.6 87850.3 100
答案 1 :(得分:3)
mlgl <- structure(c(FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE,
FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE,
FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE,
TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE,
FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE,
TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE,
FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE), .Dim = c(15L, 5L
), .Dimnames = list(NULL, c("l1", "l2", "l3", "l4", "l5")))
vec <- c("l1", "l3")
初始sol'n
initial <- function() {
sum(rowSums(mlgl[,vec]) == length(vec))
}
.Internal(...
sol'n(真的不允许)
current <- function() {
sml <- mlgl[,vec]
dims <- dim(sml)
sum(.Internal(rowSums(sml, dims[1], dims[2], FALSE)) == dims[2])
}
因此我尝试使用c ++进行简单的解决方案:
Rcpp::cppFunction('int cpp_sum_trues(LogicalMatrix x) {
int nrow = x.nrow(), ncol = x.ncol();
int out = 0;
for (int i = 0; i < nrow; i++) {
int total = 0;
for (int j = 0; j < ncol; j++) {
total += x(i, j);
}
if (total == ncol) {
out += 1;
}
}
return out;
}')
a_cpp_soln <- function() {
sml <- mlgl[,vec]
cpp_sum_trues(sml)
}
定时:
microbenchmark(initial(), current(), a_cpp_soln(), times = 1e3, unit = "eps")
#> Unit: evaluations per second
#> expr min lq mean median uq max
#> initial() 13468.01 69223.31 70388.61 71622.98 74239.05 81652.65
#> current() 22163.12 161407.47 168268.59 169319.34 180619.56 211595.43
#> a_cpp_soln() 28041.84 140007.02 151792.51 152288.15 167841.56 186950.83
#> neval cld
#> 1000 a
#> 1000 c
#> 1000 b