2016-12-07 23 views
1

我試圖分析遊戲數據,但我需要刪除指定行後的所有行。刪除時間序列中指定行下的所有行

在以下情況下,我想刪除每個用戶的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

我們可以使用data.table。轉換「data.frame」到「data.table」,由「UID」分組,得到邏輯矢量(EVENT == "Die")的雙cumsum,檢查它是否小於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。評論)

+0

這是關於'dplyr'部分 - 這很漂亮,而且很靈活。 「slice」部分需要'seq',因爲否則它只會返回匹配的行。我是否正確?而'nomatch = n()'意味着在不匹配的情況下結束?順便說一句,也許你也可以建議在末尾加上'%>%ungroup()%>%as.data.frame()'來得到一個清理好的數據框。 –

+0

@ R.S。你是對的,如果你不使用'seq',只會得到匹配的行,'nomatch = n()'是在沒有特定UID匹配的特殊情況下。有些人更喜歡將他們的輸出作爲「tbl_df」。所以,我會留下它,並添加您的評論 – akrun

+1

啊。謝謝。洞察力有所幫助。 –

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 
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鍵基於i排除x行,類似於它如何與向量一起工作(其中i必須是邏輯向量)。

  • on=.(ID, v >= v)選項告訴R我們正在進行「非等聯接」。「該v >= v部分指vi(在左側)應該比vx更大(在右側)。

結合這兩個,我們要排除。滿足在on=規定的標準行


旁註有一對夫婦的事情,我不知道:我們有比非等距一個更好的名字加入爲什麼v上即使x[i]已在i的左側有xi

我從Psidom和akrun的回答中借用了head和一個不等式。其中一個(也許?)的優勢是head(.SD, 1L)is optimized,而head(.SD, expr)還沒有。

+0

非常好的使用非平等聯接 – akrun