2010-04-13 16 views
16

Sto provando a comprimere un frame di dati rimuovendo tutte le righe tranne una da ogni gruppo di righe con valori identici in una particolare colonna. In altre parole, la prima riga di ogni gruppo.Blocco di frame di dati selezionando una riga per gruppo

Per esempio, vorrei convertire questo

> d = data.frame(x=c(1,1,2,4),y=c(10,11,12,13),z=c(20,19,18,17)) 
> d 
    x y z 
1 1 10 20 
2 1 11 19 
3 2 12 18 
4 4 13 17 

In questa:

x y z 
1 1 11 19 
2 2 12 18 
3 4 13 17 

sto usando aggregata per fare questo momento, ma la prestazione è inaccettabile con più dati:

Ho provato split/unsplit con lo stesso argomento di funzione di qui, ma unsplit complains abo ut numeri di riga duplicati.

È una possibilità? Esiste un idioma R per convertire il vettore di lunghezza di rle negli indici delle righe che iniziano ogni esecuzione, che posso quindi utilizzare per estrarre quelle righe dal frame dei dati?

risposta

25

Forse duplicated() può aiutare:

R> d[ !duplicated(d$x), ] 
    x y z 
1 1 10 20 
3 2 12 18 
4 4 13 17 
R> 

Modifica Shucks, non importa. Questo sceglie il primo in ogni blocco di ripetizioni, tu volevi l'ultimo. Così qui è un altro tentativo con plyr:

R> ddply(d, "x", function(z) tail(z,1)) 
    x y z 
1 1 11 19 
2 2 12 18 
3 4 13 17 
R> 

Qui plyr fa il duro lavoro di trovare sottoinsiemi unici, loop su di loro e applicando la funzione fornito - che restituisce semplicemente l'ultima serie di osservazioni in un blocco z utilizzando tail(z, 1) .

+0

preferirei tutte le colonne, grazie – jkebinger

+0

allora avete bisogno di aggiungere semplicemente un 'fase di lavorazione' per creare una variabile fattore sul quale plyr può loop. Tutto può essere fatto con i comandi di indicizzazione, provalo. E a proposito, sei incoerente tra il tuo testo (dicendo la prima riga selezionata) e l'esempio (mostrando la seconda riga). –

+0

Ad ogni modo, il cross-posting tra r-help e qui è anche un po 'di scarso stile. Hai buone risposte a r-help, quindi perché non le studi? –

12

solo per aggiungere un po 'a quello che Dirk fornito ... duplicated ha un argomento fromLast che è possibile utilizzare per selezionare l'ultima riga:

d[ !duplicated(d$x,fromLast=TRUE), ] 
+1

Ciao Ian - sfortunatamente James non ha mai chiarito in modo chiaro se voleva il primo o l'ultimo e si contraddice nel post ... ma il tuo suggerimento su Last è buono! –

+0

grazie, funziona come un fascino. Se il primo o l'ultimo di cui avevo bisogno era davvero all'altezza dell'ordinamento, e con l'ultimo attacco posso attaccarlo in entrambi i modi. – jkebinger

+0

Ho suggerito la stessa cosa e l'hai abbattuto per motivi di "preferisci tutte le colonne". Come mai non importa più? –

10

Ecco una soluzione data.table che sarà tempo e efficiente della memoria per grandi insiemi di dati

library(data.table) 
DT <- as.data.table(d)   # convert to data.table 
setkey(DT, x)     # set key to allow binary search using `J()` 
DT[J(unique(x)), mult ='last'] # subset out the last row for each x 
DT[J(unique(x)), mult ='first'] # if you wanted the first row for each x 
+0

Ma se _all_ è necessario l'ultima riga in ogni gruppo, allora 'DT [! Duplicato (x, daLast = TRUE)]' è probabilmente più veloce del tempo totale di 'setkey' + join, e con qualche vantaggio di zucchero sintattico di evitare la ripetizione del nome variabile di' DT' (cioè solo 'x' non' DT $ x'). –

+0

L'uso dell'indice di riga accelererebbe le cose in geuss, DT [DT [, .I [.N], da = x] $ V1]. Controlla http://stackoverflow.com/questions/19424762/efficiently-selecting-top-number-of-rows-for-each-unique-value-of-a-column-in-a. Grazie a @ Simono101 – Freddy

+2

'unique (DT, by =" x ", fromLast = TRUE)' è ora più semplice e veloce di 'DT [! Duplicato (x, daLast = TRUE)]' e 'DT [J (unico (x)), mult = 'last'] ' – Matthew

Problemi correlati