2009-11-12 74 views
7

非向量列表我明白如何外()按R:外()等效于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 = list();

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

而且我想我matricies的名单上再做一次手术。我想要做的:

outer(M, M, "*") 

在这种情况下,我想采取每个矩阵组合的点积。

其实,我试图生成一个内核矩阵(和我写了一个内核函数),所以我想做的事:

outer(M, M, kernelFunction) 

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

问题是,外()只需要“向量”的参数,而不是“列表”等等。有没有一个函数,做非等值的外部()为非矢量实体?

或者,我可以用一个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%的计算量,但这不是我想优化的代码!)

这可能吗?任何想法/建议?

回答

10

只需使用for循环。任何内置的函数都会退化为这种情况,除非您仔细地构建了一个将outer泛化以使用list的函数,否则您将失去表达的清晰度。

你能犯的最大改进是预分配矩阵:

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

PS。列表是一个向量。

13

外部函数实际上不会对名单的工作,但您提供的功能得到重复的两个输入向量,使它们包含所有可能的组合...

至于这是更快,结合外与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 
3

虽然这是一个老问题,但下面是另外一个解决方案,它更多的是外在函数的精神。该想法是沿着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)