R中非向量列表的outer()等价项

R中非向量列表的outer()等价项,r,R,我了解outer()在R中的工作原理: > 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=列表() 我想在我的婚姻清单上做个手术。我想做: outer(M, M, "*") outer(M,

我了解outer()在R中的工作原理:

> 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=列表()

我想在我的婚姻清单上做个手术。我想做:

outer(M, M, "*")
outer(M, M, kernelFunction)
在这种情况下,我想取矩阵的每个组合的点积

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

outer(M, M, "*")
outer(M, M, kernelFunction)
其中
kernelFunction
计算两个矩阵之间的距离

问题是outer()只接受“vector”参数,而不是“list”等。是否有一个函数可以对非向量实体执行与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%的计算。但这不是我试图优化的代码!)


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

只需使用for循环即可。不管怎样,任何内置函数都会退化为这种情况,并且您将失去表达的清晰性,除非您仔细构建一个泛化外部以处理列表的函数

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

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

M外部函数实际上对列表有效,但您提供的函数会重复两个输入向量,以便它们包含所有可能的组合

至于哪个更快,将outer和vapply结合起来比我机器上的double for loop快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

f1虽然这是一个老问题,但这里有另一个更符合外部函数精神的解决方案。其思想是沿列表1和列表2的索引应用外部索引:

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