【问题标题】:Merging two irregular zoo time-series is messing up the structure合并两个不规则的动物园时间序列会破坏结构
【发布时间】:2015-09-27 11:40:17
【问题描述】:

我正在处理包含数千行的贸易数据集。每条记录都有一个基于符号和日期的唯一键。给定符号的交易记录是不规则的,因此使用 zoo 将是自然的选择。我需要使用滞后和合并来创建一个新的数据集。但是,我不知道如何在动物园中设置多列索引以使用滞后功能。以下是示例数据集和预期输出。

df = data.frame(
    dt = as.Date(c("2015-01-01", "2015-01-05", "2015-01-06",
                   "2015-01-01", "2015-01-02")),
    id = c("i1", "i1", "i1", "i2", "i2"),
    v1 = c(110, 115, 119, 212, 213),
    v2 = c(100, 170, 180, 202, 210),
    v3 = c(11, 13, 16, 22, 24)
)
df$id = as.character(df$id)

输出应该是

2015-01-01, i1, 110, 100, 11, 2015-01-05, i1, 115, 170, 13 
2015-01-05, i1, 115, 170, 13, 2015-01-06, i1, 119, 180, 16 
2015-01-06, i1, 119, 180, 16, NA, NA, NA, NA, NA
2015-01-01, i2, 212, 202, 22, 2015-01-02, i2, 213, 210, 24 
2015-01-02, i2, 213, 210, 24, NA, NA, NA, NA, NA

请注意,无论列数如何,我都需要合并完整的行。以下是解决基于 zoo 的“分组”滞后操作的一种可能方法,它将合并完整的行。

doProcessing = function(df){
  icolnames = colnames(df)
  tt = zoo(df, df$dt)
  tt1 = merge(tt, lag(tt, 1))
  colnames(tt1) = c(icolnames, paste0("lag_", icolnames))
  data.frame(tt1, stringsAsFactors=F)
}
fin_df = do.call(rbind, with(df, by(df, list(id), doProcessing, simplify=F)))

这个最终输出帧将每个字段作为因子,这与原始数据帧不同。

> str(df)
'data.frame':   5 obs. of  5 variables:
 $ dt: Date, format: "2015-01-05" "2015-01-01" ...
 $ id: chr  "i1" "i1" "i1" "i2" ...
 $ v1: num  115 110 119 212 213
 $ v2: num  170 100 180 202 210
 $ v3: num  13 11 16 22 24

结果数据框看起来像

> str(fin_df)
'data.frame':   5 obs. of  10 variables:
 $ dt    : Factor w/ 4 levels "2015-01-01","2015-01-05",..: 1 2 3 1 4
 $ id    : Factor w/ 2 levels "i1","i2": 1 1 1 2 2
 $ v1    : Factor w/ 5 levels "110","115","119",..: 1 2 3 4 5
 $ v2    : Factor w/ 5 levels "100","170","180",..: 1 2 3 4 5
 $ v3    : Factor w/ 5 levels "11","13","16",..: 1 2 3 4 5
 $ lag_dt: Factor w/ 3 levels "2015-01-05","2015-01-06",..: 1 2 NA 3 NA
 $ lag_id: Factor w/ 2 levels "i1","i2": 1 1 NA 2 NA
 $ lag_v1: Factor w/ 3 levels "115","119","213": 1 2 NA 3 NA
 $ lag_v2: Factor w/ 3 levels "170","180","210": 1 2 NA 3 NA
 $ lag_v3: Factor w/ 3 levels "13","16","24": 1 2 NA 3 NA

我做错了什么以及如何根据原始数据框获得正确的结构?

我根据这个链接问了这个问题multipart index in zoo timeseries 但是我把那个线程搞砸了,因此没有收到任何回复。需要以正确的方式解决这个问题,因为手动修复并不优雅,也不是“R”的做事方式。

