2016-09-24 11 views
2

30.000個の観測値を持つデータフレームの行間のユークリッド距離を計算したい。これを行う簡単な方法は、dist関数(dist(data)など)です。しかし、私のデータフレームが大きいので、これには時間がかかります。ユークリッド距離をより速く計算する

一部の行に欠損値が含まれています。両方の行に欠損値が含まれている行と、行の間に欠落値が含まれていない行間の距離は必要ありません。

for-loopでは、私が必要としない組み合わせを除外しようとしました。残念ながら、私の解決策はさらに時間がかかる:

# Some example data 
data <- data.frame(
    x1 = c(1, 22, NA, NA, 15, 7, 10, 8, NA, 5), 
    x2 = c(11, 2, 7, 15, 1, 17, 11, 18, 5, 5), 
    x3 = c(21, 5, 6, NA, 10, 22, 12, 2, 12, 3), 
    x4 = c(13, NA, NA, 20, 12, 5, 1, 8, 7, 14) 
) 


# Measure speed of dist() function 
start_time_dist <- Sys.time() 

# Calculate euclidean distance with dist() function for complete dataset 
dist_results <- dist(data) 

end_time_dist <- Sys.time() 
time_taken_dist <- end_time_dist - start_time_dist 


# Measure speed of my own loop 
start_time_own <- Sys.time() 

# Calculate euclidean distance with my own loop only for specific cases 

# # # 
# The following code should be faster! 
# # # 

data_cc <- data[complete.cases(data), ] 
data_miss <- data[complete.cases(data) == FALSE, ] 

distance_list <- list() 

for(i in 1:nrow(data_miss)) { 

    distances <- numeric() 
    for(j in 1:nrow(data_cc)) { 
    distances <- c(distances, dist(rbind(data_miss[i, ], data_cc[j, ]), method = "euclidean")) 
    } 

    distance_list[[i]] <- distances 
} 

end_time_own <- Sys.time() 
time_taken_own <- end_time_own - start_time_own 


# Compare speed of both calculations 
time_taken_dist # 0.002001047 secs 
time_taken_own # 0.01562881 secs 

は私が必要とのユークリッド距離を計算することができる方法より高速な方法はありますか?どうもありがとう!

+2

distがCで実装されているのはもちろんですが、R forループよりも高速です。 Rcppにループを実装する必要があります。 – Roland

+0

ヒントありがとう!私はこれがどのように機能するかを理解しようとします。 – JSP

答えて

3

並列計算を使用することをお勧めします。すべてのコードを1つの関数に入れて並列化します。

Rはデフォルトですべての計算を1つのスレッドで行います。並列スレッドを手動で追加する必要があります。 Rでクラスタを起動するには時間がかかりますが、データフレームが大きい場合、メインジョブのパフォーマンスは(your_processors_number-1)倍になります。

このリンクも役立ちます:How-to go parallel in R – basics + tipsおよびA gentle introduction to parallel computing in R

ジョブをより小さいパックに分割し、各スレッドで個別に計算することをお勧めします。

library(parallel) 
library(foreach) 
library(doParallel) 
# I am not sure that all libraries are here 
# try ??your function to determine which library do you need 
# determine how many processors has your computer 
no_cores <- detectCores() - 1# one processor must be free always for system 
start.t.total<-Sys.time() 
print(start.t.total) 
startt<-Sys.time() 
print(startt) 
#start parallel calculations 
cl<-makeCluster(no_cores,outfile = "mycalculation_debug.txt") 
registerDoParallel(cl) 
# results will be in out.df class(dataframe) 
out.df<-foreach(p=1:no_cores 
        ,.combine=rbind # data from different threads will be in one table 
        ,.packages=c()# All packages that your funtion is using must be called here 
        ,.inorder=T) %dopar% #don`t forget this directive 
        { 
         tryCatch({ 
          # 
          # enter your function here and do what you want in parallel 
          # 
          print(startt-Sys.time()) 
          print(start.t.total-Sys.time()) 
          print(paste(date,'packet',p, percent((x-istart)/packes[p]),'done')) 
         } 
         out.df 
         },error = function(e) return(paste0("The variable '", p, "'", 
                  " caused the error: '", e, "'"))) 
        } 
stopCluster(cl) 
gc()# force to free memory from killed processes 
+0

お返事ありがとうございました。私はこれがRで可能であることを知らず、あなたのソリューションを実装しようとします! – JSP

+0

あなた自身の関数を作成したくない場合、 'amap'パッケージがここで役立つと思います。この[answer](http://stackoverflow.com/a/25767588/6327771)をチェックしてください –

関連する問題