简体   繁体   English

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

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

I understand how outer() works 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

It basically takes 2 vectors, finds the crossproduct of those vectors, and then applies the function to each pair in the crossproduct. 它基本上采用2个向量,找到这些向量的叉积,然后将函数应用于叉积中的每一对。

I don't have two vectors, however. 但是,我没有两个向量。 I have two lists of matrices: 我有两个矩阵列表:

M = list(); M = list();

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

And I want to do an operation on my list of matricies. 我想对矩阵列表进行操作。 I want to do: 我想要做:

outer(M, M, "*")

In this case, I want to take the dot product of each combination of matrices I have. 在这种情况下,我要获取我拥有的每种矩阵组合的点积。

Actually, I am trying to generate a kernel matrix (and I have written a kernel function), so I want to do: 实际上,我正在尝试生成内核矩阵(并且我已经编写了内核函数),所以我想这样做:

outer(M, M, kernelFunction)

where kernelFunction calculates a distance between my two matrices. 其中, kernelFunction计算两个矩阵之间的距离。

The problem is that outer() only takes "vector" arguments, rather than "list"s etc. Is there a function that does the equivalent of outer() for non-vector entities? 问题在于,outer()仅接受“向量”参数,而不是“列表”等。是否有一个函数对非向量实体而言等效于outer()?

Alternately, I could use a for-loop to do this: 或者,我可以使用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;
   }
} 

but I am trying to avoid this in favor of an R construct (which might be more efficient). 但我试图避免这种情况,而推荐使用R构造(可能会更有效)。 (Yes I know I can modify the for-loop to compute the diagonal matrix and save 50% of the computations. But that's not the code that I'm trying to optimize!) (是的,我知道我可以修改for循环以计算对角矩阵并节省50%的计算。但这不是我要优化的代码!)

Is this possible? 这可能吗? Any thoughts/suggestions? 有什么想法/建议吗?

The outer function actually DOES work on lists, but the function that you provide gets the two input vectors repeated so that they contain all possible combinations... 外部函数确实在列表上起作用,但是您提供的函数会重复获取两个输入向量,以便它们包含所有可能的组合...

As for which is faster, combining outer with vapply is 3x faster than the double for-loop on my machine. 至于哪一个更快,将external与vapply组合起来比我的机器上的double for循环快3倍。 If the actual kernel function does "real work", the difference in looping speed is probably not so important. 如果实际的内核功能确实“起作用”,则循环速度的差异可能并不那么重要。

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

Just use the for loop. 只需使用for循环。 Any built-in functions will degenerate to that anyway, and you'll lose clarity of expression, unless you carefully build a function that generalises outer to work with lists. 无论如何,任何内置函数都将退化为该函数,除非您仔细构建一个泛化到列表之外的函数,否则您将失去表达的清晰度。

The biggest improvement you could make would be to preallocate the matrix: 您可以做的最大改进就是预分配矩阵:

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

PS. PS。 A list is a vector. 列表是一个向量。

Although this is an old question, here is another solution that is more in the spirit of the outer function. 尽管这是一个古老的问题,但这是另一个解决方案,它更多地体现了外部功能的精神。 The idea is to apply outer along the indices of list1 and list2: 这个想法是沿着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