Свертывание фрейма данных путем выбора одной строки на группу - PullRequest
17 голосов
/ 13 апреля 2010

Я пытаюсь свернуть фрейм данных, удалив все строки, кроме одной, из каждой группы строк с одинаковыми значениями в определенном столбце. Другими словами, первый ряд от каждой группы.

Например, я хотел бы преобразовать это

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

В это:

    x  y  z
1   1 11 19
2   2 12 18
3   4 13 17

Я использую агрегат, чтобы сделать это в настоящее время, но производительность недопустима с большим количеством данных:

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

Я пробовал split / unsplit с тем же аргументом функции, что и здесь, но unsplit жалуется на повторяющиеся номера строк.

Есть ли возможность? Существует ли R-идиома для преобразования вектора длины rle в индексы строк, начинающих каждый прогон, который я затем могу использовать для извлечения этих строк из фрейма данных?

Ответы [ 4 ]

27 голосов
/ 13 апреля 2010

Может быть duplicated() может помочь:

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

Редактировать Черт, неважно. Это выбирает первое в каждом блоке повторений, вы хотели последний. Итак, вот еще одна попытка использования plyr :

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

Здесь plyr выполняет тяжелую работу по поиску уникальных подмножеств, их циклированию и применению предоставленной функции, которая просто возвращает последний набор наблюдений в блоке z с использованием tail(z, 1).

12 голосов
/ 13 апреля 2010

Просто добавьте немного к тому, что предоставил Дирк ... duplicated имеет аргумент fromLast, который можно использовать для выбора последней строки:

d[ !duplicated(d$x,fromLast=TRUE), ]
11 голосов
/ 19 сентября 2012

Вот решение data.table, которое экономит время и память для больших наборов данных

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
0 голосов
/ 20 марта 2019

Существует несколько вариантов использования dplyr:

library(dplyr)
df %>% distinct(x, .keep_all = TRUE)
df %>% group_by(x) %>% filter(row_number() == 1)
df %>% group_by(x) %>% slice(1)

Вы можете использовать более одного столбца с distinct() и group_by():

df %>% distinct(x, y, .keep_all = TRUE)

Подход group_by() и filter() может быть полезен при наличии даты или какого-либо другого последовательного поля и вы хотите убедиться, что последнее наблюдение сохранено, и slice() полезно, если вы хотите избежать связей:

df %>% group_by(x) %>% filter(date == max(date)) %>% slice(1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...