在R中按组检查重叠的开始和结束时间(当数据有NA时运行错误)

3

这是对之前问题的跟进,但由于NA的原因,我遇到了答案提供的问题:

require(data.table)
ID <- c(rep(1,4), rep(3, 5), rep(4,4),rep(5,5))
Begin <- c(0,2.5,NA,3,7,8,7,25,25,10,15,0,0,1,NA,10,11,13)
End <- c(1.5,3.5,NA,6,12,8,11,29,35, 12,19,NA,28,5,20,30,20,25)
df <- data.table(ID, Begin, End)
df[, Begin_New := {
  high_so_far = shift(cummax(End), fill=Begin[1L])
  w = which(Begin < high_so_far)
  Begin[w] = high_so_far[w]
  Begin
}, by=ID]
    ID   Begin  End    Begin_New
  1:  1   0.0  1.5       0.0
  2:  1   2.5  3.5       2.5
  3:  1    NA   NA        NA
  4:  1   3.0  6.0       3.0* # <~~ it supposed 3.5
  5:  3   7.0 12.0       7.0
  6:  3   8.0  8.0      12.0
  7:  3   7.0 11.0      12.0
  8:  3  25.0 29.0      25.0
  9:  3  25.0 35.0      29.0
 10:  4  10.0 12.0      10.0
 11:  4  15.0 19.0      15.0
 12:  4   0.0   NA      19.0
 13:  4   0.0 28.0       0.0* # <~~ it's supposed 19.0
 14:  5   1.0  5.0       1.0
 15:  5    NA 20.0        NA
 16:  5  10.0 30.0      20.0
 17:  5  11.0 20.0      30.0
 18:  5  13.0 25.0      30.0

我尝试检查重叠部分,如果起始时间小于结束时间,则需要按照每个ID设置Begin_New等于前一个End,并持续检查直到Begin大于End。但是当结束时间变量为NA时,代码无法理解,需要继续检查数值。我尝试了几种代码,但都没有成功。


我明白了,添加setDT(df)[ !is.na(End), Begin_New := { high_so_far = shift(cummax(End), fill=Begin[1L]) w = which(Begin < high_so_far) Begin[w] = high_so_far[w] Begin }, by=ID] - BIN
2个回答

5
您可以在之前添加另一个步骤:
df[, Begin_New := {
  End[is.na(End)] = 0 # <- new step here
  high_so_far = shift(cummax(End), fill=Begin[1L])
  w = which(Begin < high_so_far)
  Begin[w] = high_so_far[w]
  Begin
}, by=ID][]

我是如何解决这个问题的。 为了解决这种问题,我会逐步运行j从一组到另一组:

df[, if (.GRP == 1L){
  high_so_far = shift(cummax(End), fill=Begin[1L])
  print(high_so_far)
  # w = which(Begin < high_so_far)
  # Begin[w] = high_so_far[w]
  # Begin
}, by=ID][]

# 0.0 1.5 3.5  NA

所以我可以看到问题出现的地方,并通过读取?cummax来解决它,以查看是否有na.rm选项。在那里找不到一个选项,我可以考虑在这个步骤之前或之后采取什么其他步骤来达到所需的结果。
如果我在这一步没有发现问题,那么我可以逐渐取消后面的行并添加更多的print语句。或者我可以将.GRP==1更改为其他组。正如@jangorecki提到的,你也可以尝试一些正确的调试方法:

你也可以在j={...}中放置browser()并交互式地调查当前状态


1
你可以将 browser() 放在 j={...} 中并进行交互式地调查当前状态。 - jangorecki
使用 cummax 是一个不错的选择。 - akrun
谢谢你的指点,@jangorecki。我一直想学习如何使用它。 - Frank

1

不确定是否应该发布此内容,但@Arun在评论中发布了解决方案,但仅当运行OP的代码时才有效。Arun删除了他的评论并没有重新发布,所以我认为我会把它作为答案发布,这样OP和其他人就可以看到它。请随意在其他地方给出信用。

library(data.table)

ID <- c(rep(1,4), rep(3, 5), rep(4,4),rep(5,5))
Begin <- c(0,2.5,NA,3,7,8,7,25,25,10,15,0,0,1,NA,10,11,13)
End <- c(1.5,3.5,NA,6,12,8,11,29,35, 12,19,NA,28,5,20,30,20,25)
df <- data.frame(ID, Begin, End)
df
setDT(df)[, Begin_New := {
  high_so_far = shift(cummax(End), fill=Begin[1L])
  w = which(Begin < high_so_far)
  Begin[w] = high_so_far[w]
  Begin
}, by=ID]

setDT(df)[!is.na(Begin) & !is.na(End), Begin_New := {
  high_so_far = shift(cummax(End), fill=Begin[1L])
  w = which(Begin < high_so_far)
  Begin[w] = high_so_far[w]
  Begin
}, by=ID]

df
    ID Begin  End Begin_New
 1:  1   0.0  1.5       0.0
 2:  1   2.5  3.5       2.5
 3:  1    NA   NA        NA
 4:  1   3.0  6.0       3.5
 5:  3   7.0 12.0       7.0
 6:  3   8.0  8.0      12.0
 7:  3   7.0 11.0      12.0
 8:  3  25.0 29.0      25.0
 9:  3  25.0 35.0      29.0
10:  4  10.0 12.0      10.0
11:  4  15.0 19.0      15.0
12:  4   0.0   NA      19.0
13:  4   0.0 28.0      19.0
14:  5   1.0  5.0       1.0
15:  5    NA 20.0        NA
16:  5  10.0 30.0      10.0
17:  5  11.0 20.0      30.0
18:  5  13.0 25.0      30.0

1
是的,所以加入相同的代码,如!is.na(Begin)和!is.na(End),它就可以工作了。 - BIN
哦不,第16行需要变成20。 - BIN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接