【问题标题】:combn() function in rr中的combn()函数
【发布时间】:2014-04-17 18:03:24
【问题描述】:

我正在尝试对所有可能的向量组合执行点积。我能够找到所有可能的组合。我只是不太明白 combn() 中的 FUN 参数是如何工作的。以下是我的代码,感谢您的帮助!

def=c("Normal.def","Fire.def","Water.def","Electric.def","Grass.def","Ice.def",
       "Fighting.def","Poison.def","Ground.def","Flying.def","Pyschic.def","Bug.def",
       "Rock.def","Ghost.def","Dragon.def","Null.def")

combn(def,2,FUN=def%*%def,simplify=TRUE)

【问题讨论】:

  • 你能发布一些你希望做什么的示例输入和输出吗? combn 可能不是您开始任务的最佳函数......

标签: r dot-product combn


【解决方案1】:

使用@BrodieG 的示例数据,您可以只使用crossprod 函数:

set.seed(1)
vec1 <- sample(1:10)
vec2 <- sample(1:10)
vec3 <- sample(1:10)

crossprod(cbind(vec1, vec2, vec3))
#      vec1 vec2 vec3
# vec1  385  298  284
# vec2  298  385  296
# vec3  284  296  385

出于好奇,一些基准测试:

要运行的函数:

fun1 <- function() {
  A <- crossprod(do.call(cbind, lst))
  A[upper.tri(A)]
} 
fun2 <- function() {
  A <- do.call(rbind, lst) %*% do.call(cbind, lst)
  A[upper.tri(A)]
} 
fun3 <- function() {
  combn(
    seq_along(lst), 2, 
    FUN=function(idx) c(lst[[idx[[1]]]] %*% lst[[idx[[2]]]])
  )
}

“少量大向量”的基准测试。

library(microbenchmark)

set.seed(1)
n <- 5
lst <- setNames(replicate(n, sample(1:100000), simplify = FALSE), 
                paste0("V", sequence(n)))

microbenchmark(fun1(), fun2(), fun3())
# Unit: milliseconds
#    expr       min        lq    median        uq      max neval
#  fun1()  6.909651  6.992031  8.432346  8.520301 74.12263   100
#  fun2() 17.290101 18.811134 19.144601 21.292544 88.10602   100
#  fun3() 22.841209 24.283113 24.427876 25.820158 91.14007   100

没有足够的耐心对中等数量的中等向量进行基准测试:

set.seed(1)
n <- 1000
lst <- setNames(replicate(n, sample(1:1000), simplify = FALSE), 
                paste0("V", sequence(n)))

system.time(fun1())
#   user  system elapsed 
#  0.245   0.004   0.251 

system.time(fun2())
#   user  system elapsed 
#  0.407   0.016   0.425 

system.time(fun3())
#   user  system elapsed 
# 14.216   0.004  14.339 

【讨论】:

  • crossprod 似乎始终排在首位,但我能够比t(mx) %*% mx(其中mx == cbind(...))更快地获得combn,每个向量都有1e6 长。我很惊讶crossprodt(mx) %*% mx 之间存在如此大的差异,因为它们做同样的事情,而后者几乎都是内部 c 代码;此外,转置只占两者差异的一小部分。
  • 实际上,来自?crossprod,正如您可能看到的那样:这在形式上等同于(但通常略快于)调用 t(x) %*% y (crossprod) 或 x %*% t(y) (tcrossprod)。但实际上差异很大。
  • @BrodieG,不幸的是,我不喜欢 R 中的帮助页面的一件事是没有时间线。虽然我们可能会增加包的版本号等等,但这并不意味着文档发生了变化,也不意味着所有功能都发生了变化。谁知道文档是在何时或在什么条件下编写的,或者何时(如果有的话)函数变得更快。
  • 啊哈,crossprod(mx, mx) 的速度是crossprod(mx) 的两倍(至少在我引用的 3 列示例中)。与t(mx) %*% mx 进行比较时,他们一定是引用了第一个用例。但是,是的,我经常发现文档中缺乏细节令人恼火。
  • 有没有办法采用这种方法来做 12 个向量的点积,而不仅仅是 2 个?
【解决方案2】:

你为什么不把整个东西矩阵相乘。例如:

set.seed(1)
vec1 <- sample(1:10)
vec2 <- sample(1:10)
vec3 <- sample(1:10)

rbind(vec1, vec2, vec3) %*% cbind(vec1, vec2, vec3)

产生:

     vec1 vec2 vec3
vec1  385  298  284
vec2  298  385  296
vec3  284  296  385

矩阵的每个单元格是 col 和 row 标签中两个向量的点积。或者,如果你真的想使用combn

vec.lst <- list(vec1, vec2, vec3)
combn(
  seq_along(vec.lst), 2, 
  FUN=function(idx) c(vec.lst[[idx[[1]]]] %*% vec.lst[[idx[[2]]]])
)

产生:

[1] 298 284 296

注意这些数字如何对应于矩阵的上三角形。对于小型数据集,矩阵乘法方法要快得多。对于大型的,特别是那些向量非常大但数量不多的向量,combn 方法可能会更快,因为它不会运行尽可能多的计算(基本上只有上三角形)。

【讨论】:

  • 我无法提供combn 遥遥领先的示例数据。 crossprod 排在首位,但是您提出的 cbind/rbind 方法也很有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多