2012-10-29 13 views
7

Mam ramki danych R:Compute liczenia zmienna w dataframe

a <- 1:12 
list <- c(rep("x",3),rep("y",4),rep("z",3),rep("x",2)) 
data <- data.frame(a,list) 

data 
a list 
1 x 
2 x 
3 x 
4 y 
5 y 
6 y 
7 y 
8 z 
9 z 
10 z 
11 x 
12 x 

Chcę utworzyć nową kolumnę, która rozpoczyna odliczanie od 1 za każdym razem wartość zmian „list”, czyli w tym przykładzie:

b <- c(1:3,1:4,1:3,1:2)  
data <- data.frame(a,list,b) 

Daleki jestem od bycia ekspertem od R i nie mogę dla mojego życia wypracować skutecznego sposobu robienia tego. Moim głównym problemem wydaje się być, że dowolna wartość "listy" może w każdej chwili wrócić, ale nie ma reguły na długość bloków jednej wartości. Czy ktoś ma jakieś pomysły? Dzięki!

+4

Wystarczy komentarz: często jest to dobry pomysł, aby nie używać nazw wbudowanych (jak 'data' lub' list') jako nazwy zmiennych - jeśli później będziesz chciał użyć funkcji 'list()', możesz napotkać bardzo dziwne błędy. –

+0

Rzeczywiście, większość ludzi powstrzymywałaby się od dzwonienia do swojego "psa"! na przykład. –

+0

Tak, masz rację. Będę o tym pamiętać od teraz. –

Odpowiedz

5

użyłbym rle() dostać długości przebiegu list a następnie użyć poręczny sequence() funkcję wygenerować żądany licznik z komponentu $lengths zwróconej przez rle():

R> sequence(rle(as.character(data$list))$lengths) 
[1] 1 2 3 1 2 3 4 1 2 3 1 2 

Zauważ, że musimy przekonwertować list na wektor atomowy (wektor znaków w moim przypadku), ponieważ czynnik nie jest dozwolony w rle().

Mówiąc, że w data, następnie owinąć to w rozmowie, takich jak

data <- transform(data, b = sequence(rle(as.character(list))$lengths)) 

co daje

R> data <- transform(data, b = sequence(rle(as.character(list))$lengths)) 
R> data 
    a list b 
1 1 x 1 
2 2 x 2 
3 3 x 3 
4 4 y 1 
5 5 y 2 
6 6 y 3 
7 7 y 4 
8 8 z 1 
9 9 z 2 
10 10 z 3 
11 11 x 1 
12 12 x 2 
+0

idealne, dziękuję! –

+0

@ user1777393 Jeśli jesteś zadowolony z odpowiedzi, rozważ zaakceptowanie jednego z nich. Użyj dużego znacznika obok odpowiedzi, którą chcesz zaakceptować. Sekcja [ask] w [tak] faq wyjaśnia, jak to zrobić i dlaczego jest to pomocne/użyteczne. –

+0

Dziękuję. Możesz zauważyć, że wcześniej tego nie robiłem. –

5

Kluczową ideą jest użycie rle() (kodowanie długości) na data$list (po przymuszeniu go do wektora atomowego - w końcu nie jesteśmy zainteresowani określonymi wpisami). Następnie używamy seq() do tworzenia sekwencji rozpoczynających się od 1 i kończących się na wyliczonej długości przebiegu. Wreszcie, wklej wszystkie te sekwencje razem:

unlist(lapply(rle(as.numeric(data$list))$lengths,FUN=seq,from=1)) 
+0

Dziękuję! Właśnie tego potrzebowałem. Nie znałem tej funkcji, więc bardzo mnie ucieszyłeś. –

+0

Nie ma za co. Lubię sprawiać ludziom radość! ;-) –

Powiązane problemy