计算在R中省略重叠日期的持续时间

时间:2014-08-15 16:56:52

标签: r lubridate

抱歉,我对R很新,我不是数据专家。我正在尝试计算一个省略重叠日期的持续时间。我怀疑rubridate就是答案。 我的数据集如下所示:

patientnumber  rxnumber                       startdate          stopdate
100                   1                        1/1/2014          1/5/2014
100                   2                        1/1/2014          1/5/2014
100                   3                       1/20/2014         1/22/2014
200                   4                       2/14/2014         2/14/2014
200                   5                       2/15/2014         2/20/2014

我想计算得到患者100的值为8(5 + 3)和7为患者200(1 + 6)的值,以计算每位患者的总暴露量。

我认为我需要解决这个问题的方法是。计算每个患者的最小开始日期和最长停止日期,然后使用计数器变量从最小开始日期开始计数。 如果计数器变量与其中一个间隔重叠,则添加一个并移动。如果没有,只需移动直到达到最大停止日期。

我只是不知道如何编码。这将是我在R中完成的最复杂的编码,也是我第一次使用循环。请帮忙!

更新@ Richard 感谢帮助。在扩大规模时,我发现了一些问题。

假设患者数量相同且rx增加#

startdate stopdate duration重叠
3/26/2014 3/26/2014 1 3(此重叠来自上述记录) 3/27/2014 3/27/2014 1 0
3/27/2014 3/27/2014 1 1 3/27/2014 3/30/2014 4 1 3/28/2014 3/28/2014 1 3(不幸的是,我不确定要解决这个问题)

代码正常运行,只需要进行微调。希望你能帮忙。我将继续尝试解决这个问题。

2 个答案:

答案 0 :(得分:3)

一种解决方案是计算持续时间,然后纠正与前一个条目的重叠。

注意:此解决方案假定某种类型的排序,并且不适用于无序的data.frames。假设(如在提供的示例中)数据按患者编号和按时间顺序排序。

如果数据格式不同,则必须对其进行相应的排序。

# example data
dat <- read.table(header=TRUE, text=
  "patientnumber rxnumber startdate stopdate
   100 1 1/1/2014 1/5/2014
   100 2 1/1/2014 1/5/2014
   100 3 1/20/2014 1/22/2014
   200 4 2/14/2014 2/14/2014
   200 5 2/15/2014 2/20/2014
   300 5 2/19/2014 2/22/2014 
   300 6 3/27/2014 3/27/2014
   300 7 3/27/2014 3/27/2014 
   300 8 3/27/2014 3/30/2014 
   300 9 3/28/2014 3/28/2014")

# convert to date
dat$startdate <- as.Date(dat$startdate, "%m/%d/%Y")
dat$stopdate <- as.Date(dat$stopdate, "%m/%d/%Y")
# base duration
dat$duration <- difftime(dat$stopdate, dat$startdate, units="days")+1

# calculate overlap
dat$overlap <- 0

for(i in 2:nrow(dat)){
  samepat <- dat$patientnumber[i]==dat$patientnumber[i-1]
    curovl <- min(dat$stopdate[i],dat$stopdate[i-1]) - dat$startdate[i]+1
    if(curovl>0 & samepat) dat$overlap[i] <- curovl
}

# aggregate duration and overlap
res <- aggregate(duration ~ patientnumber, data=dat, sum)
res$overlap <- aggregate(overlap ~ patientnumber, data=dat, sum)[,2]

# calculate corrected value
res$corrected <- res$duration - res$overlap

结果:

>     res
  patientnumber duration overlap corrected
1           100      13        5        8 
2           200       7        0        7 
3           300      11        3        8 

修改

修正了有关重叠计算的一些问题(如果患者数量发生变化,如果重叠仅是部分的话)。看看结果现在是否符合您的期望。谢谢你指出这个!

答案 1 :(得分:1)

此解决方案使用unique函数删除重复日期。在使用unique之前,需要将原始数据框重新格式化为高瘦版本。

# example data
dat <- read.table(header=TRUE, text=
"patientnumber rxnumber startdate stopdate
   100 1 1/1/2014 1/5/2014
   100 2 1/1/2014 1/5/2014
   100 3 1/20/2014 1/22/2014
   200 4 2/14/2014 2/14/2014
   200 5 2/15/2014 2/20/2014
   300 5 2/19/2014 2/22/2014 
   300 6 3/27/2014 3/27/2014
   300 7 3/27/2014 3/27/2014 
   300 8 3/27/2014 3/30/2014 
   300 9 3/28/2014 3/28/2014")
# convert to date
dat$startdate <- as.Date(dat$startdate, "%m/%d/%Y")
dat$stopdate <- as.Date(dat$stopdate, "%m/%d/%Y")

# Create integer versions of the dates
dat$startdate <- as.integer(dat$startdate)
dat$stopdate <- as.integer(dat$stopdate)

# Initialize a "long" version of the original data frame
dat2 <- data.frame(patientnumber = as.integer(),
                   date = as.integer())

# Loop through each row in the original data frame
for (i in 1:nrow(dat)) {
  # Loop through the days between the startdate and stopdate
  for (j in dat[i, "startdate"]:dat[i, "stopdate"]) {
    # Create a new row for each day
    rowij <- data.frame(patientnumber = dat[i, "patientnumber"],
                        date = j)
    # Concatenate the new row to the "long" version of the original data frame
    dat2 <- rbind(dat2, rowij)
  }
}

# Use the unique() function to get rid of duplicate days
dat3 <- unique(dat2)

# Aggregate the days
dat4 <- aggregate(date ~ patientnumber, data=dat3, length)
names(dat4)[2] <- "numberNonoverlappingDays"
dat4

<强>结果:

> dat4
  patientnumber numberNonoverlappingDays
1           100                        8
2           200                        7
3           300                        8