【问题标题】:expand dates in two columns based on another two columns with ranges根据另外两列的范围在两列中扩展日期
【发布时间】:2020-11-18 09:29:40
【问题描述】:

我有下面 Rcode 中给出的表 1。该表给出了日期的开始和结束范围。

我有另一个表,表 2,它给出了应包含表 1 的开始和结束范围的日期范围的外端。

我的决赛桌应该如下面的 Rcode 所示。

最终表的范围应与表 1 中的确切范围相同,并且应调整表 2 的范围,以使结束日期与后续行和前面的行连续。换句话说,决赛桌应该有不重叠的间隔。我一直未能成功解决的一个复杂的日期问题。希望我已经解释清楚了。

以下代码将给出表 1 和表 2。

table1 <- read.table(text="
id  start         end      var1
A   03/15/1992  03/20/1992  1
A   03/24/1992  03/26/1992  2
A   03/28/1992  03/31/1992  5
B   06/06/1994  06/06/1994  1
", header=T, stringsAsFactors=F)

start   <- as.Date(start)
end     <- as.Date(end)
table1      <- data.frame(id,start, end, var1) 
setDT(table1)


table2 <- read.table(text="
id  t1            t2       var2
A   01/01/1992  03/16/1992  3
A   03/17/1992  03/19/1992  4
A   03/20/1992  05/25/1992  6
B   06/06/1994  06/06/1994  8
", header=T, stringsAsFactors=F)

t1   <- as.Date(t1)
t2     <- as.Date(t2)
table2     <- data.frame(id,t1, t2, var2)
setDT(table2)



finaltable <- read.table(text="
id  t1             t2     var1  var2
A   01/01/1992  03/14/1992      3
A   03/15/1992  03/20/1992  1   
A   03/21/1992  03/23/1992      6
A   03/24/1992  03/26/1992  2   
A   03/27/1992  03/27/1992      6
A   03/28/1992  03/31/1992  5   
A   04/01/1992  05/25/1992      6
B   06/06/1994  06/06/1994  1   8
  ", header=T, stringsAsFactors=F)

【问题讨论】:

  • 你想要一个 dyplr 解决方案,还是一个 SQL 解决方案?
  • 感谢专线小巴。两者都可以。
  • 在有重叠区间的情况下,能否解释一下创建var1和var2的逻辑?
  • 感谢 chinsoon12。最终表应具有从 table1 以及 var1 的确切范围。 Table2 的范围将不准确,因为它们将被调整,以便我们与相应的 var2 值具有连续、不重叠的间隔。
  • 嗨,为什么 B 的 var2 等于 8 而 A 的 var2 03/15/1992 03/20/1992 不等于 4?

标签: mysql r date dplyr data.table


【解决方案1】:

这是一个使用data.table的选项:

#get first and last rows by id for each table
d1 <- table1[, .SD[c(1L, .N)], id][, ri := rowid(id)][]
d2 <- table2[, .SD[c(1L, .N)], id][, ri := rowid(id)][]

#create the earliest and latest intervals to row bind to original table1
morerows <- d1[d2, on=.(id, ri)][, 
    .(id, start=fifelse(ri==1L, t1, end+1L), end=fifelse(ri==1L, start-1L, t2))][
        start<=end]
DT1 <- rbindlist(list(table1, morerows), use.names=TRUE, fill=TRUE)
setkey(DT1, id, start, end)

#add in missing intervals
ans <- rbindlist(list(DT1, DT1[, .(start=end[-.N]+1L, end=start[-1L]-1L), id]), 
    use.names=TRUE, fill=TRUE)[start<=end]
setkey(ans, id, start, end)

ans[is.na(var1), var2 := table2[.SD, on=.(id, t1<=start, t2>=start), var2]]
ans[is.na(var2), var2 := table2[.SD, on=.(id, t1=start, t2=start), var2]]

输出:

   id      start        end var1 var2
1:  A 1992-01-01 1992-03-14   NA    3
2:  A 1992-03-15 1992-03-20    1   NA
3:  A 1992-03-21 1992-03-23   NA    6
4:  A 1992-03-24 1992-03-26    2   NA
5:  A 1992-03-27 1992-03-27   NA    6
6:  A 1992-03-28 1992-03-31    5   NA
7:  A 1992-04-01 1992-05-25   NA    6
8:  B 1994-06-06 1994-06-06    1    8

数据:

library(data.table)
table1 <- fread("id  start         end      var1
A   03/15/1992  03/20/1992  1
A   03/24/1992  03/26/1992  2
A   03/28/1992  03/31/1992  5
B   06/06/1994  06/06/1994  1")
cols <- c("start", "end")
table1[, (cols) := lapply(.SD, as.Date, format="%m/%d/%Y"), .SDcols=cols]

table2 <- fread("id  t1            t2       var2
A   01/01/1992  03/16/1992  3
A   03/17/1992  03/19/1992  4
A   03/20/1992  05/25/1992  6
B   06/06/1994  06/06/1994  8")
cols <- c("t1", "t2")
table2[, (cols) := lapply(.SD, as.Date, format="%m/%d/%Y"), .SDcols=cols]

finaltable <- fread("id  t1             t2     var1  var2
A   01/01/1992  03/14/1992  NA    3
A   03/15/1992  03/20/1992  1   NA
A   03/21/1992  03/23/1992  NA    6
A   03/24/1992  03/26/1992  2   NA
A   03/27/1992  03/27/1992  NA    6
A   03/28/1992  03/31/1992  5   NA
A   04/01/1992  05/25/1992  NA    6
B   06/06/1994  06/06/1994  1   8")
cols <- c("t1", "t2")
finaltable[, (cols) := lapply(.SD, as.Date, format="%m/%d/%Y"), .SDcols=cols]

【讨论】:

  • 谢谢!谢谢!谢谢!非常非常感谢 Chinsoon12。我只是无法做到这一点。 id=B 的 var=8 来自 table2,因为存在的确切范围是 table1 和 table 2。
  • 我刚刚意识到对于某些ID,两个表中的行数不一样,上面的代码跳过了端点。例如,如果表 2 是 table2
  • @Pam,我假设 我有另一个表,表 2,它给出了应包含表 1 的开始和结束范围的日期范围的外端。表2是否需要覆盖表1的范围
  • 是的。那是正确的。再次感谢您的代码!
  • 代码跳过 table2 中的最后一个日期,如果表 1 只有一行,代码如下。最终表必须包含表 2 和表 1 中的所有日期和 ID。 table1
【解决方案2】:

这是一个可能的解决方案,使用包dplyranytime

library(dplyr)

table1 <- read.table(text="
id  start         end      var1
A   03/15/1992  03/20/1992  1
A   03/24/1992  03/26/1992  2
A   03/28/1992  03/31/1992  5
B   06/06/1994  06/06/1994  1
", header=T, stringsAsFactors=F) %>%
  data.frame()

library(anytime)

table1$t1 <- anydate(table1$start)
table1$t2 <- anydate(table1$end)

table2 <- read.table(text="
id  t1            t2       var2
A   01/01/1992  03/16/1992  3
A   03/17/1992  03/19/1992  4
A   03/20/1992  05/25/1992  6
B   06/06/1994  06/06/1994  8
", header=T, stringsAsFactors=F) %>%
  data.frame()

table2$t1 <- anydate(table2$t1)
table2$t2 <- anydate(table2$t2)

finaltable <- merge(table1, table2, by = c("id", "t1", "t2"), all = T) %>%
  select(-c(start, end))
finaltable
#>   id         t1         t2 var1 var2
#> 1  A 1992-01-01 1992-03-16   NA    3
#> 2  A 1992-03-15 1992-03-20    1   NA
#> 3  A 1992-03-17 1992-03-19   NA    4
#> 4  A 1992-03-20 1992-05-25   NA    6
#> 5  A 1992-03-24 1992-03-26    2   NA
#> 6  A 1992-03-28 1992-03-31    5   NA
#> 7  B 1994-06-06 1994-06-06    1    8

reprex package (v0.3.0) 于 2020 年 7 月 28 日创建

【讨论】:

  • 感谢 bttomio。决赛桌应该有不重叠的间隔。例如。对于第 1 行,t2 应为 1992-03-14,第 3-t1 行应为 1992-03-21,依此类推。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-10
  • 2020-06-28
  • 2017-04-25
  • 1970-01-01
  • 2020-02-20
  • 2019-08-25
  • 1970-01-01
相关资源
最近更新 更多