2012-05-25 44 views
3

我想計算兩個矩陣/數據幀之間所有行組合的距離度量。計算R中兩個矩陣的所有行組合的函數

結果將是具有單元i,j的矩陣,其對應於由應用於第一矩陣的第i行和第二矩陣的第j行的函數給出的結果。這裏是一個例子,說明我想用循環做什麼,並帶有一個示例函數。

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循環的情況下提示。

回答

4
outer(1:nrow(x), 1:nrow(y), Vectorize(function(i, j) sum(x[i, ] * y[j, ]))) 
+0

看起來不錯。雖然可能沒有比for循環更快,也可能更慢。 –

+0

@DWin是對的。我嘗試了這種方法,我很驚訝的是,「外部」加「矢量化」方法至少與for循環一樣長(儘管我不知道在完成之前我切斷了多長時間)。最後,我發現我可以將我的功能分解成可以使用apply和matrix代數計算的部分,並且這與大約1天相比可以在幾秒鐘內計算出一些大的數據幀。但是,我擔心我不能用其他功能做到這一點。 – klar

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和子集,我們可以比for循環快20倍,當行組合的數量僅僅是如果你有更多的速度差異會更大。

HTH。