111 votes

Sélectionnez la première ligne par groupe

À partir d'un cadre de données comme celui-ci

test <- data.frame('id'= rep(1:5,2), 'string'= LETTERS[1:10])
test <- test[order(test$id), ]
rownames(test) <- 1:10

> test
    id string
 1   1      A
 2   1      F
 3   2      B
 4   2      G
 5   3      C
 6   3      H
 7   4      D
 8   4      I
 9   5      E
 10  5      J

Je veux en créer un nouveau avec la première ligne de chaque paire id/chaîne. Si sqldf acceptait du code R en son sein, la requête pourrait ressembler à ceci :

res <- sqldf("select id, min(rownames(test)), string 
              from test 
              group by id, string")

> res
    id string
 1   1      A
 3   2      B
 5   3      C
 7   4      D
 9   5      E

Existe-t-il une solution autre que la création d'une nouvelle colonne telle que

test$row <- rownames(test)

et en exécutant la même requête sqldf avec min(row) ?

7voto

G. Grothendieck Points 40825

(1) SQLite possède une fonction intégrée de rowid pseudo-colonne pour que cela fonctionne :

sqldf("select min(rowid) rowid, id, string 
               from test 
               group by id")

donnant :

  rowid id string
1     1  1      A
2     3  2      B
3     5  3      C
4     7  4      D
5     9  5      E

(2) Aussi sqldf a lui-même un row.names= argument :

sqldf("select min(cast(row_names as real)) row_names, id, string 
              from test 
              group by id", row.names = TRUE)

donnant :

  id string
1  1      A
3  2      B
5  3      C
7  4      D
9  5      E

(3) Une troisième alternative qui mélange les éléments des deux précédentes pourrait être encore meilleure :

sqldf("select min(rowid) row_names, id, string 
               from test 
               group by id", row.names = TRUE)

donnant :

  id string
1  1      A
3  2      B
5  3      C
7  4      D
9  5      E

Notez que ces trois méthodes reposent sur une extension SQLite de SQL où l'utilisation de min o max a la garantie que les autres colonnes seront choisies dans la même rangée. (Dans d'autres bases de données basées sur SQL, cela peut ne pas être garanti).

5voto

Gavin Simpson Points 72349

Une option de base R est le split() - lapply() - do.call() idiome :

> do.call(rbind, lapply(split(test, test$id), head, 1))
  id string
1  1      A
2  2      B
3  3      C
4  4      D
5  5      E

Une option plus directe consiste à lapply() el [ fonction :

> do.call(rbind, lapply(split(test, test$id), `[`, 1, ))
  id string
1  1      A
2  2      B
3  3      C
4  4      D
5  5      E

La virgule-espace 1, ) à la fin de la lapply() L'appel est essentiel car cela équivaut à appeler [1, ] pour sélectionner la première ligne et toutes les colonnes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X