2015-04-15 20 views
5

Mam data.table który wygląda takJak liczyć ile razy element pojawia się kolejno w data.table?

ID, Order, Segment 
1, 1, A 
1, 2, B 
1, 3, B 
1, 4, C 
1, 5, B 
1, 6, B 
1, 7, B 
1, 8, B 

Zasadniczo zamawiając danych przy użyciu kolumny Order. Chciałbym zrozumieć liczbę kolejnych B dla każdego z ID. Idealnie byłoby, że wyjście jak to

ID, Consec 
1, 2 
1, 4 

Ponieważ segment B pojawia się kolejno w rzędzie 2 i 3 (2 razy), a następnie ponownie w rzędzie 5,6,7,8 (4 razy).

Rozwiązanie pętli jest dość oczywiste, ale będzie również bardzo powolne.

Czy są też eleganckie rozwiązania w data.table, które również są szybkie?

P.S. Dane, z którymi mam do czynienia, mają ~ 20 milionów wierszy.

Odpowiedz

10

Spróbuj

library(data.table)#v1.9.5+ 
    DT[order(ID, Order)][, indx:=rleid(Segment)][Segment=='B', 
    list(Consec=.N), by = list(indx, ID)][,indx:=NULL][] 

# ID Consec 
#1: 1  2 
#2: 1  4 

Albo jak @eddi zasugerował

DT[order(ID, Order)][, .(Consec = .N), by = .(ID, Segment, 
       rleid(Segment))][Segment == 'B', .(ID, Consec)] 
# ID Consec 
#1: 1  2 
#2: 1  4 

Bardziej pamięć skuteczną metodą byłoby użycie setorder zamiast order (jak sugeruje @Arun)

setorder(DT, ID, Order)[, .(Consec = .N), by = .(ID, Segment, 
       rleid(Segment))][Segment == 'B', .(ID, Consec)] 
    # ID Consec 
    #1: 1  2 
    #2: 1  4 
+6

tak naprawdę nie musisz jawnie tworzyć nowej kolumny i możesz to zrobić w locie: 'DT [order (ID, Zamówienie)] [,. (Consec =. N), przez =. (ID, Segment, rleid (Segment))] [Segment == "B",. (ID, Consec)] ' – eddi

+0

@eddi Dzięki, to jest bardziej kompaktowy. – akrun

+0

Dlaczego potrzebujesz 'order()'? – Arun

Powiązane problemy