我理解外部()在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
Run Code Online (Sandbox Code Playgroud)
它基本上需要2个向量,找到这些向量的交叉积,然后将函数应用于交叉积中的每个对.
但是,我没有两个向量.我有两个矩阵列表:
M = list();
M[[1]] = matrix(...)
M[[2]] = matrix(...)
M[[3]] = matrix(...)
Run Code Online (Sandbox Code Playgroud)
我想在我的matricies列表上做一个操作.我想要做:
outer(M, M, "*")
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我想采用我所拥有的每种矩阵组合的点积.
实际上,我正在尝试生成一个内核矩阵(我已经编写了一个内核函数),所以我想这样做:
outer(M, M, kernelFunction)
Run Code Online (Sandbox Code Playgroud)
在哪里kernelFunction计算我的两个矩阵之间的距离.
问题是outer()只接受"vector"参数,而不是"list"等.是否有一个函数可以为非向量实体执行外部()的等效操作?
或者,我可以使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
但我试图避免这种情况,转而采用R结构(可能效率更高).(是的,我知道我可以修改for循环来计算对角矩阵并节省50%的计算.但那不是我想要优化的代码!)
这可能吗?有什么想法/建议?
Tom*_*mmy 15
外部函数实际上是在列表上工作,但是你提供的函数会重复两个输入向量,以便它们包含所有可能的组合......
至于哪个更快,将外部与vapply结合比我机器上的双重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
Run Code Online (Sandbox Code Playgroud)
had*_*ley 12
只需使用for循环.无论如何,任何内置函数都会退化,并且你将失去表达式的清晰度,除非你仔细地构建一个泛化外部以使用列表的函数.
您可以做的最大改进是预分配矩阵:
M <- list()
length(M) <- numElements ^ 2
dim(M) <- c(numElements, numElements)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)