R生成新的data.table slowdown

时间:2018-02-06 15:48:06

标签: r data.table

我有一个数据表。列出了患者暴露的间隔时间以及观察暴露时间的开始和停止时间。在观察期间间隔发生曝光。我希望产生患者未暴露的相反间隔。

我的数据格式如下:

library(data.table)
DT = fread("
id t0  t  s tn
1   1  2  4 15
1   1  6  7 15
1   1 10 12 15
2   4  5  7 44
2   4  9 15 44
2   4 17 35 44")

t0是观察的开始时间,t是曝光的开始,s是曝光的结束,tn是观察的结束。一个例子可能是工人接触极端紫外线。 ID 1在2000年的第一个月开始工作,然后在第二个月在正常工作条件下暴露于极端紫外线,并且在第四个月停止,因为云层持续2个月。 " s"结束时间代表第四个月的云。他们坚持2个月,安全"条件直到第6个月紫外线再次上升2个月。等等...

我想基于这些数据生成曝光 not 发生的间隔。也就是说,当参与者处于" safe"条件。示例输出为:

id  t  s
1   1  2
1   4  6
1   7 10
1  12 15
2   4  5
2   7  9
2  15 17
2  35 44

我的第一步是以下列方式设置data.table:

nonexp <- DT[, .(t=c(t0[1], s), s=c(t, tn[1])), by=id]

但是在我的140,000多个事件的数据集中,这个运行速度非常慢。我在一个高度主持的远程计算环境中工作,所以我无法判断系统运行缓慢或代码是否错误。

这些代码在某些重要方面显然不是最理想的吗?有更快的方法吗?

1 个答案:

答案 0 :(得分:3)

我会存储数据,以便时间变量不会分成多列:

# bounds table
bdDT = melt(unique(DT[, .(id, t0, tn)]), id = "id", value.name = "t")
bdDT[variable == "t0", status := "safe"]
bdDT[variable == "tn", status := "end"]
bdDT[, variable := NULL ]

# core table
treatDT = melt(DT, id="id", value.name = "t", meas = c("t", "s"))
treatDT[variable == "t", status := "treated"]
treatDT[variable == "s", status := "safe"]
treatDT[, variable := NULL ]

# stack
res = unique(rbind(treatDT, bdDT), by=c("id", "t"))
setkey(res, id, t)

数据现在看起来像

    id  t  status
 1:  1  1    safe
 2:  1  2 treated
 3:  1  4    safe
 4:  1  6 treated
 5:  1  7    safe
 6:  1 10 treated
 7:  1 12    safe
 8:  1 15     end
 9:  2  4    safe
10:  2  5 treated
11:  2  7    safe
12:  2  9 treated
13:  2 15    safe
14:  2 17 treated
15:  2 35    safe
16:  2 44     end

从这里开始,如果你想浏览安全法术,那就......

> res[status == "safe"][res[status != "safe"], on=.(id, t), roll=TRUE, 
  .(id, start = x.t, end = i.t)
]

   id start end
1:  1     1   2
2:  1     4   6
3:  1     7  10
4:  1    12  15
5:  2     4   5
6:  2     7   9
7:  2    15  17
8:  2    35  44

注意:如果某些治疗一直持续到tn,它将不会显示为零长度法术。

或者,如果你有足够的RAM,更简洁的方法是扩展数据......

idDT = unique(DT[, .(id, start = t0, end = tn)], by="id")
fullDT = idDT[, .(t = start:end), by=id]

fullDT[, status := "safe"]
fullDT[DT, on=.(id, t >= t, t < s), status := "treated"]

从那里,您可以折叠拼写以便于浏览

fullDT[, 
  .(start = first(t), end = last(t))
, by=.(id, status, g = rleid(id, status))][, !"g"][,
  end := replace(end + 1L, .N, last(end))
, by=id][]

    id  status start end
 1:  1    safe     1   2
 2:  1 treated     2   4
 3:  1    safe     4   6
 4:  1 treated     6   7
 5:  1    safe     7  10
 6:  1 treated    10  12
 7:  1    safe    12  15
 8:  2    safe     4   5
 9:  2 treated     5   7
10:  2    safe     7   9
11:  2 treated     9  15
12:  2    safe    15  17
13:  2 treated    17  35
14:  2    safe    35  44

需要replace步骤,因为OP会写入重叠的结束日期和开始日期。