【问题标题】:Creating an xts object results in altered timestamps创建 xts 对象会导致时间戳改变
【发布时间】:2011-11-12 14:24:39
【问题描述】:

假设我有:

R> str(data)
'data.frame':   4 obs. of  2 variables:
 $ datetime: Factor w/ 4 levels "2011-01-05 09:30:00.001",..: 1 2 3 4
 $ price   : num  18.3 18.3 18.3 18.3

R> data
                 datetime price
1 2011-01-05 09:30:00.001 18.31
2 2011-01-05 09:30:00.321 18.33
3 2011-01-05 09:30:01.511 18.33
4 2011-01-05 09:30:02.192 18.34

当我尝试将其加载到 xts 对象中时,时间戳会被巧妙地改变:

R> x <- xts(data[-1], as.POSIXct(strptime(data$datetime, '%Y-%m-%d %H:%M:%OS')))
R> str(x)
An ‘xts’ object from 2011-01-05 09:30:00.000 to 2011-01-05 09:30:02.191 containing:
  Data: num [1:4, 1] 18.3 18.3 18.3 18.3
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr "price"
  Indexed by objects of class: [POSIXct,POSIXt] TZ: 
  xts Attributes:  
 NULL

 R> x
                         price
 2011-01-05 09:30:00.000 18.31
 2011-01-05 09:30:00.321 18.33
 2011-01-05 09:30:01.510 18.33
 2011-01-05 09:30:02.191 18.34

您会注意到时间戳已更改。第一个条目现在出现在09:30:00.000,而不是原始数据所说的09:30:00.001。第三行和第四行也不对。

这是什么原因造成的?我在做一些根本错误的事情吗?我尝试了各种咒语将数据放入xts 对象中,它们似乎都表现出这种行为。

编辑:添加sessionInfo()

R> sessionInfo()
R version 2.13.1 (2011-07-08)
Platform: x86_64-unknown-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
 [4] LC_COLLATE=C               LC_MONETARY=C              LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
[10] LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] xts_0.8-2 zoo_1.7-4

loaded via a namespace (and not attached):
[1] grid_2.13.1     lattice_0.19-30 tools_2.13.1   

编辑 2:如果我将源数据修改为微秒精度,如下所示:

datetime,price
2011-01-05 09:30:00.001000,18.31
2011-01-05 09:30:00.321000,18.33
2011-01-05 09:30:01.511000,18.33
2011-01-05 09:30:02.192000,18.34

然后加载它,这样我就有了:

R> test
                    datetime price
1 2011-01-05 09:30:00.001000 18.31
2 2011-01-05 09:30:00.321000 18.33
3 2011-01-05 09:30:01.511000 18.33
4 2011-01-05 09:30:02.192000 18.34

然后,最后,将其转换为xts 对象并设置索引格式:

R> x <- xts(test[,-1], as.POSIXct(strptime(test$datetime, '%Y-%m-%d %H:%M:%OS')))
R> indexFormat(x) <- '%Y-%m-%d %H:%M:%OS6'
R> x
                            [,1]
2011-01-05 09:30:00.000999 18.31
2011-01-05 09:30:00.321000 18.33
2011-01-05 09:30:01.510999 18.33
2011-01-05 09:30:02.191999 18.34

您也可以看到效果。我希望增加额外的精度会有所帮助,但不幸的是它没有。

编辑 3:请参阅 @DWin's answer 了解重现此行为的端到端测试用例。

编辑 4: 行为似乎不是面向毫秒的。下面显示了微秒分辨率时间戳的相同更改结果。如果我将输入数据更改为:

R> data
                    datetime price
1 2011-01-05 09:30:00.001001 18.31
2 2011-01-05 09:30:00.321001 18.33
3 2011-01-05 09:30:01.511001 18.33
4 2011-01-05 09:30:02.192005 18.34

然后创建一个xts对象:

R> x <- xts(data[-1], 
            as.POSIXct(strptime(as.character(data$datetime), '%Y-%m-%d %H:%M:%OS')))
R> indexFormat(x) <- '%Y-%m-%d %H:%M:%OS6'
R> x
                           price
