我想计算两个矩阵/数据帧之间所有行组合的距离度量。
结果将是具有单元i,j的矩阵,其对应于由应用于第一矩阵的行i和第二矩阵的行j的函数给出的结果。这是一个示例,通过示例函数说明我想要对for循环做什么。
x<-matrix(rnorm(30),10,3) ## Example data
y<-matrix(rnorm(12),4,3)
results<-matrix(NA,nrow(x),nrow(y))
for (i in 1:nrow(x)){
for (j in 1:nrow(y)){
r1<-x[i,]
r2<-y[j,]
results[i,j]<-sum(r1*r2) ## Example function
}
}
在现实生活中我有第一个矩阵有几十万行,第二个矩阵有几百行,我想要计算的函数不是点积(我意识到我可能选择了一个函数使得看起来我想做的就是矩阵乘法。事实上,我想替换一些函数,所以我想找到一个可以推广到不同函数的解决方案。考虑它的一种方法是我想劫持矩阵乘法来执行其他功能。使用for循环计算它需要很长时间,这是不切实际的。如果没有for循环,我会非常感激如何做到这一点。
答案 0 :(得分:4)
outer(1:nrow(x), 1:nrow(y), Vectorize(function(i, j) sum(x[i, ] * y[j, ])))
答案 1 :(得分:2)
我知道你很久以前就问过这个问题,但我认为我可能与你共享一个解决方案,与for
循环相比,当你拥有的行数变得非常大时,它会变得更有效率。在少量行中,速度差异可以忽略不计(并且for循环甚至可以更快)。这仅依赖于子集和rowSums的使用,并且非常简单:
## For reproducibility
set.seed( 35471 )
## Example data - bigger than the original to get and idea of difference in speed
x<-matrix(rnorm(60),20,3)
y<-matrix(rnorm(300),100,3)
# My function which uses grid.expand to get all combinations of row indices, then rowSums to operate on them
rs <- function( x , y ){
rows <- expand.grid( 1:nrow(x) , 1:nrow(y) )
results <- matrix( rowSums( x[ rows[,1] , ] * y[ rows[,2] , ] ) , nrow(x) , nrow(y) )
return(results)
}
# Your orignal function
flp <- function(x ,y){
results<-matrix(NA,nrow(x),nrow(y))
for (i in 1:nrow(x)){
for (j in 1:nrow(y)){
r1<-x[i,]
r2<-y[j,]
results[i,j]<-sum(r1*r2) ## Example function
}
}
return(results)
}
## Benchmark timings:
library(microbenchmark)
microbenchmark( rs( x, y ) , flp( x ,y ) , times = 100L )
#Unit: microseconds
# expr min lq median uq max neval
# rs(x, y) 487.500 527.396 558.5425 620.486 679.98 100
# flp(x, y) 9253.385 9656.193 10008.0820 10430.663 11511.70 100
## And a subset of the results returned from each function to confirm they return the same thing!
flp(x,y)[1:3,1:3]
# [,1] [,2] [,3]
#[1,] -0.5528311 0.1095852 0.4461507
#[2,] -1.9495687 1.7814502 -0.3769874
#[3,] 1.8753978 -3.0908057 2.2341414
rs(x,y)[1:3,1:3]
# [,1] [,2] [,3]
#[1,] -0.5528311 0.1095852 0.4461507
#[2,] -1.9495687 1.7814502 -0.3769874
#[3,] 1.8753978 -3.0908057 2.2341414
所以你可以看到,通过使用rowSums
和子集,当行组合的数量只有2000时,我们可以比for循环快20倍。如果你有更多,速度的差异会更大
HTH。