2012-10-09 12 views
18

Diciamo che ho quattro campioni: id = 1, 2, 3, e 4, con una o più misure su ciascuno di questi campioni:Rimuovere i duplicati mantenendo voce con grande valore assoluto

> a <- data.frame(id=c(1,1,2,2,3,4), value=c(1,2,3,-4,-5,6)) 
> a 
    id value 
1 1  1 
2 1  2 
3 2  3 
4 2 -4 
5 3 -5 
6 4  6 

voglio rimuovere i duplicati, mantenendo solo una voce per ID, quella con il valore assoluto più alto della colonna "valore". Io, questo è quello che voglio:

> a[c(2,4,5,6), ] 
    id value 
2 1  2 
4 2 -4 
5 3 -5 
6 4  6 

Come posso fare questo in R?

+1

Lei parla di "* mantenendo solo una voce per ID - quella che ha il più grande valore assoluto del 'valore' colonna. * "Qual è il comportamento desiderato se più di una voce per ID corrisponde a tale condizione? Restituire entrambi i valori o uno dei due? Ad esempio, qual è l'output desiderato se 'a [3, 2] <- 4'? – A5C1D2H2I1M1N2O1R2T1

+0

Ah .. questa è una buona domanda. La colonna del valore è un numero reale reale non un intero e molto probabilmente non sarà mai esattamente uguale. Il comportamento ideale desiderato dovrebbe probabilmente essere quello di scartare entrambe le osservazioni, ma probabilmente non succederà come ho detto. –

+0

Grazie a tutti per l'aiuto. –

risposta

26
aa <- a[order(a$id, -abs(a$value)), ] #sort by id and reverse of abs(value) 
aa[ !duplicated(aa$id), ]    # take the first row within each id 
    id value 
2 1  2 
4 2 -4 
5 3 -5 
6 4  6 
8

Partenza ?aggregate:

aggregate(value~id,a,function(x) x[which.max(abs(x))]) 

mi piace la risposta @DWin, ma vorrei mostrare come questo potrebbe funzionare anche con i metadati:

aa<-merge(aggregate(value~id,a,function(x) x[which.max(abs(x))]),a) 
# Fails if the max value is duplicated for a single id without next line. 
aa[!duplicated(aa),] 

I non ho potuto aiutare me stesso e ha creato un'ultima risposta:

do.call(rbind,lapply(split(a,a$id),function(x) x[which.max(abs(x$value)),])) 
+0

Grazie. Ho cambiato il codice. – nograpes

+0

Funziona bene come da mia descrizione, ma avrei dovuto essere più informativo. C'è in realtà un singolo ID e molte altre colonne di metadati che sono le stesse per ogni ID e molte altre colonne di valori per ciascun ID. Voglio mantenere tutte le colonne nel frame di dati, non solo l'id e il valore. –

3
library(plyr) 
ddply(a, .(id), function(x) return(x[which(abs(x$value)==max(abs(x$value))),])) 
+0

plyr è terribilmente lento – chupvl

9

Un approccio data.table potrebbe essere in ordine, se il set di dati è molto grande:

library(data.table) 

aDT <- as.data.table(a) 
setkey(aDT,"id") 

aDT[J(unique(id)), list(value = value[which.max(abs(value))])] 


O un non così rapidamente, ma ancora veloce, alternativa:

library(data.table) 
as.data.table(a)[, .SD[which.max(abs(value))], by=id] 

Questa versione restituisce tutte le colonne di a, nel caso in cui ci siano più in t lui set di dati reale.

5

Un altro approccio (anche se il codice potrebbe essere un po 'ingombrante) è quello di utilizzare ave():

a[which(abs(a$value) == ave(a$value, a$id, 
          FUN=function(x) max(abs(x)))), ] 
# id value 
# 2 1  2 
# 4 2 -4 
# 5 3 -5 
# 6 4  6 
+0

+1 per 'ave', ... la mia funzione preferita. –

+0

@DWin, ["L'ho imparato osservandoti!"] (Http://www.youtube.com/watch?v=Y-Elr5K2Vuo). ;) – A5C1D2H2I1M1N2O1R2T1

+0

Heh. Non dal mio contesto culturale, ma i out di Scrubs che ho avuto dopo la clip di "brain on drugs" su youtube sono stati curiosamente divertenti. –

Problemi correlati