Эффективная стратегия для вычисления группировки матричных операций по вектору - PullRequest
0 голосов
/ 07 февраля 2019

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

Строки - это переменные, которые я хочу сгруппировать, а столбцы -samples.

Например:

mat = matrix(seq(1,10000), ncol  = 100)
vect_group = c(1,1,1,1,1,2,2,2,3,3,3, ...)

Я хочу вычислить среднее значение по столбцам всех строк с индексами 1, 2, 3 и так далее.Итак, в этом случае, получите что-то новое в матрице с таким количеством строк, сколько уровней vect_group и соответствующей статистикой в ​​сопоставленном столбце.

До сих пор я получал эту циклическую обработку по индексам и использовал apply onэти подматрицы каждый раз, но я хотел бы ускорить процедуру.Я пробовал doParallel и foreach, но безуспешно.

Ключевой частью, с которой я борюсь, является процедура расщепления / агрегирования для получения меньших матриц.Кроме того, я не знаю, повлияют ли накладные расходы на выбор многопоточных вычислений.

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

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

Вероятно, самый быстрый способ не параллельно - использовать data.table.Ниже описаны некоторые способы сделать это, включая предыдущий ответ (хотя я не могу запустить версию dplyr на своем компьютере - я думаю, что mat не имеет имен столбцов).Data.table занимает в среднем около 3 миллисекунд, а агрегат не за горами.

mat <-  matrix(seq(1,10000), ncol  = 100)
vect_group  = rep(1:10, each = 10)

fn1_agg <- function(mat, vg) {
  aggregate(c(mat)~rep(vg, ncol(mat)), FUN = mean)
}

fn2_dt <- function(mat, vg){
  DT <- data.table::data.table(m = c(mat), v = rep(vg, ncol(mat)))
  data.table::setkey(DT, v)
  DT[, list(m = mean(m)), by = v]
}

fn3_split <- function(mat, vg) {
  splitData <- split(as.data.frame(mat), vect_group)
  sapply(splitData, colMeans)
}

microbenchmark::microbenchmark(fn1_agg(mat, vect_group),
                               fn2_dt(mat, vect_group),
                               fn3_split(mat, vect_group))
#> Unit: milliseconds
#>                        expr       min        lq      mean    median
#>    fn1_agg(mat, vect_group)  5.169709  5.437589  6.122462  6.293567
#>     fn2_dt(mat, vect_group)  1.197218  1.291972  3.004166  1.472097
#>  fn3_split(mat, vect_group) 15.480264 15.751230 16.998514 16.267098
#>         uq        max neval cld
#>   6.481626   9.454458   100  b 
#>   1.538948 142.368800   100 a  
#>  17.060969  60.686907   100   c

Создан в 2019-02-07 пакетом Представить (v0.2.1)

0 голосов
/ 07 февраля 2019

Я не знаю, нужна ли вам многопоточность для этого.

Я протестировал два решения, одно с использованием базы R, а другое с использованием dplyr.Оба были очень быстрыми в тестах.

mat <- matrix(seq(1,10000), ncol  = 100)
vect_group <- rep(1:10, each = 10)

#--
library(dplyr)

#-- Base R
splitData <- split(as.data.frame(mat), vect_group)
meansPerGroup <- sapply(splitData, colMeans)

#-- Dplyr
df <- data.frame(mat, vect_group)
meansPerGroup <- df %>%
    group_by(vect_group) %>%
    summarize_at(vars(colnames(mat)), mean)

Затем я провел тест на этих двух решениях:

rbenchmark::benchmark(replications = 5000,
    baseR = function(mat = mat, vect_group = vect_group) {
        splitData <- split(as.data.frame(mat), vect_group)
        meansPerGroup <- sapply(splitData, colMeans)
    },
    dplyr = function(df = df, vect_group = vect_group) {
        meansPerGroup <- df %>%
            group_by(vect_group) %>%
            summarize_at(vars(colnames(mat)), mean)
    })

Результаты тестов:

   test replications elapsed relative user.self sys.self user.child sys.child
1 baseR         5000   0.006      1.2     0.006        0          0         0
2 dplyr         5000   0.005      1.0     0.006        0          0         0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...