【问题讨论】:

    标签: r merge time-series zoo


    【解决方案1】:

    您在组的索引中有重叠。为避免大量遗漏,一种解决方案是使用包含每个 id 的列表作为它自己的时间序列(zoo 对象):

    >  myTsList <- tapply(1:nrow(df), df$id, function(x) { zoo::zoo(df[x, ], df$dt[x]) } )
    >  myTsList 
    $i1
               dt         id v1  v2  v3
    2015-01-01 2015-01-01 i1 110 100 11
    2015-01-05 2015-01-05 i1 115 170 13
    2015-01-06 2015-01-06 i1 119 180 16
    
    $i2
               dt         id v1  v2  v3
    2015-01-01 2015-01-01 i2 212 202 22
    2015-01-02 2015-01-02 i2 213 210 24
    

    然后您可以轻松地按照您所说的进行grouped lag

    >  res <- lapply(myTsList, function(x) merge(x, lag(x), suffixes=c("","lag")) )
    >  res
    $i1
               dt.        id. v1. v2. v3. dt.lag     id.lag v1.lag v2.lag v3.lag
    2015-01-01 2015-01-01 i1  110 100 11  2015-01-05 i1     115    170    13    
    2015-01-05 2015-01-05 i1  115 170 13  2015-01-06 i1     119    180    16    
    2015-01-06 2015-01-06 i1  119 180 16  <NA>       <NA>   <NA>   <NA>   <NA>  
    
    $i2
               dt.        id. v1. v2. v3. dt.lag     id.lag v1.lag v2.lag v3.lag
    2015-01-01 2015-01-01 i2  212 202 22  2015-01-02 i2     213    210    24    
    2015-01-02 2015-01-02 i2  213 210 24  <NA>       <NA>   <NA>   <NA>   <NA> 
    

    当然,如果你想拥有data.frame 结构,你可以然后bind 组,但由于索引重叠,我们需要先转换它们:

    > Reduce(rbind, lapply(res, as.data.frame))
                       dt. id. v1. v2. v3.     dt.lag id.lag v1.lag v2.lag v3.lag
    2015-01-01  2015-01-01  i1 110 100  11 2015-01-05     i1    115    170     13
    2015-01-05  2015-01-05  i1 115 170  13 2015-01-06     i1    119    180     16
    2015-01-06  2015-01-06  i1 119 180  16       <NA>   <NA>   <NA>   <NA>   <NA>
    2015-01-011 2015-01-01  i2 212 202  22 2015-01-02     i2    213    210     24
    2015-01-02  2015-01-02  i2 213 210  24       <NA>   <NA>   <NA>   <NA>   <NA>
    

    编辑:如果您根本不需要时间序列,而只需要 data.frame 的最终输出,那么在我的建议的启发下,您可以做一些事情:

    df$ind <- 1:nrow(df)
    myTsList <- tapply(1:nrow(df), df$id, function(x) zoo::zoo(df[x, "ind"], df$dt[x])  )
    res <- lapply(myTsList, function(x) merge(x, lag(x)) )
    newDf<- Reduce(rbind, lapply(res, as.data.frame))
    df$ind <- NULL
    as.data.frame(cbind(df[newDf[,1],],df[newDf[,2],]))
    
              dt id  v1  v2 v3         dt   id  v1  v2 v3
    1 2015-01-01 i1 110 100 11 2015-01-05   i1 115 170 13
    2 2015-01-05 i1 115 170 13 2015-01-06   i1 119 180 16
    3 2015-01-06 i1 119 180 16       <NA> <NA>  NA  NA NA
    4 2015-01-01 i2 212 202 22 2015-01-02   i2 213 210 24
    5 2015-01-02 i2 213 210 24       <NA> <NA>  NA  NA NA
    

    这也将保留原始data.frame 中的正确类等。

    EDIT*更简单的dplyr解决方案:

    library(dplyr)
    merge( 
        df,
        df %>% group_by(id) %>% mutate(lag=lag(dt)), 
        by.x=c("id","dt"), by.y=c("id","lag"), all.x=TRUE
    )
    
      id         dt v1.x v2.x v3.x         dt v1.y v2.y v3.y
    1 i1 2015-01-01  110  100   11 2015-01-05  115  170   13
    2 i1 2015-01-05  115  170   13 2015-01-06  119  180   16
    3 i1 2015-01-06  119  180   16       <NA>   NA   NA   NA
    4 i2 2015-01-01  212  202   22 2015-01-02  213  210   24
    5 i2 2015-01-02  213  210   24       <NA>   NA   NA   NA
    

    【讨论】:

    • 输出数据框将所有列作为因子。我该如何解决这个问题?
    • @JR 抱歉延迟接受。可爱的(神秘的!!!)代码。把工作做得很好。谢谢
    • 一开始我以为我误解了目的,添加了一个不那么神秘的方法。
    • 请在答案中添加更多文字说明。
    猜你喜欢
    • 2017-10-14
    • 2013-02-26
    • 2011-10-28
    • 2014-05-09
    • 1970-01-01
    • 2013-11-07
    • 2012-02-27
    • 2020-02-01
    相关资源
    最近更新 更多