r - 将 n 对开始日期和结束日期的宽格式转换为长格式
问题描述
我有一个包含 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,前后日期可能不会分别出现在 start1 和 end2 之前和之后。我在上面添加了 3 个额外的 ID 作为示例。也就是说,提前日期可能介于 start1 和 end1 或 end1 和 start1 之间。同样,发布日期可能位于时间线上的任何位置,但会在发布日期之后。最终数据应以pre开头,以post结尾,保留所有行的开始和结束范围,但在某些情况下,某些 ID 的第一行和最后一行除外。
解决方案
这是一个假设 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]
编辑:对于新数据,当 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
推荐阅读
- sql - 使用超过 60 亿次操作加速 SQL 查询
- android - 使用 ConstraintLayout 将水平回收视图放置在特定位置
- jmeter - 使用 Jmeter 处理 SSE 请求
- c# - 如何调用通用输入类型类的方法
- java - Itext5 文档未正确关闭
- reactjs - 如何在这里传递状态?
- asp.net-web-api - 从 NSwag 招摇中过滤模式
- elasticsearch - 如何在 Elastic Search 中通过术语聚合获取额外数据?
- postgresql - 检查 postgresql 函数中的行数
- javascript - Mapbox 上超出了最大调用堆栈大小