【问题标题】:How to merge a daily xts into a sparse time-indexed xts?如何将每日 xts 合并为稀疏时间索引 xts?
【发布时间】:2015-10-30 05:11:40
【问题描述】:

我有一个多列 xts 对象,它达到第二精度。然后我有另一个 xts 对象,其中包含每天的一个值。我想将该每日值添加为主要 xts 对象中的一列。这是一个例子:

Sys.setenv(TZ = "UTC") 
library(xts)

set.seed(777)

xt = xts( data.frame(A=1:20,B=201:220,C=round(runif(20)*10,1)),
  order.by = as.POSIXct("2015-06-21") + (runif(20) * 86400 * 14) )

xd = xts( round(runif(14) - 0.5,1), as.Date("2015-06-21") +  (1:14))

使用merge 不起作用:xd 条目被赋予“00:00:00”时间戳,因此它们都不匹配,所以我得到一个带有很多 NA 的 xts 对象:

                     A   B    C   xd
2015-06-21 10:04:36  5 205  7.0   NA
2015-06-22 00:00:00 NA  NA   NA -0.5
2015-06-23 00:00:00 NA  NA   NA -0.2
2015-06-23 11:42:38  4 204 10.0   NA
2015-06-24 00:00:00 NA  NA   NA  0.1
...

预期结果:

                     A   B    C   xd
2015-06-21 10:04:36  5 205  7.0   NA
2015-06-23 11:42:38  4 204 10.0 -0.2
2015-06-24 21:16:18 18 218  8.7  0.1
2015-06-25 02:30:24 15 215  8.7 -0.2
2015-06-25 07:48:42 16 216  1.0 -0.2
2015-06-25 15:04:34 14 214  5.9 -0.2
2015-06-26 07:50:09  1 201  6.9 -0.3
2015-06-27 19:28:33  7 207  3.5  0.5
...

积分:

  • 实际数据会比这个例子大很多,所以要避免过度使用内存和 CPU。
  • 如上所示,在 xd 中可能存在 NA 或缺失日期(尽管相对较少)。
  • xt 中没有显示某些日子(如上面缺少的 2015-06-22 所示)。我不希望为这样的日子创建条目。 (我想我可以使用 na.omit 来删除它们,但有可能 - 并且在我的简单示例中没有显示 - 我在数据中有一些我不想删除的真实 NA。)

更新:作为NAs 在原始数据中丢失的示例,请考虑xt[10,'B'] <- NA。使用 Joshua 的 merge(xt, xd, fill=na.locf)[index(xt)] 解决方案,2015-06-28 19:41:45 最终成为 8 203 1.7 0.4 而应该是 8 NA 1.7 0.4。 这是否是一个问题将取决于接下来将使用xt。 FXQuantTrader 的回答显示了一种使用幻数保留NAs 的解决方法,该幻数在最后变回NA。一种替代方法(使用更多内存)是复制任何包含 NA 的列,然后替换整个列。

【问题讨论】:

  • 顺便说一句,我的“避免过多的记忆”点与我(简要地)必须使用na.locfseqxd 中每秒创建一个条目的想法有关,所以合并将起作用(例如 stackoverflow.com/a/8981517/841830 )这将需要 86,400 行(如果 xt 使用毫秒则变得更加愚蠢)!

标签: r merge xts


【解决方案1】:

我会这样做的“规范”方式是:

  1. 合并两个对象。
  2. 致电na.locf 了解结果。
  3. 对该结果进行子集化,使其仅包含所需的索引值。

您可以通过merge.xts 函数的fill 参数调用na.locf。例如:

xtd <- merge(xt, xd, fill=na.locf)[index(xt)]

这是我能想到的最简单的解决方案,但不一定是性能最高的。让我知道它是否适合您的用例。如果没有,我将不得不花一些时间考虑更有效的解决方案。


如果xt 有需要保留的NA,我们可以使用相同的范例,但我们只需要在xd 中的列上运行na.locf

xtd <- merge(xt, xd)
xtd[,"xd"] <- na.locf(xtd[,"xd"])
xtd <- xtd[index(xt)]

