为啥 Rcpp 会破坏 xts 对象?
Posted
技术标签:
【中文标题】为啥 Rcpp 会破坏 xts 对象?【英文标题】:Why does Rcpp corrupt xts object?为什么 Rcpp 会破坏 xts 对象? 【发布时间】:2021-08-03 09:23:20 【问题描述】:假设我有一个 xts 对象并通过 Rcpp 函数返回索引。以这种方式触摸 xts 对象似乎会损坏 xts 对象。
可以通过强制深拷贝来解决。
虽然我确实有解决方法,但我不明白为什么会出现问题——或者为什么需要我的 hack?
使用来自 dirk 的 Rcpp Gallery 的建议代码,xts 对象一旦被触摸就会损坏。
// [[Rcpp::export]]
DatetimeVector xtsIndex(NumericMatrix X)
DatetimeVector v(NumericVector(X.attr("index")));
return v;
require(xts)
xx <- xts(1:10, order.by = seq.Date(Sys.Date(), by = "day", length.out = 10))
xtsIndex(xx)
...
> print(xx)
Error in Ops.POSIXt(.index(x), 86400) :
'%/%' not defined for "POSIXt" objects
调整代码以强制进行深层复制可防止损坏。
// [[Rcpp::export]]
DatetimeVector xtsIndex_deep(NumericMatrix X)
DatetimeVector v = clone(NumericVector(X.attr("index")));
return v;
> xtsIndex_deep(xx)
[1] "2021-05-13 UTC" "2021-05-14 UTC" "2021-05-15 UTC" "2021-05-16 UTC" "2021-05-17 UTC"
[6] "2021-05-18 UTC" "2021-05-19 UTC" "2021-05-20 UTC" "2021-05-21 UTC" "2021-05-22 UTC"
> xx
[,1] [,2]
2021-05-13 1 10
2021-05-14 2 9
2021-05-15 3 8
2021-05-16 4 7
2021-05-17 5 6
2021-05-18 6 5
2021-05-19 7 4
2021-05-20 8 3
2021-05-21 9 2
2021-05-22 10 1
发生了什么事?
【问题讨论】:
这里发生了很多事情,你玩的有点快和松。xx
是创建时的 xts
对象,它有一个(int !!)数据向量,但您将其强制转换为 xtsIndex
NumericMatrix
--> 所以“事情发生了”。我同意副作用是不可取的,但你也必须对类型更加小心。
Rcpp Gallery 文章中的函数可能是使用旧的 Date(time) 类编写的,我必须检查一下。一个更简单的版本是cppFunction("SEXP xtsIndex(NumericMatrix X) SEXP s = X.attr(\"index\"); return s; ")
,它应该避免额外的转换并使用日期和日期时间索引对象。
@DirkEddelbuettel 我刚刚测试了您建议的修复程序,我得到了相同的'%/%' not defined for "POSIXt" objects
错误。但感谢您的快速关注。
我完成了定义该函数的顺序,然后是相同的xx <- xts(1:10, order.by = seq.Date(Sys.Date(), by = "day", length.out = 10))
,然后是xtsIndex(xx)
,然后xx
仍然打印为xts
对象。
@DirkEddelbuettel 是的,它有效。请张贴作为答案,我会投票。我仍然不明白到底出了什么问题?
【参考方案1】:
我无法用更简单的属性提取功能重现,一切都很好,并且 xx 没有改变:
> cppFunction("SEXP xtsIndex(NumericMatrix X) SEXP s = X.attr(\"index\"); return s; ")
> xx <- xts(1:10, order.by = seq.Date(Sys.Date(), by = "day", length.out = 10))
> head(xx)
[,1]
2021-05-13 1
2021-05-14 2
2021-05-15 3
2021-05-16 4
2021-05-17 5
2021-05-18 6
>
> xtsIndex(xx)
[1] 1620864000 1620950400 1621036800 1621123200 1621209600 1621296000
[7] 1621382400 1621468800 1621555200 1621641600
attr(,"tzone")
[1] "UTC"
attr(,"tclass")
[1] "Date"
>
> head(xx)
[,1]
2021-05-13 1
2021-05-14 2
2021-05-15 3
2021-05-16 4
2021-05-17 5
2021-05-18 6
>
函数xtsIndex
将在输入上创建一个副本(因为我们的xts
对象包含一个整数序列作为数据,NumericMatrix
肯定是一个复制对象,但它保留了我们可以提取的attribute
)。
但请注意,xx
中的 Date
序列现在如何以 POSIXct
或 Datetime
为单位显示。这看起来像是xts
(或者可能是Rcpp
,但我认为这里是xts
)可能在这里执行的强制错误。您最好从 POSIXct
时间对象开始,即使它是每日数据。
这样做还允许我们正确键入Datetime
的提取函数:
> cppFunction("DatetimeVector xtsIndex(NumericMatrix X)
return DatetimeVector(wrap(X.attr(\"index\"))); ")
> xx <- xts(1:10, order.by = as.POSIXct(seq.Date(Sys.Date(), by = "day", length.out = 10)))
> head(xx)
[,1]
2021-05-12 19:00:00 1
2021-05-13 19:00:00 2
2021-05-14 19:00:00 3
2021-05-15 19:00:00 4
2021-05-16 19:00:00 5
2021-05-17 19:00:00 6
> head(xtsIndex(xx))
[1] "2021-05-12 19:00:00 CDT" "2021-05-13 19:00:00 CDT" "2021-05-14 19:00:00 CDT"
[6] "2021-05-15 19:00:00 CDT" "2021-05-16 19:00:00 CDT" "2021-05-17 19:00:00 CDT"
> head(xx)
[,1]
2021-05-12 19:00:00 1
2021-05-13 19:00:00 2
2021-05-14 19:00:00 3
2021-05-15 19:00:00 4
2021-05-16 19:00:00 5
2021-05-17 19:00:00 6
>
【讨论】:
请注意,由于将xx
中的索引转换为POSIXct
,因此“修复”有效。如果上面提到的DateTimeVector
类型函数@dirk 用于具有“日期”索引的xx
,则R 会话中的原始xx
已损坏。
您必须更加小心在编译代码中从日期到日期时间的交叉。我强烈建议您在编译后的代码中坚持使用 POSIXct。
好的,谢谢。我很好奇为什么会发生这种情况。如果您可以发布一个有用的链接。
@ricardo:您知道日期是整数类型而不是双精度类型吗?
@IRTFM .... 好建议!我从 Rcpp-gallery 复制了代码,并没有仔细考虑。如果我将提取函数声明为IntegerVector
,则不会发生损坏。仍然留下 why 问题。 idx_dd <- cppFunction("IntegerVector xtsIndex_dd(NumericMatrix X) return IntegerVector(X.attr(\"index\")); ")
以上是关于为啥 Rcpp 会破坏 xts 对象?的主要内容,如果未能解决你的问题,请参考以下文章