标记事件之前标记事件的快速实现

时间:2014-12-11 09:56:04

标签: r

我需要一种更快/矢量化的方式来实现以下b / c,对于具有数百万个条目的大型数据集,循环需要很长时间。但到目前为止,没有任何好处出现在我的脑海里。

df <- data.frame(
    id = c(1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4),
     t = c(1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 1, 2, 3, 1, 2, 3),
   tag = c(0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0),
  tag2 = 0 # this is supposed to be computed
)

tag_items <- function(df) {
  is1 <- FALSE
  item <- -1

  for(i in nrow(df):1) {
    curr <- df[i,"tag"]

    if(curr == 0) {
      if(item != df[i,"id"]) {
        is1 <- FALSE
        item <- -1
      } else {
        if(is1) {
          df[i,"tag2"] <- 1
        } else {
          df[i,"tag2"] <- 0
        }
      }
    } else if(curr == 1) {
      is1 <- TRUE
      item <- df[i,"id"]
      df[i,"tag2"] <- 1
    } 
  }

  return(df)
}

应用了标记:

> tag_items(df)

   id t tag tag2
1   1 1   0    1
2   1 2   0    1
3   1 3   1    1
4   1 4   0    0
5   2 1   0    1
6   2 2   0    1
7   2 3   1    1
8   2 4   0    0
9   2 5   0    0
10  2 6   0    0
11  3 1   1    1
12  3 2   0    0
13  3 3   0    0
14  4 1   0    0
15  4 2   0    0
16  4 3   0    0

口头解释:

df按时间顺序按idt(ime)排序。对于给定的idtag2的值应该为1,如果有一个值为tag的条目为1,或者tag为1为同一个条目


一种可能的方法是:按ID划分 - > FOCB - &gt;未分裂 - 但我怀疑由于顺序FOCB,该方法不会很快。

FOCB =向后进行第一次观察(LOCF转身)

2 个答案:

答案 0 :(得分:3)

尝试

library(data.table)
setkey(setDT(df), id)[,tag2:=replace(tag2, seq(which(tag==1)),1) , by=id]
df
#   id t tag tag2
#1:  1 1   0    1
#2:  1 2   0    1
#3:  1 3   1    1
#4:  1 4   0    0
#5:  2 1   0    1
#6:  2 2   0    1
#7:  2 3   1    1
#8:  2 4   0    0
#9:  2 5   0    0
#10: 2 6   0    0
#11: 3 1   1    1
#12: 3 2   0    0
#13: 3 3   0    0
#14: 4 1   0    0
#15: 4 2   0    0
#16: 4 3   0    0

或使用dplyr

library(dplyr)
df %>% 
   group_by(id) %>% 
   mutate(tag2= replace(tag2, seq(which(tag==1)),1))

答案 1 :(得分:1)

cumsum目标向量上使用rev的另一种可能性,然后rev得出结果:

library(dplyr)
df %>%
  group_by(id) %>%
  mutate(tag2 = rev(cumsum(rev(tag))))
#    id t tag tag2
# 1   1 1   0    1
# 2   1 2   0    1
# 3   1 3   1    1
# 4   1 4   0    0
# 5   2 1   0    1
# 6   2 2   0    1
# 7   2 3   1    1
# 8   2 4   0    0
# 9   2 5   0    0
# 10  2 6   0    0
# 11  3 1   1    1
# 12  3 2   0    0
# 13  3 3   0    0
# 14  4 1   0    0
# 15  4 2   0    0
# 16  4 3   0    0

或在data.table中应用相同的功能:

library(data.table)
setkey(setDT(df), id)[ , tag2 := rev(cumsum(rev(tag))), by = id]