【问题标题】:Filling in missing (blanks) in a data table, per category - backwards and forwards按类别填充数据表中的缺失(空白) - 向后和向前
【发布时间】:2012-09-18 10:01:19
【问题描述】:

我正在处理我 11 年以上临床实践的账单记录的大型数据集。相当多的行缺少转诊医生。但是,使用一些规则我可以​​很容易地填写它们,但不知道如何在 R 下的 data.table 中实现它。我知道 zoo 包中有 na.locf 和数据中的 self rolling join 之类的东西。表包。我看到的例子太简单了,对我没有帮助。

这里有一些虚构的数据来指导你(作为 dput ASCII 文本表示)

    structure(list(patient.first.name = structure(c(1L, 1L, 1L, 1L, 
1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L), .Label = c("John", "Kathy", 
"Timothy"), class = "factor"), patient.last.name = structure(c(3L, 
3L, 3L, 3L, 3L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L), .Label = c("Jones", 
"Martinez", "Squeal"), class = "factor"), medical.record.nr = c(4563455, 
4563455, 4563455, 4563455, 4563455, 2663775, 2663775, 2663775, 
2663775, 2663775, 3330956, 3330956, 3330956, 3330956), date.of.service = c(39087, 
39112, 39112, 39130, 39228, 39234, 39244, 39244, 39262, 39360, 
39184, 39194, 39198, 39216), procedure.code = c(44750, 38995, 
40125, 44720, 44729, 44750, 38995, 40125, 44720, 44729, 44750, 
44729, 44729, 44729), diagnosis.code.1 = c(456.87, 456.87, 456.87, 
456.87, 456.87, 521.37, 521.37, 521.37, 521.37, 356.36, 456.87, 
456.87, 456.87, 456.87), diagnosis.code.2 = c(413, 413, 413, 
413, 413, 532.23, NA, NA, NA, NA, NA, NA, NA, NA), referring.doctor.first = structure(c(1L, 
1L, 1L, 1L, 1L, 2L, 2L, 2L, NA, NA, NA, 1L, 1L, NA), .Label = c("Abe", 
"Mark"), class = "factor"), referring.doctor.last = structure(c(1L, 
1L, 1L, 1L, 1L, 2L, 2L, 2L, NA, NA, NA, 1L, 1L, NA), .Label = c("Newstead", 
"Wydell"), class = "factor"), referring.docotor.zip = c(15209, 
15209, 15209, 15209, 15209, 15222, 15222, 15222, NA, NA, NA, 
15209, 15209, NA), some.other.stuff = structure(c(1L, 1L, 1L, 
NA, 3L, NA, NA, 4L, NA, 6L, NA, 2L, 5L, NA), .Label = c("alkjkdkdio", 
"cheerios", "ddddd", "dddddd", "dogs", "lkjljkkkkk"), class = "factor")), .Names = c("patient.first.name", 
"patient.last.name", "medical.record.nr", "date.of.service", 
"procedure.code", "diagnosis.code.1", "diagnosis.code.2", "referring.doctor.first", 
"referring.doctor.last", "referring.docotor.zip", "some.other.stuff"
), row.names = c(NA, 14L), class = "data.frame")

显而易见的解决方案是在 refer.doctor.last 和 refer.doctor.first 上使用某种最后观察结转 (LOCF) 算法。但是,当它到达新患者时,它必须停止。换言之,LOCF 必须仅应用于由患者.first.name、患者.last.name、medical.record.nr 的组合标识的一位患者。另请注意,有些患者在第一次就诊时会错过转诊医生,这意味着必须向后进行一些观察。更复杂的是,一些患者会更换初级保健医生,因此可能会在更早的时候有一位转诊医生,而在以后可能会有另一位转诊医生。因此,该算法需要了解具有缺失值的行的日期顺序。

在动物园na.locf 我看不到一种简单的方法来对每个患者的 LOCF 进行分组。我看到的滚动连接示例在这里不起作用,因为我不能简单地取出缺少 refering.doctor 信息的行,因为我会丢失 date.of.service 和 procedure.code 等。我希望您能帮助我了解 R 如何填补我缺失的数据。

