2015-02-10 38 views
5

Ich habe einen Datenrahmen, der wie folgt aussieht:Gruppierung, Vergleichen und Zählen Zeilen 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") 

Ich möchte einen neuen Datenrahmen mit der nächsten Struktur

 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)) 

erhalten Die Gruppierung erfolgt nach Id und die Differenz (zwischen den Zeilen) im "System" -Feld gleich eins. Auch ich möchte das unterschiedliche "System" und wie viel davon in der Gruppierung beteiligt bekommen. Abschließend noch eine Spalte mit dem ersten "Initial" und dem letzten "Final".

Es ist möglich, das in r zu tun? Danke.

Antwort

3

Sie könnten data.table verwenden. Konvertieren Sie "data.frame" in "data.table" (setDT), erstellen Sie eine Gruppierungsvariable "indx", indem Sie die Differenz benachbarter Elemente von "system" (diff(system)), cumsum den logischen Vektor verwenden, verwenden Sie "Id" und "indx "als Gruppierungsvariable, um die Statistiken zu erhalten.

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 

Oder basierend auf @ Kommentar des jazzurro über first/last Funktionen von dplyr, mit

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

mit Can 'first()' und ' last() 'sei eine andere Option hier? 'first()' kommt von dplyr. – jazzurro

+0

@jazzurro Ich denke, es funktioniert. Sie könnten das als dplyr-Lösung posten. – akrun

+0

Ich frage mich immer noch, ob es gut ist, einige Funktionen von 'dplyr' in' data.table' zu ​​verwenden. Die 'dplyr' Lösung wird nur eine Übersetzung Ihres Codes sein. Wenn Sie glücklich sind, einen zu schreiben, gehen Sie bitte voran. Ich überlasse es dir. :) – jazzurro

1

Eine Lösung ohne data.table, aber 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