2010-04-13 15 views
16

Próbuję zwinąć ramkę danych, usuwając wszystkie wiersze z wyjątkiem jednego z każdej grupy wierszy z identycznymi wartościami w określonej kolumnie. Innymi słowy, pierwszy wiersz z każdej grupy.Zwijanie ramki danych przez wybranie jednego wiersza na grupę

Na przykład chciałbym skonwertować ten

> 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 

Do tego:

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

Używam kruszywo to zrobić obecnie, ale wydajność jest nie do przyjęcia z większą ilością danych:

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

próbowałem split/niedwojonych z tym samym argumentem funkcji jak tutaj, ale niedwojonych narzeka abo ut duplikat numerów wierszy.

Czy istnieje możliwość? Czy istnieje idiom R do zamiany wektora długości rle na indeksy wierszy, które rozpoczynają każdy przebieg, które następnie mogę wykorzystać do zerwania tych wierszy z ramki danych?

Odpowiedz

25

Może duplicated() może pomóc:

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

Edit Shucks, nieważne. Ten wybiera pierwszy w każdym bloku powtórzeń, chciałeś ostatni. Więc tutaj jest kolejna próba korzystania 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> 

Tutaj plyr robi ciężka praca znalezienia unikalne podzbiory, zapętlenie nad nimi i stosując funkcję dostarczoną - które po prostu zwraca ostatni zbiór obserwacji w bloku z wykorzystaniem tail(z, 1) .

+0

wolałbym wszystkie kolumny, thanks – jkebinger

+0

Więc trzeba po prostu dodać „etap przetwarzania”, aby utworzyć zmienną czynnik, nad którym plyr możliwe, pętla. Można to zrobić za pomocą poleceń indeksujących, spróbuj. A tak przy okazji, jesteś niespójny między tekstem (mówiąc pierwszy wybrany wiersz) i przykładem (pokazując drugi wiersz). –

+0

Nawiasem mówiąc, cross-posting między r-help i tutaj jest również nieco kiepski styl. Masz dobre odpowiedzi w r-help, więc dlaczego ich nie studiujesz? –

12

Wystarczy dodać trochę do tego, co Dirk warunkiem ... duplicated ma fromLast argument, który można użyć, aby wybrać ostatni wiersz:

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

Cześć Ian - niestety James nigdy nie wyjaśnił, czy chce pierwszy, czy ostatni i zaprzecza sobie samemu w poście ... ale twoja podpowiedź z ostatniej jest dobra! –

+0

dzięki, że działa jak urok. Niezależnie od tego, czy pierwszy, czy ostatni, którego potrzebowałem, był naprawdę zależny od zamawiania, i ze wszystkim mogłem zaatakować to tak czy inaczej, – jkebinger

+0

Zasugerowałem to samo i zastrzeliłeś to na podstawie "preferuj wszystkie kolumny". Dlaczego to już nie ma znaczenia? –

10

Oto data.table rozwiązanie, które będzie czas i pamięć wydajny dla dużych zbiorów danych

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

Ale jeśli _all_, który jest potrzebny, to ostatni wiersz w każdej grupie, to 'DT [! Zduplikowany (x, fromLast = TRUE)] jest prawdopodobnie szybszy niż całkowity czas 'setkey' + join, i z pewną przewagą cukru syntaktycznego unikając powtarzania nazwy zmiennej' DT' (tj. po prostu 'x', a nie' DT $ x'). –

+0

Użycie indeksu wiersza przyspieszyłoby rzeczy i geuss, DT [DT [, .I [. N], o = x] $ V1]. Sprawdź http://stackoverflow.com/questions/19424762/efficiently-selecting-top-number-of-rows-for-each-unique-value-of-a-column-in-a. Dzięki @ Simono101 – Freddy

+2

'unique (DT, by =" x ", fromLast = TRUE)' jest teraz prostsze i szybsze niż 'DT [! Duplikowane (x, fromLast = TRUE)]' i 'DT [J (unique (x)), mult = "last"] " – Matthew

Powiązane problemy