2016-03-15 12 views
6

Ho un set di posizioni di animali con intervalli di campionamento diversi. Quello che voglio fare è raggruppare e le sequenze in cui l'intervallo di campionamento corrisponde a un determinato criterio (ad esempio è inferiore ad un certo valore). Lasciatemi illustrare con alcuni dati dummy:Raggruppamento di righe in base alle differenze di riga in R

start <- Sys.time() 
timediff <- c(rep(5,3),20,rep(5,2)) 
timediff <- cumsum(timediff) 

# Set up a dataframe with a couple of time values 
df <- data.frame(TimeDate = start + timediff) 

# Calculate the time differences between the rows 
df$TimeDiff <- c(as.integer(tail(df$TimeDate,-1) - head(df$TimeDate,-1)),NA) 

# Define a criteria in order to form groups 
df$TimeDiffSmall <- df$TimeDiff <= 5 

      TimeDate TimeDiff TimeDiffSmall 
1 2016-03-15 23:11:49  5   TRUE 
2 2016-03-15 23:11:54  5   TRUE 
3 2016-03-15 23:11:59  20   FALSE 
4 2016-03-15 23:12:19  5   TRUE 
5 2016-03-15 23:12:24  5   TRUE 
6 2016-03-15 23:12:29  NA   NA 

In questo dati fittizi, righe 1: 3 appartengono a un gruppo, in quanto la differenza di tempo tra loro è < = 5 secondi. 4 - 6 appartengono al secondo gruppo, ma ipoteticamente potrebbe esserci un numero di righe tra i due gruppi che non appartengono a nessun gruppo (TimeDiffSmall uguale a FALSE).

Combinando le informazioni da due risposte SO multiple (ad esempio part 1), ho creato una funzione che risolve questo problema.

number.groups <- function(input){ 
    # part 1: numbering successive TRUE values 
    input[is.na(input)] <- F 
    x.gr <- ifelse(x <- input == TRUE, cumsum(c(head(x, 1), tail(x, -1) - head(x, -1) == 1)),NA) 
    # part 2: including last value into group 
    items <- which(!is.na(x.gr)) 
    items.plus <- c(1,items+1) 
    sel <- !(items.plus %in% items) 
    sel.idx <- items.plus[sel] 
    x.gr[sel.idx] <- x.gr[sel.idx-1] 
    return(x.gr) 


# Apply the function to create groups 
df$Group <- number.groups(df$TimeDiffSmall) 

      TimeDate TimeDiff TimeDiffSmall Group 
1 2016-03-15 23:11:49  5   TRUE  1 
2 2016-03-15 23:11:54  5   TRUE  1 
3 2016-03-15 23:11:59  20   FALSE  1 
4 2016-03-15 23:12:19  5   TRUE  2 
5 2016-03-15 23:12:24  5   TRUE  2 
6 2016-03-15 23:12:29  NA   NA  2 

Questa funzione funziona effettivamente per risolvere il mio problema. Questo è, sembra un modo pazzo e rookie per andare su questo. Esiste una funzione che potrebbe risolvere il mio problema in modo più professionale?

+5

Does 'cumsum (c (TRUE, diff (df $ TimeDate)> 5))' lo fai per il tuo esempio più grande? – thelatemail

risposta

2

Come @thelatemail, utilizzerei quanto segue per ottenere gli ID di gruppo. Funziona perché cumsum() finirà per incrementare il conteggio del gruppo ogni volta che raggiunge un elemento preceduto da un intervallo di tempo maggiore di 5 secondi.

df$Group <- cumsum(c(TRUE, diff(df$TimeDate) > 5)) 
df$Group 
# [1] 1 1 1 2 2 2 
+0

Oppure 'cumsum (c (FALSE,! (Diff (df $ TimeDate) <= 5)))' se si desidera continuare a inquadrare la selezione nel modo in cui è, piuttosto che come non lo è. – thelatemail

+0

@thelatemail Questo è quello che ho iniziato con in realtà, e quando ho visto che avrei quindi dovuto aggiungerne uno al risultato (o cambiare l'iniziale 'FALSE' in un' TRUE') per ottenere numeri di gruppo che iniziano con uno, ho capovolto tutto intorno a ciò che sembra l'incantesimo più semplice. –

+0

Abbastanza corretto - dipende, suppongo, se i criteri di selezione sono complessi. Quindi negare è più semplice che provare a capovolgerlo tutto manualmente e assicurarsi che '&' e '|' siano tutti corretti. – thelatemail

Problemi correlati