2016-09-24 18 views
2

Я хочу рассчитать эвклидовы расстояния между строками кадра данных с 30 000 наблюдений. Простым способом сделать это является функция dist (например, dist (data)). Однако, поскольку мой блок данных большой, это занимает слишком много времени.Вычислить эвклидовое расстояние более быстрым способом

Некоторые из строк содержат отсутствующие значения. Мне не нужны расстояния между строками, где обе строки содержат отсутствующие значения или между строками, где ни одна из строк не содержит отсутствующих значений.

В течение цикла я попытался исключить комбинации, которые мне не нужны. К сожалению, мое решение занимает еще больше времени:

# 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. Вы должны реализовать свой цикл в Rcpp. – Roland

+0

Спасибо за подсказку! Я попытаюсь выяснить, как это работает. – JSP

ответ

3

Я рекомендую использовать параллельные вычисления. Поместите весь свой код в одну функцию и сделайте это параллельно.

R будет выполнять все вычисления в одном потоке по умолчанию. Вы должны добавить параллельные потоки вручную. Запуск кластеров в R потребует времени, но если у вас большой кадр данных, производительность основного задания будет (your_processors_number-1) раз быстрее.

Данные ссылки могут также помочь: How-to go parallel in R – basics + tips и A gentle introduction to parallel computing in R.

Хороший выбор состоит в том, чтобы разделить работу на более мелкие упаковки и рассчитать их отдельно в каждом потоке. Создавайте темы только один раз, потому что это занимает много времени в 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' может быть полезен здесь, если вы не хотите создавать свои собственные функции, проверьте этот [ответ] (http://stackoverflow.com/a/25767588/6327771) –