Эффективная таблица данных / фрейм / Tibble / другая агрегация в R - PullRequest
0 голосов
/ 30 октября 2018

У меня есть data.table значений, для которых я вычисляю обобщенную статистику в цикле и пытаюсь объединить обобщенные результаты для дополнительной обработки. Однако в результате агрегации время обработки цикла неожиданно велико, и я ищу более быстрое решение.

Метод очень напоминает подход, обсужденный здесь ( Назначение вектора конкретной существующей строке таблицы данных в R ).

Код ( немного сокращен для удобства чтения, но компоненты материала сохранены иллюстративно):

library(data.table);
x <- data.table(matrix(double(),nrow=10000,ncol=120));
system.time({for (i in NROW(x):1) {
    m <- matrix(rnorm(8*15),nrow=8,ncol=15);
}});
#  user  system elapsed 
# 0.165   0.006   0.171 
system.time({for (i in NROW(x):1) {
    m <- matrix(rnorm(8*15),nrow=8,ncol=15);
    as.list(t(m[1:8,]));
}});
#   user  system elapsed 
#  0.245   0.001   0.249
system.time({for (i in NROW(x):1) {
    m <- matrix(rnorm(8*15),nrow=8,ncol=15);
    x[i,] <- as.list(t(m[1:8,]));
}});
#   user  system elapsed 
# 36.227   0.682  37.529

# Obtain input data.table
inputdt <- fread('filename');

# Preallocate summary statistics aggregate
sumstatsdt <- data.table(matrix(double(),nrow=10000,ncol=120));

# Loop over input data.table (the *apply suite not suitable for mypkg::calcstats())
for (i in NROW(inputdt):1) {
    # Produce a matrix of summary statistics for the row (of type double)
    sumstat_matrix <- mypkg::calcstats(inputdt,...);

    # Aggregate the summary statistics (where "a","b","c",... are matrix row names of ordered statistics)
    # >>>> This is the operation that leads to lengthy execution time
    sumstatsdt[i,] <- as.list(t(sumstat_matrix[c("a","b","c",...),]));
};

Входной файл data.table содержит 10 000 наблюдений с 8 атрибутами, и в общей сложности необходимо сохранить 1,2 миллиона сводных статистических данных (каждый из которых имеет тип «double»). При комментировании последней строки в цикле, который выполняет агрегирование, общее время обработки составляет около 24 сек . При запуске с агрегацией общее время обработки увеличивается до 34 мин .

Я пытался использовать сопоставимый код с data.frame и cbind() со слабо похожими результатами производительности (у меня не было возможности попробовать tidyverse suite). Признайте, что операции глубокого копирования будут несколько медленнее, хотя величина разницы во времени выполнения, учитывая относительно небольшой набор данных, кажется, указывает на другую проблему.

Запуск R v3.4.4, data.table v1.11.4 при последней установке Fedora. Использование памяти незначительно (менее 3% системной памяти используется во время выполнения сценария R). Один из процессоров с тактовой частотой 2,1 ГГц со сродством к сеансу R работает почти на 100% в течение всего времени выполнения сценария. Других процессов, связанных с этим ядром, нет, а остальные ядра в основном простаивают. ( NB : иллюстративный код, запускаемый в гостевой системе KVM на другом компьютере)

Sidenote: Также любопытно, почему узкое место ЦП проявляется в том, что в противном случае является проблемой с памятью.

Цените время и с радостью предоставлю дополнительную полезную информацию.

Редактировать [2018.10.31]

  • Включите иллюстративный код, запрашиваемый 42

1 Ответ

0 голосов
/ 31 октября 2018

Ваш компьютер кажется примерно в два раза быстрее моего, но тем не менее я получаю почти 15-кратное улучшение для последовательного присваивания определенным строкам объекта data.table, используя оператор data.table := вместо <- , Я не уверен, но подозреваю, что использование <- обязывает вас зависеть от обычного шага R создания промежуточной временной копии, поэтому вполне вероятно, что метод := также более эффективен для памяти:

?`:=`

 system.time({for (i in NROW(x):1) {
     m <- matrix(rnorm(8*15),nrow=8,ncol=15);
     x[i , (1:120) := as.list(t(m))] } })

 #   user  system elapsed 
 # 4.390   0.096   4.486 


system.time({for (i in NROW(x):1) {
     m <- matrix(rnorm(8*15),nrow=8,ncol=15);
     x[i , ] <- as.list(t(m)) } })

#   user  system elapsed 
# 67.963  15.573  83.572 

Regular R - однопотоковый процесс, если только вы не установите один из "сторонних" модов, таких как MRAN.

...