删除时间系列中指定行下的所有行

时间:2016-12-07 02:30:38

标签: r data.table

我正在尝试分析游戏数据,但我需要删除指定行之后的所有行。

在以下情况中,我想删除每个用户的EVENT“Die”之后的所有行。数据按UID,TIME.HOUR排序。

DF:

 UID  TIME.HOUR  EVENT
  1      5       Run
  1      5       Run
  1      6       Run
  1      7       Die
  1      8       Run
  1      9       Run
  2      14      Jump
  2      15      Die
  2      16      Run
  2      17      Run

预期结果:

 UID  TIME.HOUR  EVENT
  1      5       Run
  1      5       Run
  1      6       Run
  1      7       Die
  2      14      Jump
  2      15      Die

我认为我正在使用下面的代码走上正轨,但不要在下一步中挣扎。

 args <- which(df$EVENT== "Die")
 df[,c(sapply(args, function(x) ???), by = UID] #seq? range? 

谢谢。

3 个答案:

答案 0 :(得分:3)

我们可以使用data.table。转换&#39; data.frame&#39;通过&#39; UID&#39;分组到&#39; data.table&#39;,得到逻辑向量的双cumsumEVENT == "Die"),检查它是否小于2子集Data.table(.SD

library(data.table)
setDT(df)[, .SD[cumsum(cumsum(EVENT=="Die"))<2] , UID]
#   UID TIME.HOUR EVENT
#1:   1         5   Run
#2:   1         5   Run
#3:   1         6   Run
#4:   1         7   Die
#5:   2        14  Jump
#6:   2        15   Die

Or a faster approach:获取行索引,提取该列($V1)以对数据进行子集化

setDT(df)[df[, .I[cumsum(cumsum(EVENT=="Die"))<2] , UID]$V1]

或修改@ Psidom的方法

setDT(df)[df[, .I[seq(match("Die", EVENT, nomatch = .N))] , UID]$V1]

或使用dplyr

library(dplyr)
df %>%
   group_by(UID) %>% 
   slice(seq(match("Die", EVENT, nomatch = n())))
#    UID TIME.HOUR EVENT
#  <int>     <int> <chr>
#1     1         5   Run
#2     1         5   Run
#3     1         6   Run
#4     1         7   Die
#5     2        14  Jump
#6     2        15   Die

如果我们需要一个data.frame输出,带%>% as.data.frame的链(来自@ R.S。评论)

答案 1 :(得分:3)

这可能不是那么有效,但你可以做一个花哨的加入:

mdf = df[EVENT == "Die", head(.SD, 1L), by=UID, .SDcols = "TIME.HOUR"]
df[!mdf, on=.(UID, TIME.HOUR > TIME.HOUR)]

   UID TIME.HOUR EVENT
1:   1         5   Run
2:   1         5   Run
3:   1         6   Run
4:   1         7   Die
5:   2        14  Jump
6:   2        15   Die

当然,您实际上不需要将mdf表另存为单独的对象。

工作原理

  • x[!i],其中i是另一个data.table或向量列表,是一个反连接,告诉R根据{{1}排除x行类似于它如何与向量一起工作(其中i必须是一个逻辑向量)。

  • i选项告诉R我们正在进行“非等连接”。 on=.(ID, v >= v)部分意味着来自v >= v(左侧)的v应该大于来自i的{​​{1}}(右侧)手边)。

将这两者结合起来,我们排除的行符合v中指定的条件。

附注。有几件我不确定的事情:我们有一个比非equi加入更好的名字吗?为什么x左侧的on=即使v i左侧有x[i]

我借用Psidom和akrun的答案,使用x和不平等。这里的一个(可能是?)优势是i is optimizedhead还没有。

答案 2 :(得分:2)

另一种选择,您可以将head()match()一起使用(找到第一个Die索引):

dt[, head(.SD, match("Die", EVENT, nomatch = .N)), UID]   # if no match is found within the 
                                                          # group, return the whole group

#   UID TIME.HOUR EVENT
#1:   1         5   Run
#2:   1         5   Run
#3:   1         6   Run
#4:   1         7   Die
#5:   2        14  Jump
#6:   2        15   Die