gpt4 book ai didi

r - 为什么 R(在我的示例中)处理日期/日期时间非常慢?

转载 作者:行者123 更新时间:2023-12-04 09:31:56 26 4
gpt4 key购买 nike

我有一个包含 40 个数据帧的列表,大约有 25 万行,我想为每个数据帧附加一个新变量。这个新变量 period 是从另一个包含 Date 对象的变量计算而来的,转换非常简单,如果日期的年份部分低于 2015 period 则设置为“new”,否则设置为“old”。

我认为使用矢量化计算会非常快,但大约需要 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

当我将字符串强制转换为 80 万行数据帧中的日期时,我已经遇到了缓慢的性能,因此我怀疑日期操作是导致性能不佳的罪魁祸首。 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

所以我尝试了相同的转换,跳过日期格式,即直接使用年份字符串。性能提升是明确的:

我还使用 lubridate 包中的另一个格式化函数 year 对其进行了测试。格式化非常快,我猜是因为它是在 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 格式化/转换日期这么慢?

_我可以使用 Base R 提高我的代码的性能吗?在处理日期/日期时间时,为了性能目的有哪些好的做法?

谢谢!

最佳答案

format 函数可以返回许多不同的格式,预计会很慢。如果您对 lubridate 的 year 函数感到满意,您可以直接使用它的(非常简单的)代码:

as.POSIXlt(x, tz = tz(x))$year + 1900

一般来说,当性能很重要时,您应该避免在任何类型/类和字符之间进行转换。这通常会很慢。最好进行数值计算(例如,您可以使用作为 Date 变量基础的整数,但这会导致闰年问题,因此最好使用 POSIXlt,它会为您解决这个问题)。

关于r - 为什么 R(在我的示例中)处理日期/日期时间非常慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30803624/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com