2011-01-05 09:30:00.001000 18.31
2011-01-05 09:30:00.321001 18.33
2011-01-05 09:30:01.511001 18.33
2011-01-05 09:30:02.192004 18.34

编辑 5: 这似乎是一个浮点精度问题。观察:

R> t <- as.POSIXct("2011-01-05 09:30:00.001001")
R> t
[1] "2011-01-05 09:30:00.001 CST"
R> as.numeric(t)
[1] 1294241400.0010008812

这显示了错误行为,并且与 EDIT 4 中的示例一致。但是,使用未显示错误的示例:

R> t <- as.POSIXct("2011-01-05 09:30:01.511001")
R> t
[1] "2011-01-05 09:30:01.511001 CST"
R> as.numeric(t)
[1] 1294241401.5110011101

似乎xts 或某些基础组件正在向下舍入而不是最接近的?

【问题讨论】:

  • 我无法复制这个...你的sessionInfo()是什么?
  • 添加 sessionInfo() 输出作为编辑
  • 我有一段记忆,动物园对象与 xts 相关,它们的索引值在系列的开头和结尾略微扩展。还是仅使用 seq.zoo?这实际上并不能解释你所看到的一切,因为高端它也被“推回”。这可能是闰秒问题吗?
  • 没有seq.zoo这样的方法。目前尚不清楚“略微扩展”是指什么,但暗示动物园在不询问的情况下对索引值进行某种不良的捣乱是不太可能的。
  • 对不起。我可能将其他一些函数的行为混为一谈,hist 或 cut 也许有一种方法可以扩展日期时间范围以避免在极端情况下丢弃事件。

标签: r time-series xts


【解决方案1】:

你有你的时间在一个因素:

R> str(data)
'data.frame':   4 obs. of  2 variables:
 $ datetime: Factor w/ 4 levels "2011-01-05 09:30:00.001",..: 1 2 3 4
 [...]

这不是最好的起点。您需要转换为字符。因此,而不是

x <- xts(data[-1], as.POSIXct(strptime(data$datetime, '%Y-%m-%d %H:%M:%OS')))

建议

x <- xts(data[-1], 
         order.by=as.POSIXct(strptime(as.character(data$datetime), 
                                      '%Y-%m-%d %H:%M:%OS')))   

根据我的经验,围绕一个因素的as.character() 至关重要。因子对于建模非常有用,但是当您从读取数据中意外获取它们时,它们会有点麻烦。使用stringsAsFactor=FALSE 对您有利,并在数据导入时避免使用它们。

编辑:所以这似乎指向 strptime/strftime 实现。为了让事情更有趣,R 从操作系统中获取了其中的一些,并在src/main/datetime.c 中重新实现了一些。

另外,请注意最小的 epsilon,您可以添加到时间变量中并且仍然让 R 将它们视为相等。在我的 64 位 Linux 系统上,这发生在 10^-7 :

R> sapply(seq(1, 8), FUN=function(x) identical(now, now+1/10^x)) 
[1] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
R> 

【讨论】:

  • 德克,不幸的是,这似乎没有任何影响。我尝试用as.character() 包装时间戳,并尝试读取数据并指定stringsAsFactors=FALSE。两者都没有改变我看到的行为。
  • 感谢 Dirk 的跟进。我看到的和你一样:epsilon。
【解决方案2】:

看来问题只出在打印上。使用OP的原版data:

ind <- as.POSIXct(strptime(data$datetime, '%Y-%m-%d %H:%M:%OS'))
as.numeric(ind)*1e6  # as expected
# [1] 1294241400001000 1294241400321000 1294241401511000 1294241402192000
ind  # wrong
# [1] "2011-01-05 09:30:00.000 CST" "2011-01-05 09:30:00.321 CST"
# [3] "2011-01-05 09:30:01.510 CST" "2011-01-05 09:30:02.191 CST"
x <- xts(data[-1], ind)
x  # wrong
#                         price
# 2011-01-05 09:30:00.000 18.31
# 2011-01-05 09:30:00.321 18.33
# 2011-01-05 09:30:01.510 18.33
# 2011-01-05 09:30:02.191 18.34
as.numeric(index(x))*1e6  # but the underlying index values are as expected
# [1] 1294241400001000 1294241400321000 1294241401511000 1294241402192000

