Парадигма повторяющегося анализа, с которой я сталкиваюсь в своем исследовании, заключается в необходимости поднабора на основе всех различных значений идентификатора группы, выполнения статистического анализа каждой группы по очереди и помещения результатов в выходную матрицу для дальнейшей обработки / суммирования.
Как я обычно делаю это в R, примерно так:
data.mat <- read.csv("...")
groupids <- unique(data.mat$ID) #Assume there are then 100 unique groups
results <- matrix(rep("NA",300),ncol=3,nrow=100)
for(i in 1:100) {
tempmat <- subset(data.mat,ID==groupids[i])
# Run various stats on tempmat (correlations, regressions, etc), checking to
# make sure this specific group doesn't have NAs in the variables I'm using
# and assign results to x, y, and z, for example.
results[i,1] <- x
results[i,2] <- y
results[i,3] <- z
}
Это работает для меня, но в зависимости от размера данных и количества групп, с которыми я работаю, это может занять до трех дней.
Помимо перехода к параллельной обработке, есть ли какой-нибудь "прием" для ускорения выполнения чего-то подобного? Например, преобразование циклов во что-то другое (что-то вроде применения с функцией, содержащей статистику, которую я хочу запустить внутри цикла), или устранение необходимости фактически назначать подмножество данных переменной?
Edit:
Может быть, это просто общеизвестно (или ошибка выборки), но я попытался заключить в некоторые части моего кода подстановки в скобки, а не использовать команду подмножества, и это, казалось, дало небольшой прирост производительности, что меня удивило. У меня есть некоторый код, который я использовал и выводил ниже, используя те же имена объектов, что и выше:
system.time(for(i in 1:1000){data.mat[data.mat$ID==groupids[i],]})
user system elapsed
361.41 92.62 458.32
system.time(for(i in 1:1000){subset(data.mat,ID==groupids[i])})
user system elapsed
378.44 102.03 485.94
Обновление:
В одном из ответов jorgusch предложил использовать пакет data.table для ускорения поднабора. Итак, я применил это к проблеме, с которой столкнулся ранее на этой неделе. В наборе данных с более чем 1 500 000 строк и 4 столбцами (ID, Var1, Var2, Var3) я хотел вычислить две корреляции в каждой группе (индексируемой переменной «ID»). Есть чуть более 50000 групп. Ниже мой исходный код (который очень похож на выше):
data.mat <- read.csv("//home....")
groupids <- unique(data.mat$ID)
results <- matrix(rep("NA",(length(groupids) * 3)),ncol=3,nrow=length(groupids))
for(i in 1:length(groupids)) {
tempmat <- data.mat[data.mat$ID==groupids[i],]
results[i,1] <- groupids[i]
results[i,2] <- cor(tempmat$Var1,tempmat$Var2,use="pairwise.complete.obs")
results[i,3] <- cor(tempmat$Var1,tempmat$Var3,use="pairwise.complete.obs")
}
Я повторяю это прямо сейчас, чтобы точно определить, сколько времени это заняло, но из того, что я помню, я запустил его, когда пришел в офис утром, и он закончился где-то в середине дня. Рисунок 5-7 часов.
Перестройка моего кода для использования data.table ....
data.mat <- read.csv("//home....")
data.mat <- data.table(data.mat)
testfunc <- function(x,y,z) {
temp1 <- cor(x,y,use="pairwise.complete.obs")
temp2 <- cor(x,z,use="pairwise.complete.obs")
res <- list(temp1,temp2)
res
}
system.time(test <- data.mat[,testfunc(Var1,Var2,Var3),by="ID"])
user system elapsed
16.41 0.05 17.44
Сравнивая результаты с использованием data.table с теми, что я получил от использования цикла for для подстановки всех идентификаторов и записи результатов вручную, они, похоже, дали мне те же ответы (хотя мне придется проверить, что немного больше тщательно). Это выглядит как довольно большое увеличение скорости.
Обновление 2:
Запуск кода с использованием подмножеств наконец завершился снова:
user system elapsed
17575.79 4247.41 23477.00
Обновление 3:
Я хотел посмотреть, получилось ли что-нибудь иначе, используя пакет plyr, который также был рекомендован. Я впервые использую его, поэтому я мог сделать что-то неэффективно, но это все же помогло существенно по сравнению с циклом for с поднабором.
Использование тех же переменных и настроек, что и раньше ...
data.mat <- read.csv("//home....")
system.time(hmm <- ddply(data.mat,"ID",function(df)c(cor(df$Var1,df$Var2, use="pairwise.complete.obs"),cor(df$Var1,df$Var3,use="pairwise.complete.obs"))))
user system elapsed
250.25 7.35 272.09