Быстрая агрегатная матрица по столбцам и группам строк - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть большая матрица mat с именами строк group_label_x и именами group_label_y. Я хочу агрегировать mat в ave_mat, по group_label_x и group_label_y, где значение ave_mat[i,j] является средним значением mat[ group_label_x[i], group_label_y[j] ]. Это может быть достигнуто с помощью двойного цикла или двойного применения функции aggregate (aggregate( mat, by = list(group_label_x), FUN='mean' )). Но есть ли подход, который может достичь более высокой скорости? (поскольку у меня много матриц для агрегирования).

Следующий код генерирует демонстрационную случайную матрицу из приблизительно 1E4 строк и 2E4 столбцов, которые я хочу объединить в матрицу ~ 1E3 x 1E3:

set.seed(1)

dim_x_raw = 1E4
dim_y_raw = 2E4

n_groups_x = 1E3
n_groups_y = 1E3

group_len_x = diff(sort(sample( 1:dim_x_raw, n_groups_x )))
group_label_x = rep( paste0('group_', 1:length(group_len_x)), group_len_x )

group_len_y = diff(sort(sample( 1:dim_y_raw, n_groups_y )))
group_label_y = rep( paste0('group_', 1:length(group_len_y)), group_len_y )

mat = matrix( runif( length(group_label_x)*length(group_label_y) ), length(group_label_x) )

######################################

Мой код агрегации (медленно):

ave_mat_x = aggregate( mat, by = list(group_label_x), FUN='mean' )
ave_mat = aggregate( t(ave_mat_x), by = list(group_label_y), FUN='mean' )

1 Ответ

0 голосов
/ 09 ноября 2018

Вы можете попробовать

library(data.table)
# add row and colnames
mat = matrix(runif( length(group_label_x)*length(group_label_y)), length(group_label_x), 
              dimnames = list(group_label_x, group_label_y))
# transform to data.table
mat_dt <- data.table(mat, keep.rownames = TRUE, stringsAsFactors = FALSE)
rm(mat) #rmove the old matrix
# melt, summarise per group and calculate mean
mat_dt <- melt(mat_dt, id.vars = "rn")
head(mat_dt)
        rn variable     value
1: group_1  group_1 0.8718050
2: group_1  group_1 0.9671970
3: group_1  group_1 0.8669163
4: group_1  group_1 0.4377153
5: group_1  group_1 0.1919378
6: group_1  group_1 0.0822944
res <- mat_dt[,.(Mean=mean(value)),.(rn, variable)]
head(res)
        rn variable      Mean
1: group_1  group_1 0.4888935
2: group_2  group_1 0.3903115
3: group_3  group_1 0.4601481
4: group_4  group_1 0.5023852
5: group_5  group_1 0.5067483
6: group_6  group_1 0.4851856
dim(res)
[1] 998001      3

Конечно, вы можете запустить все в одну строку и проверить скорость

system.time(
 res <- melt(data.table(mat, keep.rownames = TRUE, stringsAsFactors = FALSE), id.vars = "rn")[,.(Mean=mean(value)),.(rn, variable)]
+ )
       User      System verstrichen 
       8.15        0.01        8.19 
...