2016-05-10 1 views
1

У меня есть матрица с несколькими миллионами строк и около 40 столбцов.Производительность в R: Каков самый быстрый способ сортировки элементов строки в матрице?

Я хочу сортировать элементы в каждой строке так, чтобы их значение уменьшалось. Таким образом, элемент с самым высоким значением каждой строки должен быть в первом столбце.

Для этого я могу использовать функцию apply. Например:

set.seed(1) 
mm <- replicate(10, rnorm(20)) #random matrix with 20 rows and 10 columns 
mm.sorted <- apply(mm,1,sort,decreasing=T) 

Но когда я делаю это для очень большой матрицы, этот подход занимает очень много времени.

Интересно, существуют ли разные подходы к ускорению сортировки элементов в строках.

+1

Вы можете посмотреть руководство для распараллеливания здесь: https://cran.r-project.org/web/views/HighPerformanceComputing.html Я предполагаю, что это будет выглядеть как 'lapply (split (mm, row (mm))), sort) 'но заменяя' lapply' некоторым вариантом, например mclapply – Frank

+1

FYI - 'replicate (10, rnorm (20))]' - это матрица с 20 строками и 10 колонами. – rbm

+0

@rbm: Спасибо! Починил это. –

ответ

6

Вы можете использовать пакет data.table:

set.seed(1) 
mm <- matrix(rnorm(1000000*40,0,10),ncol=40) 
library(data.table) 
system.time({ 
    d <- as.data.table(mm) 
    d[, row := .I] 
    d <- melt(d, id.vars = "row") #wide to long format 
    setkey(d, row, value) #sort 
    d[, variable := paste0("V", ncol(mm):1)] #decreasing order 

    #back to wide format and coerce to matrix 
    msorted <- as.matrix(dcast(d, row ~ variable)[, row := NULL]) 
}) 
#user system elapsed 
#4.96 0.59 5.62 

Если бы вы могли держать его в долгосрочном формате data.table (т.е. пропускается последний шаг), это займет около 2 секунд на моей машине.

Для сравнения, тайминги ответа @qjgods' на моей машине:

#user system elapsed 
#3.71 2.08 8.81 

Обратите внимание, что с помощью apply (или параллельные версии этого) переставляет матрицу.

+0

Я не знаю, как оптимизирован reshape2 ::: melt.matrix, но это может быть другой вариант для первых нескольких шагов, таких как 'd = melt (mm); setDT (d, key = c ("row", "value")) '. И может быть «acast» или что-то еще для обратного пути – Frank

7

использовать параллельный пакет для ускорения

library(parallel) 
data<-matrix(rnorm(1000000*40,0,10),ncol=40) 
cl <- makeCluster(8) # 8 is the number of CPU 
system.time({ 
    parApply(cl,data,1,sort,decreasing=T) 
}) 
    user system elapsed 
    9.68 10.11 29.87 
stopCluster(cl)