【问题标题】:outer() equivalent for non-vector lists in R外部()等效于R中的非向量列表
【发布时间】:2009-11-12 02:07:18
【问题描述】:

我了解 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 = 列表();

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% 的计算量。但这不是我要优化的代码!)

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

【问题讨论】:

    标签: r


    【解决方案1】:

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

    至于哪个更快,结合 external 和 vapply 比我机器上的双 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
    

    【讨论】:

      【解决方案2】:

      只需使用 for 循环。无论如何,任何内置函数都会退化为这种情况,并且您将失去表达的清晰度,除非您仔细构建一个泛化外部的函数以使用列表。

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

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

      PS。列表就是一个向量。

      【讨论】:

        【解决方案3】:

        虽然这是一个老问题,但这里有另一个更符合外部函数精神的解决方案。这个想法是沿着list1和list2的索引应用outer:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-01
          • 2020-09-23
          • 2021-09-27
          • 2013-03-14
          • 2015-11-16
          • 1970-01-01
          • 1970-01-01
          • 2011-06-05
          相关资源
          最近更新 更多