如何将每日xts合并为稀疏时间索引的xts?

时间:2015-08-06 21:33:18

标签: r merge xts

我有一个多列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删除它们,但有可能 - 我的简单示例中没有显示 - 我在数据中有一些真正的NAs,我不想删除。)

更新:作为原始数据丢失的NA的示例,请考虑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的答案显示了使用幻数保存NA的变通方法,最后将其转换为NA。一种替代方法(使用更多内存)是获取包含NA的任何列的副本,然后替换整个列。

2 个答案:

答案 0 :(得分:3)

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

  1. 合并这两个对象。
  2. 在结果上调用na.locf
  3. 结果的子集,因此它只包含所需的索引值。
  4. 您可以通过na.locf函数的merge.xts参数进行fill调用。例如:

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

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

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

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

答案 1 :(得分: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中的值是常识未使用的数值的NA,如-Inf,因此仍然可以使用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。