繁体   English   中英

R中的非向量列表的external()等效项

[英]outer() equivalent for non-vector lists in R

我了解在R中external()是如何工作的:

> outer(c(1,2,4),c(8,16,32), "*")

     [,1] [,2] [,3]
[1,]    8   16   32
[2,]   16   32   64
[3,]   32   64  128

它基本上采用2个向量,找到这些向量的叉积,然后将函数应用于叉积中的每一对。

但是,我没有两个向量。 我有两个矩阵列表:

M = list();

M[[1]] = matrix(...)
M[[2]] = matrix(...)
M[[3]] = matrix(...)

我想对矩阵列表进行操作。 我想要做:

outer(M, M, "*")

在这种情况下,我要获取我拥有的每种矩阵组合的点积。

实际上,我正在尝试生成内核矩阵(并且我已经编写了内核函数),所以我想这样做:

outer(M, M, kernelFunction)

其中, kernelFunction计算两个矩阵之间的距离。

问题在于,outer()仅接受“向量”参数,而不是“列表”等。是否有一个函数对非向量实体而言等效于outer()?

或者,我可以使用for循环来执行此操作:

M = list() # Each element in M is a matrix

for (i in 1:numElements)
{
   for (j in 1:numElements)
   {
      k = kernelFunction(M[[i]], M[[j]])
      kernelMatrix[i,j] = k;
   }
} 

但我试图避免这种情况,而推荐使用R构造(可能会更有效)。 (是的,我知道我可以修改for循环以计算对角矩阵并节省50%的计算。但这不是我要优化的代码!)

这可能吗? 有什么想法/建议吗?

外部函数确实在列表上起作用,但是您提供的函数会重复获取两个输入向量,以便它们包含所有可能的组合...

至于哪一个更快,将external与vapply组合起来比我的机器上的double for循环快3倍。 如果实际的内核功能确实“起作用”,则循环速度的差异可能并不那么重要。

f1 <- function(a,b, fun) {
  outer(a, b, function(x,y) vapply(seq_along(x), function(i) fun(x[[i]], y[[i]]), numeric(1)))
}

f2 <- function(a,b, fun) {
    kernelMatrix <- matrix(0L, length(a), length(b))
    for (i in seq_along(a))
    {
       for (j in seq_along(b))
       {
          kernelMatrix[i,j] = fun(a[[i]], b[[j]])
       }
    }
    kernelMatrix
}

n <- 300
m <- 2
a <- lapply(1:n, function(x) matrix(runif(m*m),m))
b <- lapply(1:n, function(x) matrix(runif(m*m),m))
kernelFunction <- function(x,y) 0 # dummy, so we only measure the loop overhead

> system.time( r1 <- f1(a,b, kernelFunction) )
   user  system elapsed 
   0.08    0.00    0.07 
> system.time( r2 <- f2(a,b, kernelFunction) )
   user  system elapsed 
   0.23    0.00    0.23 
> identical(r1, r2)
[1] TRUE

只需使用for循环。 无论如何,任何内置函数都将退化为该函数,除非您仔细构建一个泛化到列表之外的函数,否则您将失去表达的清晰度。

您可以做的最大改进就是预分配矩阵:

M <- list()
length(M) <- numElements ^ 2
dim(M) <- c(numElements, numElements)

PS。 列表是一个向量。

尽管这是一个古老的问题,但这是另一个解决方案,它更多地体现了外部功能的精神。 这个想法是沿着list1和list2的索引应用外部的:

cor2 <- Vectorize(function(x,y) {
   vec1 <- list1[[x]]
   vec2 <- list2[[y]]
   cor(vec1,vec2,method="spearman")
})
outer(1:length(list1), 1:length(list2), cor2)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM