【问题标题】:R- efficiently convert time in milliseconds to as.POSIXct with varying time zonesR- 以毫秒为单位有效地将时间转换为具有不同时区的 as.POSIXct
【发布时间】:2015-10-12 11:47:42
【问题描述】:

我想将具有不同时区的多个时间值(目前以 1970 年 1 月 1 日以来的毫秒数表示)转换为 POSIXct 格式。

我有以下数据集:

times <- c(1427450400291, 1428562800616, 1418651628795, 1418651938990, 1418652348281, 1418652450161)
tzones <- c("America/Los_Angeles", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Israel Standard Time")

问题是as.POSIXct 方法只接受一个 tz 值,而不是一个向量。因此,我不能直接调用它。我尝试使用 lapply 并逐个元素地调用它,但这需要很长时间(对于更长的向量):

get.dates.with.timezones <- function(epoch.vec,tz.vec) {  
    res <- lapply(seq(epoch.vec),function(x){
           as.POSIXct(epoch.vec[x]/1000,origin = "1970-01-01", tz = tz.vec[x])
        })
        return(do.call(c,res))
}

所以只有 1200 个值,几乎需要一秒钟。

timesX200 <- rep(times,200)
tzonesX200 <- rep(tzones,200)
system.time( get.dates.with.timezones(timesX200,tzonesX200) )
           user              system             elapsed 
0.86800000000005184 0.01999999999999602 0.88899999999921420 

我是 R 的新手,所以我想知道是否有办法提高这项任务的性能。这个问题有矢量化选项吗?此外,as.POXIXct() 方法本身似乎存在一些性能问题,如 here 所示。

--------- 编辑 --------

显然不可能保存具有不同时区的 POSIXct 向量。来自 POSIXct 文档:

在“POSIXlt”对象上使用 c 会将它们转换为当前时区, 并且在“POSIXct”对象上删除任何“tzone”属性(即使它们 都标有相同的时区)。 Source

那太糟糕了。我想知道是否有任何替代方法来处理日期+时间+不同的时区。如果有的话会很高兴。

【问题讨论】:

  • 我会试试lubridate 包中的时间函数,它们比as.POSIXct 高效得多。
  • @Paul Hiemstra 谢谢。我查看了lubridate,但找不到我正在寻找的方法。

标签: r timezone posixct


【解决方案1】:

我发现这种方法要快得多。它还输出一个保存所创建时区的列表:

f_time <- function(x,y) as.POSIXct(x/1000, origin="1970-01-01", tz=y)
s <- split(timesX200, tzonesX200)
result <- mapply(f_time, s, names(s))

您的输出不保留时区分配。检查你的输出:

get.dates.with.timezones(times, tzones)
[1] "2015-03-27 06:00:00 EDT" "2015-04-09 03:00:00 EDT"
[3] "2014-12-15 08:53:48 EST" "2014-12-15 08:58:58 EST"
[5] "2014-12-15 09:05:48 EST" "2014-12-15 09:07:30 EST"

它们都被强制到当地时区。

基准测试

times <- c(1427450400291, 1428562800616, 1418651628795, 1418651938990, 1418652348281, 1418652450161)
tzones <- c("America/Los_Angeles", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Israel")

timesX200 <- rep(times,200)
tzonesX200 <- rep(tzones,200)


get.dates.with.timezones <- function(epoch.vec,tz.vec) {  
    res <- lapply(seq(epoch.vec),function(x){
           as.POSIXct(epoch.vec[x]/1000,origin = "1970-01-01", tz = tz.vec[x])
        })
        return(do.call(c,res))
}

library(microbenchmark)
microbenchmark(
  get = get.dates.with.timezones(timesX200, tzonesX200),
  plafort = {s <- split(timesX200, tzonesX200);mapply(f_time, s, names(s))},
  times=20L)
# Unit: microseconds
#     expr        min         lq       mean     median         uq
#      get 342693.638 362465.069 378195.687 372553.491 389080.277
#  plafort    997.138   1027.731   1110.846   1107.471   1149.314
#         max neval cld
#  445539.744    20   b
#    1558.473    20  a 

【讨论】:

  • 谢谢!有什么简单的方法可以保持矢量输出吗?前面的函数适用于创建作为数据帧一部分的向量。此外,它不保持原来的顺序。
  • 可能使用 lubridate 或 chron。我会看看一些方法并添加到答案中
猜你喜欢
  • 1970-01-01
  • 2019-03-03
  • 2021-09-29
  • 2018-03-07
  • 2021-02-27
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
相关资源
最近更新 更多