2016-07-12 5 views
2

ich ein data.table in der folgenden Form habe:data.table Reihen von Gruppe basierend auf Verzögerungswert entfernen

DT <- data.table(tag = rep(c("A", "B"), each = 10), 
       value = c(0, 3, 3, 3, 0, 1, 1, 1, 3, 0, 
          0, 1, 3, 1, 0, 3, 0, 1, 1, 0)) 
> DT 
    tag value 
1: A  0 
2: A  3 
3: A  3 
4: A  3 
5: A  0 
6: A  1 
7: A  1 
8: A  1 
9: A  3 
10: A  0 
11: B  0 
12: B  1 
13: B  3 
14: B  1 
15: B  0 
16: B  3 
17: B  0 
18: B  1 
19: B  1 
20: B  0 

ich alle Zeilen entfernen möchte, die den Wert von 3, sondern nur diejenigen, folgen einem 0. Das heißt, ich möchte Zeile 2, 3, 4 und Zeile 16 entfernen, aber Zeile 9 und Zeile 13 beibehalten müssen.

Gibt es eine Möglichkeit, dies durchzuführen?

Antwort

5

Eine mögliche Lösung:

DT[, `:=` (threes = rleid(value==3), apz = value == 3 & shift(value) == 0) 
    ][, if (all(!apz)) .SD, by = threes 
    ][, c('threes','apz') := NULL] 

die gibt:

tag value 
1: A  0 
2: A  0 
3: A  1 
4: A  1 
5: A  1 
6: A  3 
7: A  0 
8: B  0 
9: B  1 
10: B  3 
11: B  1 
12: B  0 
13: B  0 
14: B  1 
15: B  1 
16: B  0 
3
DT[, prev.value := shift(value), by = tag][ 
    , prev.value := prev.value[1], by = .(tag, rleid(value))][ 
    !(value == 3 & prev.value == 0)] 
# tag value prev.value 
# 1: A  0   NA 
# 2: A  0   3 
# 3: A  1   0 
# 4: A  1   0 
# 5: A  1   0 
# 6: A  3   1 
# 7: A  0   3 
# 8: B  0   NA 
# 9: B  1   0 
#10: B  3   1 
#11: B  1   3 
#12: B  0   1 
#13: B  0   3 
#14: B  1   0 
#15: B  1   0 
#16: B  0   1 
2

Hier ist ein Einzeiler von Sorten (Requisiten @Procrastinatus zur Verbesserung):

DT[setDT(rle(value))[, rep(!(values==3 & shift(values)==0), lengths)] ] 

Um zu verstehen, wie es funktioniert, versuchen Sie es Ausführen von DT[, setDT(rle(value))], zeigt, wie R Läufe von sequenziellen Werten zusammenfasst, und lesen ?rle.


Mein ursprünglicher Ansatz war:

DT[ rleid(value) %in% setDT(rle(value))[ , .I[!(values==3 & shift(values)==0)]] ] 

DT[, rleid(value)] Versuchen und ?rleid für Details zu lesen. Dieser zweite Ansatz ist schlechter, da die Läufe zweimal ausgewertet werden (unter Verwendung von rle und rleid).

+0

Ich wünschte, ich könnte dies schreiben, ohne die Läufe zweimal zu bewerten (mit RLE und RLEID), aber konnte nicht auf eine nette Weise denken. – Frank

+0

Schön auch! Eine Alternative mit nur 'rle':' DT [setDT (rle (Wert)) [, rem: =! (Werte == 3 & Verschiebung (Werte) == 0)] [, rep (rem, Längen)]] ' – Jaap

+1

Noch kürzer: 'DT [setDT (rle (Wert)) [, rep (! (Werte == 3 & Verschiebung (Werte) == 0), Längen)]]' – Jaap

Verwandte Themen