2012-10-09 16 views
18

Lassen Sie uns sagen, dass ich vier Proben haben: id = 1, 2, 3 und 4, mit einem oder mehreren Messungen an jeder dieser Proben:Duplikate entfernen Eintrag mit dem größten absoluten Wert zu halten

> 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 

Ich möchte Entfernen von Duplikaten, wobei nur eine Eingabe pro ID gespeichert wird - diejenige mit dem größten absoluten Wert der Spalte "value". Das heißt, was ich will:

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

Wie kann ich das in R tun?

+1

Sie erwähnen „* nur ein Eintrag pro ID zu halten - die eine der größten absoluten Wert der‚Wert‘mit Spalte. * "Was ist das gewünschte Verhalten, wenn mehr als ein Eintrag pro ID diese Bedingung erfüllt? Geben Sie beide Werte oder beide Werte zurück? Zum Beispiel, was ist Ihre gewünschte Ausgabe, wenn 'a [3, 2] <- 4'? – A5C1D2H2I1M1N2O1R2T1

+0

Ah .. das ist eine gute Frage. Die Wertespalte ist eine tatsächlich reelle Zahl, keine Ganzzahl und wird wahrscheinlich nie genau gleich sein. Ideales erwünschtes Verhalten sollte wahrscheinlich sein, beide Beobachtungen zu verwerfen, aber das wird wahrscheinlich nicht passieren, wie ich sagte. –

+0

Danke allen für die Hilfe. –

Antwort

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

Check out ?aggregate:

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

Ich mag die Antwort von @DWin, aber ich möchte zeigen, wie dies auch mit Metadaten arbeiten könnten:

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 konnte mir nicht helfen und erstellte eine letzte antwort:

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

Danke. Ich habe den Code geändert. – nograpes

+0

Das funktioniert gut gemäß meiner Beschreibung, aber ich hätte mehr informativ sein sollen. Es gibt tatsächlich eine einzelne ID und viele andere Metadatenspalten, die für jede ID identisch sind, und viele andere Wertespalten für jede ID. Ich möchte alle Spalten im Datenrahmen behalten, nicht nur die eine ID und den Wert. –

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

plyr ist schrecklich langsam – chupvl

9

Ein data.table Ansatz könnte sein, um, wenn Ihr Datensatz ist sehr groß:

library(data.table) 

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

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


Oder eine nicht ganz so schnell, aber immer noch schnell, Alternative:

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

Diese Version gibt alle Spalten von a zurück, falls es mehr in t gibt Der echte Datensatz.

5

Ein anderer Ansatz (obwohl der Code ein wenig umständlich aussehen könnte) ist ave() zu verwenden:

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 für 'ave', ... meine Lieblingsfunktion. –

+0

@DWin, ["Ich habe es gelernt, indem ich dich beobachtete!"] (Http://www.youtube.com/watch?v=Y-Elr5K2Vuo). ;) – A5C1D2H2I1M1N2O1R2T1

+0

Heh. Nicht aus meinem kulturellen Rahmen, aber die Scrubs-Outtakes, die ich bekam, nachdem der Clip "brain on drugs" auf youtube seltsam amüsant war. –

Verwandte Themen