Расширяя рамка данных, выбрав одну строку на группу
Вопрос
Я пытаюсь свернуть кадр данных, удалив все, кроме одну строку из каждой группы строк с одинаковыми значениями в определенном столбце. Другими словами, первый ряд от каждой группы.
Например, я хотел бы преобразовать это
> 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 с тем же аргументом функций, что и здесь, но без них жалуется на дублирующие номера строк.
У меня есть возможность? Существует ли r идиома для преобразования вектора длины RLE в индексы строк, которые запускают каждый прогон, который я могу затем использовать, чтобы вырвать эти строки из кадра данных?
Решение
Может быть duplicated()
может помочь:
R> d[ !duplicated(d$x), ]
x y z
1 1 10 20
3 2 12 18
4 4 13 17
R>
Редактировать Шудки, не берите в голову. Это выбирает первый в каждом блоке повторений, вы хотели последнее. Так вот еще одна попытка использовать поспешность:
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>
Здесь поспешность Желая работа по нахождению уникальных подмножеств, зацикливающих их и применяя прилагаемую функцию - которая просто возвращает последний набор наблюдений в блоке z
с использованием tail(z, 1)
.
Другие советы
Просто добавить немного к тому, что предоставлено Дирку ... duplicated
имеет fromLast
Аргумент, который вы можете использовать для выбора последней строки:
d[ !duplicated(d$x,fromLast=TRUE), ]
Вот 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
Есть пара параметров, использующих 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)