Recolhendo o quadro de dados selecionando uma linha por grupo

Eu estou tentando recolher um quadro de dados, removendo todos, mas uma linha de cada grupo de linhas com valores idênticos em uma coluna específica. Em outras palavras, a primeira linha de cada grupo.

Por exemplo, eu gostaria de converter isso

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

Nisso:

  xyz 1 1 11 19 2 2 12 18 3 4 13 17 

Estou usando agregado para fazer isso atualmente, mas o desempenho é inaceitável com mais dados:

 > d.ordered = d[order(-d$y),] > aggregate(d.ordered,by=list(key=d.ordered$x),FUN=function(x){x[1]}) 

Eu tentei dividir / descompactar com o mesmo argumento de function que aqui, mas desmembrar reclama sobre números de linha duplicados.

É uma possibilidade? Existe um idioma R para converter vetores de comprimento de rle nos índices das linhas que iniciam cada execução, que eu posso usar para extrair essas linhas do quadro de dados?

Talvez duplicated() possa ajudar:

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

Edite Shucks, não importa. Isso escolhe o primeiro em cada bloco de repetições, você queria o último. Então aqui está outra tentativa usando plyr :

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

Aqui plyr faz o trabalho duro de encontrar subconjuntos únicos, passando por cima deles e aplicando a function fornecida – que simplesmente retorna o último conjunto de observações em um bloco z usando tail(z, 1) .

Apenas para adicionar um pouco ao que o Dirk forneceu … duplicated tem um argumento fromLast que você pode usar para selecionar a última linha:

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

Aqui está uma solução data.table que será eficiente em termos de tempo e memory para grandes conjuntos de dados

 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