2012-05-06 10 views
22

Dato un codice di ordinamento, esiste un collegamento data.table per duplicare le funzionalità first e last che si trovano in SAS e SPSS?utilizzando data.table per contrassegnare il primo (o ultimo) record in un gruppo

L'approccio pedonale sottostante indica il primo record di un gruppo.

Data l'eleganza di data.table (con cui sto lentamente diventando familiare), presumo ci sia una scorciatoia utilizzando un join automatico & mult, ma sto ancora cercando di capirlo.

Ecco l'esempio:

require(data.table) 

set.seed(123) 
n <- 17 
DT <- data.table(x=sample(letters[1:3],n,replace=T), 
       y=sample(LETTERS[1:3],n,replace=T)) 
sortkey <- c("x","y") 
setkeyv(DT,sortkey) 
key <- paste(DT$x,DT$y,sep="-") 
nw <- c(T , key[2:n]!=key[1:(n-1)]) 
DT$first <- 1*nw 
DT 
+0

buone risposte qui, tra cui una di dati. soluzione di tabella: http://stats.stackexchange.com/questions/7884/fast-ways-in-r-to-get-the-first-row-of-a-data-frame-grouped-by-an-identifier/7889 # 7889 – Chase

+0

Penso che M.Mimo voglia specificamente * etichettare * il primo e l'ultimo nel gruppo anziché * estrarli *. Il link che hai indicato, così come l'approccio 'mult' cui l'OP si riferisce, mostra come estrarre *, non * etichetta *. –

risposta

21

Ecco paio di soluzioni che utilizzano data.table:

## Option 1 (cleaner solution, added 2016-11-29) 
uDT <- unique(DT) 
DT[, c("first","last"):=0L] 
DT[uDT, first:=1L, mult="first"] 
DT[uDT, last:=1L, mult="last"] 


## Option 2 (original answer, retained for posterity) 
DT <- cbind(DT, first=0L, last=0L) 
DT[DT[unique(DT),,mult="first", which=TRUE], first:=1L] 
DT[DT[unique(DT),,mult="last", which=TRUE], last:=1L] 

head(DT) 
#  x y first last 
# [1,] a A  1 1 
# [2,] a B  1 1 
# [3,] a C  1 0 
# [4,] a C  0 1 
# [5,] b A  1 1 
# [6,] b B  1 1 

C'è ovviamente un sacco confezionato in ciascuna di queste linee. Il costrutto chiave, però, è il seguente, che restituisce l'indice di riga del primo record in ogni gruppo:

DT[unique(DT),,mult="first", which=TRUE] 
# [1] 1 2 3 5 6 7 11 13 15 
+0

Grazie per la risposta. Avevo la sensazione che fosse possibile usando il join e "first", ma non riuscivo a capire la sintassi corretta. Eccolo, chiaramente spiegato. Grazie ancora. –

+0

+1 bello sapere l'argomento 'which' –

+0

Grazie, entrambi. In pratica, probabilmente userei qualcosa come l'approccio di @ PrasadChalasani. Ma ho pensato che si trattasse di una bella demo di un insieme di funzionalità di 'data.table' e speravo che altri potessero trovarlo utile. Sarò anche interessato ad apprendere (a) se c'è una soluzione data.table migliore per questo, e (b) se c'è un modo migliore di "unique (DT)" di estrarre tutte le combinazioni di tasti univoche nel 'data.table '. –

8

Un modo semplice è quello di utilizzare la funzione duplicated(). Quando applicato a un frame di dati, produce un vettore in cui una voce è TRUE se e solo se la combinazione di valori di riga non si è verificata prima, quando si sposta verso il basso il frame di dati.

DT$first <- !duplicated(DT[, list(x,y) ])                                                          
DT$last <- rev(!duplicated(DT[, list(rev(x),rev(y)) ]))                                                      

> DT                                                                   
     x y first last                                                               
    [1,] a A TRUE TRUE                                                               
    [2,] a B TRUE TRUE                                                               
    [3,] a C TRUE FALSE                                                               
    [4,] a C FALSE TRUE                                                               
    [5,] b A TRUE TRUE                                                               
    [6,] b B TRUE TRUE                                                               
    [7,] b C TRUE FALSE                                                               
    [8,] b C FALSE FALSE                                                               
    [9,] b C FALSE FALSE                                                               
[10,] b C FALSE TRUE                                                               
[11,] c A TRUE FALSE                                                               
[12,] c A FALSE TRUE                                                               
[13,] c B TRUE FALSE                                                               
[14,] c B FALSE TRUE                                                               
[15,] c C TRUE FALSE                                                               
[16,] c C FALSE FALSE                                                               
[17,] c C FALSE TRUE    

Un altro modo senza utilizzare duplicated() è:

DT[ unique(DT), list(first = c(1, rep(0,length(y)-1)),                                                       
        last = c(rep(0,length(y)-1),1)) ]  

     x y first last                                                             
    [1,] a A  1 1                                                               
    [2,] a B  1 1                                                               
    [3,] a C  1 0                                                               
    [4,] a C  0 1                                                               
    [5,] b A  1 1                                                               
    [6,] b B  1 1                                                               
    [7,] b C  1 0                                                               
    [8,] b C  0 0                                                               
    [9,] b C  0 0                                                               
[10,] b C  0 1                                                               
[11,] c A  1 0                                                               
[12,] c A  0 1                                                               
[13,] c B  1 0                                                               
[14,] c B  0 1                                                               
[15,] c C  1 0                                                               
[16,] c C  0 0                                                               
[17,] c C  0 1   
+0

Grazie! Mi chiedo ancora una soluzione data.table, ma l'eleganza si qualifica sicuramente in questo caso. –

+0

Prego ... Ho appena aggiunto un altro modo per farlo. La funzione 'mult' cui ti riferisci è solo per selezionare la prima o l'ultima (o tutte) corrispondenze quando ci sono più corrispondenze all'argomento' i' in 'DT [i, j, mult = ...]' –

1

Un modo più semplice di Josh può essere

unique(DT) 
unique(DT,fromLast=TRUE] 
Problemi correlati