У меня есть список из 40 фреймов данных размером около 250 тыс. Строк, и я хочу добавить новую переменную в каждый файл данных. Эта новая переменная period
вычисляется из другой переменной, содержащей объекты Date, преобразование очень просто, если годовая часть даты меньше, чем в период 2015 года, устанавливается на «новое» еще «старое».Почему R (в моем примере) очень медленный для обработки дат/времени?
Я думал, что вычисление будет очень быстрым с использованием векторизации, но для завершения потребуется около 41 секунды! (Используйте цикл for или lapply, дающий те же самые показатели).
Возпроизводимо пример:
datas.d <- function(nDf, nRow) {
lapply(seq_len(nDf), function(x) {
data.frame(
id1 = sample(7e8:9e8, nRow),
id2 = sample(1e9, nRow),
id3 = sample(1e9, nRow),
date = sample(seq(as.Date("2012-01-01"), Sys.Date(), by = 1), nRow, rep = TRUE),
code1 = sample(10, nRow, rep = TRUE),
code2 = sample(10, nRow, rep = TRUE),
code3 = sample(10, nRow, rep = TRUE)
)
})
}
datasDate <- datas.d(40, 25e4)
forLoopDate <- function(datas) {
for (i in seq_along(datas)) {
datas[[i]]$period <- rep("old", nrow(datas[[i]]))
datas[[i]]$period[format(datas[[i]]$date, "%Y") == "2015"] <- "new"
}
return(datas)
}
> system.time(forLoopDate(datasDate))
utilisateur système écoulé
41.46 0.31 41.84
я уже испытал медленные выступления, когда я принужден строк в даты в 800K строк dataframe поэтому я подозревал дату манипуляцию виновности для плохих выступлений. R Profiler подтвердил:
Rprof(tmp <- tempfile())
datas <- forLoopDate(datasDate)
Rprof(NULL)
summaryRprof(tmp)
$by.self
self.time self.pct total.time total.pct
"format.POSIXlt" 39.34 94.16 39.34 94.16
"as.POSIXlt.Date" 1.80 4.31 1.80 4.31
"==" 0.36 0.86 0.36 0.86
"forLoopDate" 0.22 0.53 41.78 100.00
"format.Date" 0.06 0.14 41.20 98.61
Так что я попробовал то же преобразование skiping с датой форматирования, то есть непосредственно использовать строку в течение года. Усиление производительности недвусмысленно:
Я также тестирую его с помощью другой функции форматирования, year
из пакета lubridate. Форматирование происходит очень быстро, я думаю, потому что он работает на уровне C?
datas.s <- function(nDf, nRow) {
lapply(seq_len(nDf), function(x) {
data.frame(
id1 = sample(7e8:9e8, nRow),
id2 = sample(1e9, nRow),
id3 = sample(1e9, nRow),
date = sample(2012:2015, nRow, rep = TRUE),
code1 = sample(10, nRow, rep = TRUE),
code2 = sample(10, nRow, rep = TRUE),
code3 = sample(10, nRow, rep = TRUE)
)
})
}
datasString <- datas.s(40, 25e4)
forLoopString <- function(datas) {
for (i in seq_along(datas)) {
datas[[i]]$period <- rep("old", nrow(datas[[i]]))
datas[[i]]$period[datas[[i]]$date == "2015"] <- "new"
}
return(datas)
}
library(lubridate)
forLoopDate2 <- function(datas) {
for (i in seq_along(datas)) {
datas[[i]]$period <- rep("old", nrow(datas[[i]]))
datas[[i]]$period[year(datas[[i]]$date) == 2015] <- "new"
}
return(datas)
}
library(microbenchmark)
mbm <- microbenchmark(
date = datas <- forLoopDate(datasDate),
string = datas <- forLoopString(datasString),
lubridate = datas <- forLoopDate2(datasDate),
times = 10L)
> mbm
Unit: seconds
expr min lq mean median uq max neval
date 41.502728 41.561497 41.649533 41.652306 41.69218 41.875110 10
string 4.119266 4.131186 4.167809 4.166946 4.17993 4.239481 10
lubridate 2.088281 2.105413 2.133042 2.111710 2.15794 2.250739 10
И здесь возникает много вопросов!
_Почему форматирование/конвертирование Даты - это медленное с R?
_Can Я улучшаю производительность своего кода, используя Base R? Каковы наилучшие методы, с точки зрения производительности, при работе с датами/датами?
Спасибо!