Como faço para remover todos os registros duplicados, exceto um específico, em um quadro de dados R? [fechadas]

16

Eu tenho um quadro de dados que contém alguns IDs duplicados. Quero remover registros com IDs duplicados, mantendo apenas a linha com o valor máximo.

Portanto, para estruturado como este (outras variáveis ​​não mostradas):

id var_1
1 2
1 4
2 1
2 3
3 5
4 2

Eu quero gerar isso:

id var_1
1 4
2 3
3 5
4 2

Eu sei sobre unique () e duplicated (), mas não consigo descobrir como incorporar a regra de maximização ...

Abe
fonte
Ele deve realmente estar em stackoverflow, pois é uma tarefa relacionada puramente programação e tem pouco a ver com estatísticas
Enthusiast

Respostas:

24

Uma maneira é ordenar reversamente os dados e usá duplicated-los para eliminar todas as duplicatas. Para mim, esse método é conceitualmente mais simples do que aqueles que se aplicam. Eu acho que deveria ser muito rápido também.

# Some data to start with:
z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
# id var
#  1   2
#  1   4
#  2   1
#  2   3
#  3   5
#  4   2

# Reverse sort
z <- z[order(z$id, z$var, decreasing=TRUE),]
# id var
#  4   2
#  3   5
#  2   3
#  2   1
#  1   4
#  1   2

# Keep only the first row for each duplicate of z$id; this row will have the
# largest value for z$var
z <- z[!duplicated(z$id),]

# Sort so it looks nice
z <- z[order(z$id, z$var),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

Edit: Acabei de perceber que a ordem inversa acima nem precisa ser ordenada id. Você pode simplesmente usar z[order(z$var, decreasing=TRUE),]e ele também funcionará.

Mais um pensamento ... Se a varcoluna for numérica, existe uma maneira simples de classificar, de modo que idesteja subindo, mas vardescendo. Isso elimina a necessidade da classificação no final (supondo que você queira que ela seja classificada).

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))

# Sort: id ascending, var descending
z <- z[order(z$id, -z$var),]

# Remove duplicates
z <- z[!duplicated(z$id),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2
wch
fonte
1
Essa abordagem é significativamente mais rápida que "split-computate-rbind". Além disso, permite agrupar mais de um fator. Para um c. 650.000 linhas (8, estreitas, colunas), a abordagem "duplicada por ordem" levou 55 segundos, a divisão de computação dividida ... 1h15minutos. É claro que quando a computação agregada é diferente de selecionar ou filtrar duplicatas, a última abordagem ou abordagens semelhantes baseadas em plyr são necessárias.
mjv
7

Você realmente deseja selecionar o elemento máximo dos elementos com o mesmo ID. Para isso, você pode usar o ddplypacote plyr :

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
> ddply(dt,.(id),summarise,var_1=max(var))
   id var_1
1  1   4
2  2   3
3  3   4
4  4   2

uniquee duplicatedé para remover registros duplicados; no seu caso, você tem apenas IDs duplicados, não registros.

Atualização: Aqui está o código quando existem variáveis ​​adicionais:

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2),bu=rnorm(6))
> ddply(dt,~id,function(d)d[which.max(d$var),])
mpiktas
fonte
E se houvesse outras variáveis: como você as carrega?
Aniko 24/05
Nós não movemos essas perguntas - muita pressa para pouquíssimo ganho.
6

A solução base-R envolveria split, assim:

z<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
do.call(rbind,lapply(split(z,z$id),function(chunk) chunk[which.max(chunk$var),]))

splitdivide o quadro de dados em uma lista de blocos, na qual executamos o corte na única linha com valor máximo e do.call(rbind,...)reduz a lista de linhas únicas em um quadro de dados novamente.


fonte
1
E, como de costume, isso é cerca de 2x mais rápido que a versão plyr.
1
@mbq, sim, naturalmente, mas se você incluir os custos de depuração, para conjuntos de dados comuns, a velocidade resultante é a mesma :) plyr é dedicado não à velocidade, mas à clareza e conveniência.
mpiktas
e usando av é duas vezes mais rápido de qualquer maneira :)
Eduardo Leoni
2
@Eduardo aveé um invólucro de lapply+ split, verificar o código de (-;
1
@ Eduardo Sim, mas tudo funciona apenas devido a uma possibilidade peculiar de classificação vetorial dentro de fatores usando order; para problemas mais genéricos splité inevitável.
5

Eu prefiro usar ave

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,3,3,4,2))
## use unique if you want to exclude duplicate maxima
unique(subset(dt, var==ave(var, id, FUN=max)))
Eduardo Leoni
fonte
+1, não sabia sobre a ave. Quando ele apareceu em R?
mpiktas 25/05
1

Ainda outra maneira de fazer isso com base:

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))

data.frame(id=sort(unique(dt$var)),max=tapply(dt$var,dt$id,max))
  id max
1  1   4
2  2   3
3  3   4
4  4   2

Eu prefiro a solução plyr dos mpiktas.

Sacha Epskamp
fonte
1

Se, como no exemplo, a coluna var já estiver em ordem crescente, não precisaremos classificar o quadro de dados. Nós apenas usamos a função que duplicatedpassa o argumento fromLast = TRUE, portanto, a duplicação é considerada do lado oposto, mantendo os últimos elementos:

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
z[!duplicated(z$id, fromLast = TRUE), ]

  id var
2  1   4
4  2   3
5  3   5
6  4   2

Caso contrário, classificaremos o quadro de dados em ordem crescente primeiro:

z <- z[order(z$id, z$var), ]
z[!duplicated(z$id, fromLast = TRUE), ]

Usando o dplyrpacote:

library(dplyr)
z %>%
  group_by(id) %>%
  summarise(var = max(var))

Source: local data frame [4 x 2]    
  id var
1  1   4
2  2   3
3  3   5
4  4   2
mpalanco
fonte