2013-03-19 2 views
2

У меня есть dataframe, содержащий строки данных с именем столбца FirmID и DEF. Столбцы DEF содержат только нули. Столбец FirmID содержит идентификатор фирмы. Я хочу иметь последние 2 наблюдения для данного FirmID. Столбец DEF равен нулю.Извлечь последние 2 строки в каждой группе

FirmID LTQ DLCQ DEF 
1004 0.45 0.21 0 
1004 0.32 0.43 0 
1004 0.36 0.47 0 
1004 0.25 0.67 0 
1004 0.56 0.34 0 
1021 0.12 0.39 0 
1021 0.16 0.31 0 
1021 0.24 0.76 0 
1021 0.37 0.56 0 
1035 0.89 0.78 0 
...  . . . 
...  . . . 

Итак, как получить только последние 2 строки для заданной FirmID

1004 . . 0 
1004 . . 0 
1021 . . 0 
1021 . . 0 
1035 . . 0 
1035 . . 0 
+1

поскольку значения являются идентичными, * почему это имеет значение, если это верх или низ 2 *? Вы можете просто взять 'уникальный' свой data.frame, а затем' rbind' его с собой один раз ... – Arun

+0

+1 @Arun. Поставьте реалистичный пример или вы получите решение, которое может не удовлетворить вашу * актуальную * потребность. Или, если этот пример * * реалистичен, тогда у Аруна есть ваше решение. – ndoogan

+0

спасибо Арун, хорошая точка. У меня, конечно, несколько строк, и на самом деле это данные, которые мне нужны для последних двух строк, в частности. – Maximilian

ответ

4

Suposing вам данные называют DF:

lasttwo <- do.call(rbind,by(DF,DF$FirmID,tail,2)) 
+0

спасибо за быстрый и правильный ответ! – Maximilian

3

База-R способ сделать это вручную сделайте танцы split-apply-combination. Использование данных:

dat <- read.table(text = "FirmID LTQ DLCQ DEF 
1004 0.45 0.21 0 
1004 0.32 0.43 0 
1004 0.36 0.47 0 
1004 0.25 0.67 0 
1004 0.56 0.34 0 
1021 0.12 0.39 0 
1021 0.16 0.31 0 
1021 0.24 0.76 0 
1021 0.37 0.56 0 
1035 0.89 0.78 0", header = TRUE) 

Мы

  1. разделить данные на FirmID: split(dat, dat$FirmID). Это возвращает список, который мы
  2. lapply над, применяя функцию tail вернуться в большинстве последних 2-х линий, результатом этого является списком, компонентами которого являются результаты tail, которые мы тогда
  3. объединить обратно в с использованием do.call и rbind.

Весь вызов может быть нанизанные в одну строку:

do.call("rbind", lapply(split(dat, dat$FirmID), tail, 2)) 

, который дает:

> (out <- do.call("rbind", lapply(split(dat, dat$FirmID), tail, 2))) 
     FirmID LTQ DLCQ DEF 
1004.4 1004 0.25 0.67 0 
1004.5 1004 0.56 0.34 0 
1021.8 1021 0.24 0.76 0 
1021.9 1021 0.37 0.56 0 
1035  1035 0.89 0.78 0 

Если вам не нравятся эти противные имена строк, просто удалите их:

> rownames(out) <- NULL 
> out 
    FirmID LTQ DLCQ DEF 
1 1004 0.25 0.67 0 
2 1004 0.56 0.34 0 
3 1021 0.24 0.76 0 
4 1021 0.37 0.56 0 
5 1035 0.89 0.78 0 
+0

Обновлен в соответствии с примером новых данных OP. –

+0

спасибо, Gavin. Конечно, ваш ответ более приятный и правильный, но я дал согласие на Rcoster, так как он правильно ответил примерно 2 мин раньше. Большое спасибо! – Maximilian

7

Вы можете использовать пакет data.table следующим образом (при условии, что вы начинаете с data.frame названием «mydf»):

> library(data.table) 
> DT <- data.table(mydf, key="FirmID") 
> DT[, tail(.SD, 2), by = key(DT)] 
    FirmID LTQ DLCQ DEF 
1: 1004 0.25 0.67 0 
2: 1004 0.56 0.34 0 
3: 1021 0.24 0.76 0 
4: 1021 0.37 0.56 0 
5: 1035 0.89 0.78 0 

Очевидно, что изменение «2» на количество строк вы на самом деле хотите (есть противоречие в названии вашего вопроса и его текст).


Другой вариант заключается в использовании plyr аналогичным образом:

> library(plyr) 
> ddply(mydf, .(FirmID), tail, 2) 
    FirmID LTQ DLCQ DEF 
1 1004 0.25 0.67 0 
2 1004 0.56 0.34 0 
3 1021 0.24 0.76 0 
4 1021 0.37 0.56 0 
5 1035 0.89 0.78 0 

И, одна необычная альтернатива с использованием базовой Р:

temp <- within(mydf, { 
    ID <- ave(FirmID, FirmID, FUN = function(x) rev(seq_along(x))) 
}) 

temp[temp$ID %in% c(1, 2), 1:4] 
Смежные вопросы