【问题标题】:Add dummies with conditions in data.table?在 data.table 中添加具有条件的假人?
【发布时间】:2014-02-04 02:05:20
【问题描述】:

抱歉,问题太长了。我会尽我最大的努力清楚地阐明我的目标

我想用update方法在data.table中添加假人,和this already answered in this link一样,但是稍微复杂一点。

为了更好地描述,我创建了数据。

DT <- data.table(UID = paste0("UID",rep(1:5,each=2)), 
                 date = as.IDate(c("2012-01-01","2012-01-02","2012-01-03","2012-01-04","2012-01-05","2012-01-06","2012-02-01","2012-02-02","2012-02-03","2012-02-04")),
                 value = c(1:10)) 

DT是一个data.table,包含UID、日期和值的信息。在原始数据中,结构相同,但时间跨度较长(2年)。

这里我想根据日期添加假人。

日期有几个特殊的时间跨度,我们可以用假期来表示。

例如,在我上面创建的假数据中。

有两个假期

  1. 从“2012-01-02”到“2012-01-05”
  2. 从“2012-02-02”到“2012-02-03”

我要添加两种类型的假人

  1. 关于假期长度的傻瓜:首先计算不同假期的长度。在此示例中,我们有两个不同的长度(2 和 4)。因此,我们将添加 2 个假人来指示日期是否在这些假期中。

预期的结果是这样的:

UID 日期值 D_length_2 D_length_4 UID1 2012 年 1 月 1 日 1 假 假 UID2 2012 年 1 月 2 日 2 假 真 UID3 2012 年 1 月 3 日 3 假 真 UID4 2012 年 1 月 4 日 4 假 真 UID5 2012 年 1 月 5 日 5 假 真 UID1 2012 年 1 月 6 日 6 假 假 UID2 2/1/2012 7 真假 UID3 2/2/2012 8 真假 UID4 2/3/2012 9 假 假 UID5 2/4/2012 10 假 假
  1. 关于这一天是正好是假期前一天还是正好是假期后一天的傻瓜。
UID 日期值 之前 之后 UID1 2012 年 1 月 1 日 1 真假 UID2 2012 年 1 月 2 日 2 假 假 UID3 2012 年 1 月 3 日 3 假 假 UID4 2012 年 1 月 4 日 4 假 假 UID5 2012 年 1 月 5 日 5 假 假 UID1 2012 年 1 月 6 日 6 假 真 UID2 2/1/2012 7 真假 UID3 2/2/2012 8 假 假 UID4 2/3/2012 9 假 假 UID5 2012 年 2 月 4 日 10 假 真

所以总的期望结果是这样的

UID Date Val 之前 之后 D_length_2 D_length_4 UID1 1/1/2012 1 真假假假 UID2 2012 年 1 月 2 日 2 FALSE FALSE FALSE TRUE UID3 2012 年 1 月 3 日 3 FALSE FALSE FALSE TRUE UID4 1/4/2012 4 FALSE FALSE FALSE TRUE UID5 2012 年 1 月 5 日 5 FALSE FALSE FALSE TRUE UID1 1/6/2012 6 FALSE TRUE FALSE FALSE UID2 2/1/2012 7 真假假假 UID3 2/2/2012 8 FALSE FALSE TRUE FALSE UID4 2/3/2012 9 FALSE FALSE TRUE FALSE UID5 2/4/2012 10 FALSE TRUE FALSE FALSE

总观察量超过 10M 行,大约有 10 个不同的假期和 4 个不同的长度。

我认为是第二种假人

f <- function(x){ 
ifelse(x %in% as.Date(c("2012-01-02","2012-02-02")) - 1, return(TRUE), return(FALSE))
}

DT[,Before:= f(date)] 

但这似乎不正确。

对于第一个,我没有想出一个好的解决方案。

这个问题是关于data.table中的更新,任何关于如何处理它以及如何编写更新函数的想法都非常欢迎!

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    这是一个开始:

    library(data.table)
    
    DT <- data.table(UID = paste0("UID",rep(1:5,each=2)), 
                     date = as.IDate(c("2012-01-01","2012-01-02","2012-01-03","2012-01-04","2012-01-05","2012-01-06","2012-02-01","2012-02-02","2012-02-03","2012-02-04")),
                     value = c(1:10)) 
    setkey(DT, date)
    
    
    vacStart <- data.table(start = as.IDate(c("2012-01-02", "2012-02-02")), key="start")
    vacEnd <- data.table(date = as.IDate(c("2012-01-05", "2012-02-03")), key="date")
    
    #identify vacations:
    vacStart[, Start:=.I]
    DT <- vacStart[DT, roll=TRUE]
    vacEnd[, End:=.I]
    DT <- vacEnd[DT, roll=-Inf]
    DT[,vac:=(End==Start)*Start]
    DT[is.na(vac), vac:=0L]
    
    #2-day vacations:
    DT[,length_2 := (.N==2) & vac!=0, by=vac]
    #days before vacation
    DT[,before := c(diff(vac)>0, FALSE) & vac==0]
    #           date End Start  UID value vac length_2 before
    #  1: 2012-01-01   1    NA UID1     1   0    FALSE   TRUE
    #  2: 2012-01-02   1     1 UID1     2   1    FALSE  FALSE
    #  3: 2012-01-03   1     1 UID2     3   1    FALSE  FALSE
    #  4: 2012-01-04   1     1 UID2     4   1    FALSE  FALSE
    #  5: 2012-01-05   1     1 UID3     5   1    FALSE  FALSE
    #  6: 2012-01-06   2     1 UID3     6   0    FALSE  FALSE
    #  7: 2012-02-01   2     1 UID4     7   0    FALSE   TRUE
    #  8: 2012-02-02   2     2 UID4     8   2     TRUE  FALSE
    #  9: 2012-02-03   2     2 UID5     9   2     TRUE  FALSE
    # 10: 2012-02-04  NA     2 UID5    10   0    FALSE  FALSE
    

    【讨论】:

    • 谢谢罗兰!它真的很有帮助!并且可以在我的第二个问题的解决方案中提供一些 cmets 吗?为什么更新后都是TRUE?
    • @Bigchao 因为ifelse 中的那些returns。 return 停止函数并返回值。由于ifelse 的写入方式,第一个return 首先被评估并返回一个TRUE 被回收。只需省略 returns 即可。
    • 我在这个假数据集上尝试了这段代码,结果非常好。但是当我根据真实数据使用时,假期从3天到8天不等。然后代码没有按预期运行。我认为DT[,vac:=(End==Start)*Start] 在时间跨度很大的情况下效果不佳。你认为这是问题所在吗?
    • 不,我的解决方案与假期长度无关。但是,有一些假设,例如,每个假期都有开始和结束,并且没有重叠的假期。由于真实数据可能很混乱,因此您应该检查这些假设。另外,我假设日期是连续的(至少在假期内)。
    • 感谢您的 cmets,原始数据集中没有重叠。代码我试了好几遍,原来vac只有1和2,我在哪里比较注意呢?我认为代码实现实际上是正确的..谢谢!
    猜你喜欢
    • 1970-01-01
    • 2017-12-17
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多