【问题讨论】:

  • 您可以使用ave(Data, [unique patient identifier], FUN=na.locf) 对每位患者进行分组。您可以使用fromLast 参数将顺序颠倒到na.locf。
  • @Farrel。我看到了您对我的答案提出的修改,但在我看到它之前,一个模组已经拒绝了它。它对我来说看起来非常好和正确!但是,只需添加一个新答案即可。认为这就是它可能被拒绝的原因。可以自己回答,我会投票给它。

标签: r data.table zoo missing-data


【解决方案1】:

一个更简洁的例子会更容易回答。例如,您包含了相当多的列,这些列似乎是多余的。真的需要按名字和姓氏,还是我们可以使用患者编号?

由于您希望填写的数据中已经有NAs,所以data.table 中的roll 不是真的。当您的数据没有 NA 但您有另一个时间序列(例如)连接到数据中间的位置时,滚动连接更适用。 (一个效率优势是您不首先创建NA,然后您必须填写第二步。)或者,换句话说,在您的问题中您只有一个数据集;你没有加入两个。

所以你确实需要na.locf @Joshua 建议。不过,我不知道有一个函数可以将NA 向前然后向后填充第一个值。

在data.table 中,按组使用na.locf 只是:

require(data.table)
require(zoo)
DT[,doctor:=na.locf(doctor),by=patient]

具有快速聚合和引用更新的效率优势。您必须在 na.locf 之上编写一个新的小函数来向后滚动第一个非 NA。

确保数据首先按患者排序,然后按日期排序。那么上面的内容会随着时间的推移应对医生的变化,因为by维护了每个组内的行顺序。

希望能给你一些提示。

【讨论】:

    【解决方案2】:

    @MatthewDowle 为我们提供了一个很好的起点,我们将在这里得出结论。

    简而言之,使用 zoo 的na.locf。该问题不适用于滚动连接。

    setDT(bill)
    bill[,referring.doctor.last:=na.locf(referring.doctor.last,na.rm=FALSE),
         by=list(patient.last.name, patient.first.name, medical.record.nr)]
    bill[,referring.doctor.last:=na.locf(referring.doctor.last,na.rm=FALSE,fromLast=TRUE),
         by=list(patient.last.name, patient.first.name, medical.record.nr)]
    

    然后为referring.doctor.first做类似的事情

    几点建议:

    1. by 语句确保最后的观察结果仅限于同一患者,这样就不会“流血”到列表中的下一位患者。

    2. 必须使用na.rm=FALSE 参数。如果不这样做,那么在第一次就诊时缺少转诊医生信息的患者将删除NA,并且新值的向量(现有+结转)将是行数不足的一个元素。缩短的向量被回收,所有内容都向上移动,最后一行在回收时获取向量的第一个元素。换句话说,大乱。最糟糕的是,您有时只会看到它。

    3. 使用fromLast=TRUE 再次遍历该列。这会填充任何数据之前的 NA。动物园使用下一个后向观察(NOCB)代替最后一次观察结转(LOCF)。幸福——您现在已经以适合大多数情况的方式填写了缺失的数据。

    4. 每行可以传递多个:=,例如DT[,`:=`(new=1L,new2=2L,...)]

    【讨论】:

    • +1 您可以嵌套两个na.locf 调用,以保存两次分组;例如,na.locf(na.locf(referring.doctor.last,na.rm=FALSE),na.rm=FALSE,fromLast=TRUE)。或者事先将其包装成一个简短的辅助函数。
    • 而不是#4,使用overwrite<-paste0("referring.doctor.",c("last","first")); bill[,(overwrite):=lapply(.SD,function(x)na.locf(na.locf(x,na.rm=F),na.rm=F,fromLast=T)),.SDcols=overwrite]可能会更简洁@
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    • 2017-08-12
    • 2016-11-03
    相关资源
    最近更新 更多