合并两个具有不规则时间戳列的数据帧

Merging two dataframes with irregular timestamp columns

我有一个与股票相关的数据样本,其中的价格 date/time 在几秒钟内以不规则的随机间隔标记,称为 ESH5ESM5

我想生成另一个 full data.frame,其中一个 date/time 列以秒为单位递增时间,并填写来自ESH5ESM5。除非 ESH5ESM5

中存在匹配时间的值,否则任何值都将成为 'latest price',它将延续到下一个时间间隔

例如,ESH5

    Date                 Price    Type
    22/10/2015 9:00:00   50.10    Bid
    22/10/2015 9:00:02   50.12    Ask
    22/10/2015 9:00:06   50.10    Trade

ESM5

    Date                 Price    Type
    22/10/2015 9:00:01   50.09    Bid
    22/10/2015 9:00:02   50.11    Ask
    22/10/2015 9:00:04   50.09    Trade

我希望生成一个完整的 data.frame 喜欢

    Date                 ESH5.Bid   ESH5.Ask   ESH5.Trade   ESM5.Bid   ESM5.Ask   ESM5.Trade
    22/10/2015 9:00:00      50.10         NA           NA        NA          NA          NA
    22/10/2015 9:00:01      50.10         NA           NA     50.09          NA          NA
    22/10/2015 9:00:02      50.10       50.12          NA     50.09       50.11          NA
    22/10/2015 9:00:03      50.10       50.12          NA     50.09       50.11          NA
    22/10/2015 9:00:04
    22/10/2015 9:00:05
    22/10/2015 9:00:06

目前,我正在使用 for 循环和 if-else 语句生成 table。我使用常规时间戳增量预生成 NA 空数据帧,最新更新 bidasktrade,然后 运行 同时进行条件检查填写table。

我当前的代码有效,但是循环需要相当长的时间来处理(10 分钟)。 R 中是否有任何内置函数可用于此搜索、替换和继承类似功能?

如果这有点难以理解,我们深表歉意。谢谢。

我认为你想要做的事情需要几个步骤:

首先,使用 seq 创建日期列,如 @akrun

所示

其次重建数据结构。这可以通过多种方式完成,但我认为 reshape2 包中的 dcast 函数是最好的:

ESH5c <- dcast(ESH5, Date ~ Type, value.var='Price')
ESM5c <- dcast(ESM5, Date ~ Type, value.var='Price')

最后一步是 merge 这些新数据与您的日期向量。

将两个数据集中的 'Date' 列从 'character' class 转换为 'POSIXct'。

ESH5$Date <- as.POSIXct(ESH5$Date, format='%d/%m/%Y %H:%M:%S')
ESM5$Date <- as.POSIXct(ESM5$Date, format='%d/%m/%Y %H:%M:%S')

通过连接这些数据集的 'Date' 列得到 'min' 和 'max' 值。

MinD <- min(c(ESH5$Date, ESM5$Date))
MaxD <- max(c(ESH5$Date, ESM5$Date))

根据 'MinD' 和 'MaxD' 值创建日期时间序列作为新数据集

d1 <- data.frame(Date=seq(MinD, MaxD, by='sec'))

merge 所有数据集,方法是将它们放在 'list' 中并使用 Reduce

d2 <- Reduce(function(...) merge(..., by='Date', all=TRUE),
           list(d1, ESH5, ESM5))

将 'd2' 数据集从 'wide' 重塑为 'long'

dLong <- reshape(d2, idvar='Date', varying=2:5, sep=".", direction='long')
dLong$time <- factor(dLong$time, labels=c('ESH5', 'ESM5'))
row.names(dLong) <- NULL

使用 dcast

将 'long' 格式更改为 'wide'
library(reshape2) 
res <- dcast(dLong, Date~time+Type, value.var='Price')

删除多余的 NA 列

res1 <- res[!grepl('NA', names(res))]

使用 zoo 中的 na.locf 用之前的非 NA 值填充 NA 值

library(zoo)
res1[-1] <- lapply(res1[-1], na.locf, na.rm=FALSE)
res1
#                 Date ESH5_Ask ESH5_Bid ESH5_Trade ESM5_Ask ESM5_Bid ESM5_Trade
#1 2015-10-22 09:00:00       NA     50.1         NA       NA       NA         NA
#2 2015-10-22 09:00:01       NA     50.1         NA       NA    50.09         NA
#3 2015-10-22 09:00:02    50.12     50.1         NA    50.11    50.09         NA
#4 2015-10-22 09:00:03    50.12     50.1         NA    50.11    50.09         NA
#5 2015-10-22 09:00:04    50.12     50.1         NA    50.11    50.09      50.09
#6 2015-10-22 09:00:05    50.12     50.1         NA    50.11    50.09      50.09
#7 2015-10-22 09:00:06    50.12     50.1       50.1    50.11    50.09      50.09

或者使用dplyr/tidyr,我们可以使用spread来改变每个数据集的格式,full_join,它们与'd1'一起改变'NA' 每列中的值与使用 na.locfmutate_each 的 'non-NA' 先前值。使用 paste(如果需要)更改列名称。

 library(dplyr)
 library(tidyr)
 library(zoo)

 res2 <-  full_join(spread(ESH5, Type, Price), 
                        spread(ESM5, Type, Price), by='Date') %>%
                    full_join(d1, ., by='Date') %>%
                    mutate_each(funs(na.locf(., na.rm=FALSE)), -Date) 

 names(res2)[-1] <- c(paste('ESH5', sort(ESH5$Type),sep="_"), 
                      paste('ESM5', sort(ESM5$Type), sep="_"))

  res2
  #               Date ESH5_Ask ESH5_Bid ESH5_Trade ESM5_Ask ESM5_Bid ESM5_Trade
  #1 2015-10-22 09:00:00       NA     50.1         NA       NA       NA         NA
  #2 2015-10-22 09:00:01       NA     50.1         NA       NA    50.09         NA
  #3 2015-10-22 09:00:02    50.12     50.1         NA    50.11    50.09         NA
  #4 2015-10-22 09:00:03    50.12     50.1         NA    50.11    50.09         NA
  #5 2015-10-22 09:00:04    50.12     50.1         NA    50.11    50.09      50.09
  #6 2015-10-22 09:00:05    50.12     50.1         NA    50.11    50.09      50.09
  #7 2015-10-22 09:00:06    50.12     50.1       50.1    50.11    50.09      50.09