【问题标题】:Finding closest matching time for each patient为每位患者寻找最接近的匹配时间
【发布时间】:2017-02-01 14:54:41
【问题描述】:

我有两组数据:

第一组:

 patient<-c("A","A","B","B","C","C","C","C")
 arrival<-c("11:00","11:00","13:00","13:00","14:00","14:00","14:00","14:00")
 lastRow<-c("","Yes","","Yes","","","","Yes")

 data1<-data.frame(patient,arrival,lastRow)

另一组数据:

 patient<-c("A","A","A","A","B","B","B","C","C","C")
 availableSlot<-c("11:15","11:35","11:45","11:55","12:55","13:55","14:00","14:00","14:10","17:00")

 data2<-data.frame(patient, availableSlot)

我想向第一个数据集添加一列,这样对于每个患者的最后一行,它会显示可用的插槽,即 最接近到达时间:

结果是:

  patient arrival lastRow availableSlot
       A   11:00        
       A   11:00     Yes     11:15
       B   13:00        
       B   13:00     Yes     12:55
       C   14:00        
       C   14:00        
       C   14:00        
       C   14:00     Yes     14:00

如果有人能告诉我如何在 R 中实现这一点,我将不胜感激。

【问题讨论】:

  • 您可能需要先将包含小时数的列转换为日期类
  • 所以这个? merge(data1, data2[!duplicated(data2$patient),], by = 'patient') 假设您的 data2arrival 订购
  • @Sotos 不,这只是幸运。 OP 说“最接近”,恰好与这里的第一个相吻合。
  • 啊...我错过了最近的部分

标签: r dataframe time logic


【解决方案1】:

我会使用 data.table,首先通过转换为 ITime 并忽略冗余行进行清理:

library(data.table)
setDT(data1)[, arrival := as.ITime(as.character(arrival))]
setDT(data2)[, availableSlot := as.ITime(as.character(availableSlot))]
DT1 = unique(data1, by="patient", fromLast=TRUE)

然后你可以做一个“滚动连接”:

res = data2[DT1, on=.(patient, availableSlot = arrival), roll="nearest", 
  .(patient, availableSlot = x.availableSlot)]

#    patient availableSlot
# 1:       A      11:15:00
# 2:       B      12:55:00
# 3:       C      14:00:00

它是如何工作的

语法是x[i, on=, roll=, j]

  • on= 是合并列。
  • 这是一个连接:对于i 的每一行,我们都在x 中寻找匹配项。
  • 使用roll="nearest"on= 中的最后一列“滚动”到最接近的匹配项。
  • 原始表中的on= 列可以用x.*i.* 前缀引用。
  • j 参数应该给出列列表,.()list() 的别名。

http://r-datatable.com/Getting-started 上查看包的介绍性材料,并输入?data.table 以获取与滚动连接相关的文档。


我会在res 停下来,但如果你真的想把它放回原来的桌子上......

# a very nonstandard step:
data1[lastRow == "Yes", availableSlot := res$availableSlot ]

#    patient  arrival lastRow availableSlot
# 1:       A 11:00:00                  <NA>
# 2:       A 11:00:00     Yes      11:15:00
# 3:       B 13:00:00                  <NA>
# 4:       B 13:00:00     Yes      12:55:00
# 5:       C 14:00:00                  <NA>
# 6:       C 14:00:00                  <NA>
# 7:       C 14:00:00                  <NA>
# 8:       C 14:00:00     Yes      14:00:00

现在,data1 在新列中添加了 availableSlot,类似于您使用 data1$col &lt;- val 时的情况。

【讨论】:

  • 精彩解释+1!
  • 一如既往的好解释
  • 非常感谢您的帮助。请问x.availableSlot中的x是什么?
  • @Headandtoes 当然。如果您通过键入?data.table 查看文档,您会看到语法为x[i, ...],并且可以使用x.*i.* 表示法来引用正在连接的列(在on= 中)从各自的表中取出它们。这些很有用,因为 x.colnamei.colname 在像这样的滚动连接中可能会有所不同(以及其他一些特殊情况)。
  • @Headandtoes 是的,为此,您需要as.ITime(as.POSIXct("02Aug2016 11:15:00", format = "%d%b%Y %H:%M:%S")) 或者只是坚持使用 POSIXct 而不是提取时间。有关相关文档,请参阅?strptime。如果您不想过多地摆弄日期时间格式,您也可以尝试anytime 包,它似乎可以可靠地猜出相关的format
【解决方案2】:

这是一个解决方案(基于joel.wilson's answer 对我的问题),它适用于基础R

#Convert dates to POSIXct format
data1$arrival = as.POSIXct(data1$arrival, format = "%H:%M")
data2$availableSlot = as.POSIXct(data2$availableSlot, format = "%H:%M")

#Lookup times from data2$availableSlot closest to data1$arrival
data1$availableSlot = sapply(data1$arrival, function(x)
                    data2$availableSlot[which.min(abs(x - data2$availableSlot))])

#Keep just hour and minutes
data1$availableSlot = strftime(as.POSIXct(data1$availableSlot, 
                                origin = "1970-01-01"), format = "%H:%M")
data1$arrival = strftime(as.POSIXct(data1$arrival), format = "%H:%M")

#Remove times when lastrow is empty
data1$availableSlot[which(data1$lastRow != "Yes")] = ""

【讨论】:

    猜你喜欢
    • 2011-03-01
    • 2015-03-18
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多