【讨论】:

  • 它不会被认为是xts 中的一个错误,它没有打印出准确的时间戳吗?
  • 这不是 xts 错误。 xts 只是格式化/打印POSIXct 对象。您可以在我的回答中看到 xts 索引的格式与ind 完全相同。问题是为什么format.POSIXct 会这样做。
【解决方案3】:

我发布这个只是为了让想要探索它的人可以有一个可重现的例子,这表明它不仅仅发生在 OP 的系统上。 as.character 的因素并不能阻止它的发生。

dat <- read.table(textConnection("     datetime\tprice
 1\t2011-01-05 09:30:00.001\t18.31
 2\t2011-01-05 09:30:00.321\t18.33
 3\t2011-01-05 09:30:01.511\t18.33
 4\t2011-01-05 09:30:02.192\t18.34"), header =TRUE, sep="\t")
 as.character(dat$datetime)
#[1] "2011-01-05 09:30:00.001" "2011-01-05 09:30:00.321" "2011-01-05 09:30:01.511"
#[4] "2011-01-05 09:30:02.192"
  strptime(as.character(dat$datetime),         '%Y-%m-%d %H:%M:%OS')
#[1] "2011-01-05 09:30:00" "2011-01-05 09:30:00" "2011-01-05 09:30:01"
#[4] "2011-01-05 09:30:02"
 as.POSIXct(strptime(as.character(dat$datetime), 
                                       '%Y-%m-%d %H:%M:%OS'))
#[1] "2011-01-05 09:30:00 EST" "2011-01-05 09:30:00 EST" "2011-01-05 09:30:01 EST"
#[4] "2011-01-05 09:30:02 EST"
 x <- xts(dat[-1], 
          order.by=as.POSIXct(strptime(as.character(dat$datetime), 
                                       '%Y-%m-%d %H:%M:%OS')))
 x
####                price
2011-01-05 09:30:00 18.31
2011-01-05 09:30:00 18.33
2011-01-05 09:30:01 18.33
2011-01-05 09:30:02 18.34
indexFormat(x) <- '%Y-%m-%d %H:%M:%OS6'
x
                           price
2011-01-05 09:30:00.000999 18.31
2011-01-05 09:30:00.321000 18.33
2011-01-05 09:30:01.510999 18.33
2011-01-05 09:30:02.191999 18.34

sessionInfo()
R version 2.13.1 RC (2011-07-03 r56263)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/C/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] grid      splines   stats     graphics  grDevices utils     datasets  methods  
[9] base     

other attached packages:
 [1] xts_0.8-2       zoo_1.7-4       sculpt3d_0.2-2  RGtk2_2.20.12  
 [5] rgl_0.92.798    survey_3.24     hexbin_1.26.0   spam_0.23-0    
 [9] xtable_1.5-6    polspline_1.1.5 Ryacas_0.2-10   XML_3.4-0      
[13] rms_3.3-1       Hmisc_3.8-3     survival_2.36-9 sos_1.3-0      
[17] brew_1.0-6      lattice_0.19-30

loaded via a namespace (and not attached):
[1] cluster_1.14.0 tools_2.13.1  

【讨论】:

  • 感谢您发布重现该行为的端到端示例。
  • 这在 Ubuntu 64 位和 CRAN 的 xts/zoo 上仍然可以正常工作......奇怪。
  • @Joshua,请查看我最近的编辑。它似乎是舍入的浮点精度问题。这是否引发了关于如何避免这种情况的任何想法?四舍五入似乎不正确,因为它似乎总是向下舍入而不是最接近的。
猜你喜欢
  • 1970-01-01
  • 2018-11-27
  • 2011-07-16
  • 1970-01-01
  • 2017-05-04
  • 1970-01-01
  • 2019-08-13
  • 2014-03-03
  • 1970-01-01
相关资源
最近更新 更多