【讨论】:

  • 谢谢 - 这很容易。虽然当xt 已经包含应该保留的NA 值时它确实出错了(我刚刚编辑了我的问题以显示一个示例)。
  • @DarrenCook:这很容易解决。只需在merge 呼叫之外执行na.locf。我将编辑我的答案。
【解决方案2】:

为了得到你想要的,你想将 xd 时间戳准确地合并到 xd 时间戳上(到亚秒级)。因此,一种方法是在您所在时区的每个日历日查找 xt 中的第一个时间戳,并将该时间戳用作 xd 中当天的索引值。

假设您在交易日的开始(00:00:00)知道 xd 的值,您可以执行这样的操作(如果您需要对以下代码进行微调只知道交易日结束时xd的值):

Sys.setenv(TZ = "UTC") 
library(xts)

set.seed(777)

library(lubridate)
xt = xts( data.frame(A=1:20,B=201:220,C=round(runif(20)*10,1)),
          order.by = as.POSIXct("2015-06-21") + (runif(20) * 86400 * 14) )

# Use consistent time index ordering (both POSIXct):
xd = xts( round(runif(14) - 0.5,1), as.POSIXct("2015-06-21") +  days(1:14))

# since xd elements are randomly created each time:
xd2 <- xd

# get first timestamp of each day in xt:
first_each_day <- .indexday(xt)
first_each_day_ndup <- !duplicated(first_each_day)
first_each_day_ndup.i <- which(first_each_day_ndup) # this row is the first for each day

xt_sub <- xt[first_each_day_ndup.i]

xt_sub_floor_dates <- floor_date(index(xt_sub), "day")
xd_date_eq_xt_date.i <- which(index(xd2) %in% xt_sub_floor_dates)
switch2.i <- which(xt_sub_floor_dates %in% index(xd2))


# Set xd time to the first timestamp in xt for the day, if it exists in xt:
xdtmp <- xd2[xd_date_eq_xt_date.i,]
index(xdtmp) <- index(xt_sub[switch2.i,])

# xts merge trick -- name new column at the same time as merging all in one statement:
res <- merge(xt, dailyvalue = drop(xdtmp))
res[, "dailyvalue"] <- na.locf(res[, "dailyvalue"])

关于你的观点:

如果 xt 中没有与 xd 中的日期相对应的行,则使用此方法不会在 xt 中添加行(即解决了您的第 3 点)。

您还没有提到在合并 xd 和 xt 之前之前您希望如何处理可能预先存在于 xd 中的 NA,但是在合并后了解 xt 中的 NA 的一种方法是设置xd 中的值对于常识未使用的数值(如 -Inf)来说是 NA,因此仍然可以使用 na.locf 来适当地填充 xt 中的 dailyvalue 列

# suppose NA exists in xd at row 7:

xd2[7,] <- NA

# Set a replacement dummy numeric value for recognising NAs in the dailyvalue column. e.g. Inf

xd2[is.na(xd2),] <- -Inf

# Now repeat the above code for merging:
xdtmp <- xd2[xd_date_eq_xt_date.i,]
index(xdtmp) <- index(xt_sub[switch2.i,])

# merge and name new column at the same time all in one statement:
res <- merge(xt, dailyvalue = drop(xdtmp))
res[, "dailyvalue"] <- na.locf(res[, "dailyvalue"])

# backfill NAs in dailyvale if necessary:
res[!is.finite(res[, "dailyvalue"]), "dailyvalue"] <- NA
print(res)

最后,如果您在 xd 中缺少日期,但知道您希望如何回填它们的值,您可以在执行上述代码合并之前将这些未知日期添加到 xd。

【讨论】:

  • 感谢您在该答案中所做的努力!但肯定它不应该那么复杂吗? xts 索引处理非常复杂,肯定有一些帮助。顺便说一句,使用 -9999 暂时表示 NA 是非常危险的——你永远不知道代码何时将用于与你目前所见范围不同的数据。 (我想说-InfNaN 比-9999 更安全,但我想它们同样脆弱。)
  • 关于临时 NA 替换,您是对的,Inf 是更简洁的选择,并且可以与 na.locf 一起使用。虽然 NaN 似乎不适用于 na.locf。
猜你喜欢
  • 2016-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 2017-12-08
  • 2011-05-16
相关资源
最近更新 更多