2012-10-09 26 views
18

Digamos que tengo cuatro muestras: id = 1, 2, 3 y 4, con una o más mediciones en cada una de las muestras:eliminar duplicados de mantenimiento de la entrada con el valor absoluto más grande

> 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 

Quiero eliminar duplicados, manteniendo solo una entrada por ID, la que tiene el mayor valor absoluto de la columna "valor". Es decir, esto es lo que quiero:

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

¿Cómo puedo hacer esto en R?

+1

Usted menciona "* manteniendo sólo una entrada por la identificación - el que tiene el mayor valor absoluto del 'valor' columna. * "¿Cuál es el comportamiento deseado si más de una entrada por ID coincide con esa condición? ¿Devuelve ambos valores o uno? Por ejemplo, ¿cuál es tu salida deseada si 'a [3, 2] <- 4'? – A5C1D2H2I1M1N2O1R2T1

+0

Ah ... esa es una buena pregunta. La columna de valor es un número realmente real, no un número entero, y muy probablemente nunca será exactamente igual. El comportamiento ideal deseado debería ser descartar ambas observaciones, pero probablemente esto no sucederá como dije. –

+0

Gracias a todos por la ayuda. –

Respuesta

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

Salida ?aggregate:

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

me gusta la respuesta por @DWin, pero me gustaría mostrar cómo este también podría trabajar con metadatos:

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 no pude evitarlo y creó una última respuesta:

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

Gracias. Cambié el código. – nograpes

+0

Esto funciona bien según mi descripción, pero debería haber sido más informativo. En realidad, hay una única ID y muchas otras columnas de metadatos que son las mismas para cada ID, y muchas otras columnas de valor para cada ID. Quiero mantener todas las columnas en el marco de datos, no solo el ID y el valor. –

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

plyr es terriblemente lento – chupvl

9

Un enfoque data.table podría estar en orden si el conjunto de datos es muy 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 no tan rápido, pero sigue siendo rápido, alternativa:

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

Esta versión devuelve todas las columnas de a, en caso de que haya más en t El conjunto de datos real.

5

Otro enfoque (aunque el código podría ser un poco engorroso) es utilizar 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 para 'ave', ... mi función favorita. –

+0

@DWin, ["¡Lo aprendí observándote!"] (Http://www.youtube.com/watch?v=Y-Elr5K2Vuo). ;) – A5C1D2H2I1M1N2O1R2T1

+0

Heh. No desde mi marco cultural, pero las tomas de Scrubs que obtuve después del clip "brain on drugs" en youtube fueron curiosamente divertidas. –

Cuestiones relacionadas