2015-04-15 11 views
5

Ho un data.table che assomiglia a questoCome contare il numero di volte in cui un elemento appare consecutivamente in un 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 

Fondamentalmente ordinando i dati utilizzando la colonna Ordine. Mi piacerebbe capire il numero di B consecutive per ciascuno degli ID. Idealmente l'uscita desidero è

ID, Consec 
1, 2 
1, 4 

Poiché il segmento B appare consecutivamente nella riga 2 e 3 (2 volte), e poi nuovamente nella riga 5,6,7,8 (4 volte).

La soluzione del ciclo è abbastanza ovvia ma sarebbe anche molto lenta.

Ci sono soluzioni eleganti in data.table che sono anche veloci?

P.S. I dati che sto trattando hanno ~ 20 milioni di righe.

risposta

10

Prova

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 

O come @eddi suggerito

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

Un metodo efficace più memoria potrebbe essere quella di utilizzare setorder invece di order (come suggerito da @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

non hai davvero bisogno di creare una nuova colonna in modo esplicito e puoi farlo al volo: 'DT [ordine (ID, Ordine)] [,. (Consec = .N), di =. (ID, Segmento, rleide (Segmento))] [Segmento == 'B',. (ID, Consec)] ' – eddi

+0

@eddi Grazie, cioè più compatto. – akrun

+0

Perché hai bisogno di 'order()'? – Arun

Problemi correlati