【问题标题】:Convert wide format to long format for n pairs of start and end dates将 n 对开始日期和结束日期的宽格式转换为长格式
【发布时间】:2020-07-30 21:18:04
【问题描述】:

我有一个包含 51 列、id 和 50 对宽格式的开始日期和结束日期的表格。我想将其转换为带有开始和结束日期的长格式。下面给出的示例代码仅适用于 2 对开始日期和结束日期。还必须在“end”的结尾和“start”的开头之间插入新行。此外,每个 id 应该有两行从 'pre' 到第一个开始日期和另一行,从最后一个结束日期到每个 id 的 'post'。另请注意,end2 可能与 post 相同。

library(data.table)
table1 <- fread("
id  pre               post       start1     end1       start2        end2        var1
A   01/01/1992   12/31/1992   03/15/1992  03/20/1992  03/25/1992  03/30/1992       1
C   04/01/1992   06/30/1992   05/28/1992  06/30/1992   NA          NA              5
D   05/01/1992   06/01/1992     NA           NA         NA         NA  NA
E   07/18/1992   08/02/1992     07/15/1992  07/22/1992  NA         NA   1
F   06/02/1992   09/03/1992   07/15/1992   07/17/1992  07/20/1992 09/10/1992      2" )

cols <- c("pre","post","start1", "end1","start2", "end2")
table1[, (cols) := lapply(.SD, as.Date, format="%m/%d/%Y"), .SDcols=cols]


Final table should be-
id  start         end       var1
A   01/01/1992   03/14/1992  -99
A   03/15/1992  03/20/1992   1
A   03/21/1992  03/24/1992  -99
A   03/25/1992  03/30/1992   1
A   04/01/1992  12/31/1992   -99
C   04/01/1992  05/27/1992   -99
C   05/28/1992  06/30/1992   5
D   05/01/1992   06/01/1992  NA
E   07/18/1992   07/22/1992  NA
E   07/23/1992   08/02/1992  1 
F   06/02/1992   07/14/1992  2
F   07/15/1992   07/17/1992  2
F  07/18/1992    07/19/1992  2
F  07/20/1992    09/03/1992  2

更正我的原始帖子:我发现在我的数据中,对于某些 ID,pre 和 post 日期可能不会分别出现在 start1 和 end2 之前和之后。我在上面添加了 3 个额外的 ID 作为示例。也就是说,提前日期可能介于 start1 和 end1 或 end1 和 start1 之间。同样,发布日期可能位于时间线上的任何位置,但会在发布日期之后。最终数据应以 pre 开头并以 post 结尾,保留所有行的开始和结束范围,某些情况下某些 ID 的第一行和最后一行除外。

【问题讨论】:

  • 我很难理解如何从table1 进入你的决赛桌。您提到了多对 startend 日期列。但是您的示例数据也有一个 prepost 列,它们以某种方式集成到您的最终表格中。如何?为什么决赛桌第一行的日期是01/01/1992id=Apre)和03/14/1992table1 中没有匹配的条目)?为什么有些var1-99。一些var1 值似乎会重复(var1 = 1 代表id=A 出现两次),其他则没有(var1 = 5 代表id=B 只出现一次)。这里有什么规则?
  • pre 和 post 是每个 ID 的整个日期范围的结束点。你可以把它想象成一个序列,pre

标签: r dplyr data.table


【解决方案1】:

这是一个假设 pre 和 post 覆盖整个范围的选项:

setnames(table1, c("pre", "post"), c("start0", "end0"))
mDT <- melt(table1, id.vars=c("id", "var1"), measure.vars=patterns("start","end"), 
    na.rm=TRUE, value.name=c("start","end"))

ans <- mDT[, {
        b <- c(start, end[.N] + 1L)
        e <- c(start[2L] - 1L, end[-1L], end[1L])
        .(start=c(b, e[-.N]+1L), end=c(e, b[-1L]-1L))
    }, id][start <= end]
setkey(ans, id, start, end)
ans[, var1 := -99L][mDT, on=.(id, start, end), var1 := i.var1]

edit:对于新数据,当pre-post不覆盖start1到endN的范围时,pre-post期间是否也应该具有相同的var1存在一些不一致之处。但是,如果我们假设 pre-post 不应该具有 var1 值,那么对于 pre-post 不涵盖所有开始和结束日期的情况,这里有一个选项:

setnames(table1, c("pre", "post"), c("start0", "end0"))
mDT <- melt(table1, id.vars=c("id", "var1"), measure.vars=patterns("start","end"),
    value.name=c("start_d","end_d"), na.rm=TRUE)

#identify the pre-post range
mDT[, ri := rowid(id, var1)]

#as per before, we create continuous intervals out of these start and end dates
ans <- mDT[order(id, start_d, end_d), {
    if (.N > 1L) {
        ms <- start_d[1L]
        me <- end_d[1L]
        dates <- c(start_d, end_d+1L)
        sdates <- sort(dates[ms <= dates & dates < me])
        .(start_d=sdates, end_d=c(sdates[-1L]-1L, me))
    } else
        .(start_d, end_d)
}, .(id, var1)][start_d <= end_d]
setkey(ans, id, start_d, end_d)

#identify which ranges falls within the non pre-post periods
w <- unique(ans[mDT[ri!=1L], on=.(id, start_d>=start_d, end_d<=end_d),
    mult="last", nomatch=0L, which=TRUE])
ans[!w, var1 := -99L]

输出:

    id var1    start_d      end_d
 1:  A  -99 1992-01-01 1992-03-14
 2:  A    1 1992-03-15 1992-03-20
 3:  A  -99 1992-03-21 1992-03-24
 4:  A    1 1992-03-25 1992-03-30
 5:  A  -99 1992-03-31 1992-12-31
 6:  C  -99 1992-04-01 1992-05-27
 7:  C    5 1992-05-28 1992-06-30
 8:  D  -99 1992-05-01 1992-06-01
 9:  E  -99 1992-07-15 1992-07-17
10:  E    1 1992-07-18 1992-07-22
11:  F  -99 1992-06-02 1992-07-14
12:  F    2 1992-07-15 1992-07-17
13:  F  -99 1992-07-18 1992-07-19
14:  F    2 1992-07-20 1992-09-03

【讨论】:

  • 哇!钦松。如此紧凑的代码,并且工作得非常漂亮。非常感谢。我很难理解以下代码。对不起,我不像你那样是 R 专家。希望简单解释一下代码的工作原理对您来说不会太麻烦。如果你不能那么不要担心。再次感谢钦松! ans
  • 如果我手工锻炼并张贴照片会更容易。等几天好吗?
  • 绝对!我会等待你的解释。谢谢!
  • 我已对我的原始帖子进行了更正。我后来发现的一些数据问题。当你有时间时,你能改变你的答案吗?一如既往的感谢。
  • @Pam var1 是否也是 pre-post 范围的值存在一些不一致之处。我添加了一种方法,假设 var1 不应用于开始和结束之外的范围。一个很好的例子是 id=D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-12
  • 2016-12-02
  • 1970-01-01
  • 1970-01-01
  • 2018-07-19
  • 1970-01-01
相关资源
最近更新 更多