2016-09-24 17 views
2

Ich möchte die euklidischen Abstände zwischen Zeilen eines Datenrahmens mit 30.000 Beobachtungen berechnen. Ein einfacher Weg, dies zu tun, ist die Funktion dist (z. B. dist (Daten)). Da mein Datenrahmen jedoch groß ist, benötigt dies zu viel Zeit.Berechnen Sie den euklidischen Abstand schneller

Einige der Zeilen enthalten fehlende Werte. Ich brauche nicht die Abstände zwischen Zeilen, in denen beide Zeilen fehlende Werte enthalten, oder zwischen Zeilen, in denen keine der Zeilen fehlende Werte enthält.

In einer For-Schleife habe ich versucht, die Kombinationen auszuschließen, die ich nicht brauche. Leider nimmt meine Lösung noch mehr Zeit:

# 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 

Gibt es einen schnelleren Weg, wie ich die euklidischen Entfernungen berechnen könnte, die ich brauche? Danke vielmals!

+2

dist ist in C implementiert, natürlich ist es schneller als eine R for-Schleife. Sie sollten Ihre Schleife in Rcpp implementieren. – Roland

+0

Danke für den Hinweis! Ich werde versuchen herauszufinden, wie das funktioniert. – JSP

Antwort

3

Ich empfehle Ihnen, parallele Berechnungen zu verwenden. Setzen Sie all Ihren Code in eine Funktion und tun Sie es parallel.

R wird standardmäßig alle Berechnungen in einem Thread durchführen. Sie sollten parallele Threads manuell hinzufügen. Das Starten von Clustern in R benötigt Zeit. Wenn Sie jedoch einen großen Datenrahmen haben, ist die Leistung des Hauptjobs (your_processors_number-1) um ein Vielfaches schneller.

Diese Links können auch helfen: How-to go parallel in R – basics + tips und A gentle introduction to parallel computing in R.

Eine gute Wahl ist es, Ihre Arbeit in kleinere Packungen aufzuteilen und sie in jedem Thread separat zu berechnen. Erstellen Sie Threads nur einmal, weil es in R. zeitaufwendig ist.

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

Vielen Dank für Ihre Antwort, das hilft mir sehr! Ich wusste nicht einmal, dass dies mit R möglich ist und werde versuchen, Ihre Lösung zu implementieren! – JSP

+0

Ich denke, "Amap" -Paket könnte hier hilfreich sein, wenn Sie keine eigenen Funktionen erstellen möchten, überprüfen Sie diese [Antwort] (http://stackoverflow.com/a/25767588/6327771) heraus –

Verwandte Themen