2015-02-10 38 views
5

Mam ramki danych, który wygląda jak następuje:grupowanie, porównywanie i liczenie wierszy w r

 system Id initial final 
665  9 16001 6070 6071 
683  10 16001 6100 6101 
696  11 16001 6101 6113 
712  10 16971 6150 6151 
715  11 16971 6151 6163 
4966  7 4118 10238 10242 
5031  9 4118 10260 10278 
5088  10 4118 10279 10304 
5115  11 4118 10305 10317 


structure(list(system = c(9L, 10L, 11L, 10L, 11L, 7L, 9L, 10L, 
11L), Id = c(16001L, 16001L, 16001L, 16971L, 16971L, 4118L, 4118L, 
4118L, 4118L), initial = c(6070, 6100, 6101, 6150, 6151, 10238, 
10260, 10279, 10305), final = c(6071, 6101, 6113, 6151, 6163, 
10242, 10278, 10304, 10317)), .Names = c("system", "Id", "initial", 
"final"), row.names = c(665L, 683L, 696L, 712L, 715L, 4966L, 
5031L, 5088L, 5115L), class = "data.frame") 

chciałbym uzyskać nową ramkę danych z kolejnej struktury

 Id system length initial final 
1 16001 9,10,11  3 6070 6113 
2 16971 10,11  2 6150 6163 
3 4118  7  1 10238 10242 
4 4118 9,10,11  3 10260 10317 


structure(list(Id = c(16001L, 16971L, 4118L, 4118L), system =  structure(c(3L, 
1L, 2L, 3L), .Label = c("10,11", "7", "9,10,11"), class =  "factor"), 
    length = c(3L, 2L, 1L, 3L), initial = c(6070L, 6150L, 10238L, 
    10260L), final = c(6113, 6163, 10242, 10317)), .Names = c("Id", 
"system", "length", "initial", "final"), class = "data.frame",  row.names = c(NA, 
-4L)) 

Grupowanie odbywa się według Id, a różnica (między wierszami) w polu "system" jest równa jedności. Chciałbym również uzyskać inny "system" i ile z tego jest zaangażowanych w grupowanie. W końcu także kolumna z pierwszym "początkowym" i ostatnim "końcem".

Jest to możliwe w r? Dzięki.

Odpowiedz

3

Można użyć data.table. Konwertuj "data.frame" na "data.table" (setDT), utwórz zmienną grupującą "indx", biorąc różnicę sąsiednich elementów "systemu" (diff(system)), cumsum w wektor logiczny, użyj "Id" i "indx" "jako zmienną grupującą, aby uzyskać statystyki.

library(data.table) 
setDT(df)[,list(system=toString(system), length=.N, initial=initial[1L], 
    final=final[.N]), by=list(Id,indx=cumsum(c(TRUE, diff(system)!=1)))][, 
    indx:=NULL][] 

#  Id system length initial final 
#1: 16001 9, 10, 11  3 6070 6113 
#2: 16971 10, 11  2 6150 6163 
#3: 4118   7  1 10238 10242 
#4: 4118 9, 10, 11  3 10260 10317 

lub w oparciu o użytkownika @ jazzurro komentarzu na temat korzystania first/last funkcji z dplyr,

library(dplyr) 
df %>% 
    group_by(indx=cumsum(c(TRUE, diff(system)!=1)), Id) %>% 
    summarise(system=toString(system), length=n(), 
    initial=first(initial), final=last(final)) 
+1

Czy używając 'pierwszy()' i ' last() 'być inną opcją tutaj? 'first()' pochodzi jednak z dplyr. – jazzurro

+0

@jazzurro Myślę, że to działa. Możesz opublikować to jako rozwiązanie dplyr. – akrun

+0

Nadal zastanawiam się, czy dobrze jest używać niektórych funkcji z 'dplyr' w' data.table'. Rozwiązanie 'dplyr' będzie po prostu tłumaczeniem twojego kodu. Jeśli z przyjemnością napiszesz, proszę śmiało. Zostawię to tobie. :) – jazzurro

1

Rozwiązanie bez data.table, ale plyr:

library(plyr) 

func = function(subdf) 
{ 
    bool = c(diff(subdf$system),1)==1 
    ldply(split(subdf, bool), function(u){ 
     data.frame(system = paste(u$system, collapse=','), 
        Id  = unique(u$Id), 
        length = nrow(u), 
        initial= head(u,1)$initial, 
        final = tail(u,1)$final) 
    }) 
} 


ldply(split(df, df$Id), func) 

# .id system length Id initial final 
#1 FALSE  7  1 4118 10238 10242 
#2 TRUE 9,10,11  3 4118 10260 10317 
#3 TRUE 9,10,11  3 16001 6070 6113 
#4 TRUE 10,11  2 16971 6150 6163