我有一个多列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
...
点数:
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的任何列的副本,然后替换整个列。
答案 0 :(得分:3)
我会做这样的“规范”方式是:
na.locf
。您可以通过na.locf
函数的merge.xts
参数进行fill
调用。例如:
xtd <- merge(xt, xd, fill=na.locf)[index(xt)]
这是我能想到的最简单的解决方案,可能不一定是最高效的解决方案。如果它适合您的用例,请告诉我。如果没有,我将不得不花一些时间考虑更有效的解决方案。
如果xt
有NA
需要保留,我们可以使用相同的范例,但我们只需要在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。