2016-06-16 10 views
3

Ich möchte eine Zählerspalte in einem Datenrahmen basierend auf einer Reihe von identischen Zeilen hinzufügen. Um dies zu tun, habe ich das Paket data.table verwendet. In meinem Fall muss der Vergleich zwischen den Zeilen aus der Kombination der Spalten "z" UND ("x" ODER "y") erfolgen.data.table: "Gruppenzähler" für eine bestimmte Kombination von Spalten

I getestet:

DF[ , Index := .GRP, by = c("x","y","z") ] 

aber das Ergebnis ist die Kombination der "z" und "x" und "y".

Wie kann ich die Kombination von "z" UND ("x" ODER "y") haben?

Hier ist ein Datenbeispiel:

DF = data.frame(x=c("a","a","a","b","c","d","e","f","f"), y=c(1,3,2,8,8,4,4,6,0), z=c("M","M","M","F","F","M","M","F","F")) 
DF <- data.table(DF) 

Ich möchte diese Ausgabe haben:

> DF 
    x y z Index 
1: a 1 M 1 
2: a 3 M 1 
3: a 2 M 1 
4: b 8 F 2 
5: c 8 F 2 
6: d 4 M 3 
7: e 4 M 3 
8: f 6 F 4 
9: f 0 F 4 
+2

FYI, Sie können Ihren Datensatz mit 'data.table' erstellen, ohne' data.frame' zu ​​verwenden. Oder wandeln Sie alternativ Ihre 'data.frame' in eine' data.table' ohne Kopien mit 'setDT' um. Außerdem sollte die gewünschte Ausgabe für Fälle wie "data.table" (x = c ("a", "a", "a"), y = c (1, 1, 2), z = c (" M "," F "," F "))"? –

+1

Für Ihr Beispiel wird 'DF [, Index: = rleid (z)]' funktionieren, aber es berücksichtigt nur "Z" und nicht ("x" ODER "y"). – lmo

+3

Ok, und die Ausgabe für 'data.table (x = c (" b "," a "," a "), y = c (1, 1, 2), z = c (" F "," F "," F "))"? –

Antwort

6

Die neue Gruppe beginnt, wenn der Wert für z ist oder für Ändern der Werte sowohl xundy ändern sich.

Versuchen Sie dieses Beispiel.

require(data.table) 

DF <- data.table(x = c("a","a","a","b","c","d","e","f","f"), 
       y = c(1,3,2,8,8,4,4,6,0), 
       z=c("M","M","M","F","F","M","M","F","F")) 

# The functions to compare if value is not equal with the previous value 
is.not.eq.with.lag <- function(x) c(T, tail(x, -1) != head(x, -1)) 

DF[, x1 := is.not.eq.with.lag(x)] 
DF[, y1 := is.not.eq.with.lag(y)] 
DF[, z1 := is.not.eq.with.lag(z)] 
DF 

DF[, Index := cumsum(z1 | (x1 & y1))] 
DF 
+0

IIUC, wird dies funktionieren:' pmin (rleid (dt $ x, dt $ y), rleid (dt $ z)) '? – Arun

+0

@Arun Ich denke, das wird nicht für Zeiten funktionieren, wenn es nur ein Muster in 'z' gibt, aber keine Muster in' x' oder 'y', wie' DF <- data.table (x = c (" f "," r "), y = c (6, 0), z = c (" F "," F ")) –

+0

@Arun scheint zu funktionieren. – djhurio

0

weiß, dass ich eine Menge Leute warnen vor einer for Schleife in R, aber in diesem Fall halte ich es für eine sehr direkte Art und Weise ist, das Problem zu nähern. Außerdem wächst das Ergebnis nicht, daher sind Leistungsprobleme kein großes Problem. Der for Schleife Ansatz wäre:

dt$grp <- rep(NA,nrow(dt)) 
    for (i in 1:nrow(dt)){ 
     if (i == 1){ 
      dt$grp[i] = 1 
     } 
     else { 
      if(dt$z[i-1] == dt$z[i] & (dt$x[i-1] == dt$x[i] | dt$y[i-1] == dt$y[i])){ 
      dt$grp[i] = dt$grp[i-1] 
      }else{ 
      dt$grp[i] = dt$grp[i-1] + 1 
      } 
     } 
    } 

Der Versuch, dies auf OPs ursprüngliches Problem, das Ergebnis ist:

DF = data.frame(x=c("a","a","a","b","c","d","e","f","f"), y=c(1,3,2,8,8,4,4,6,0), z=c("M","M","M","F","F","M","M","F","F")) 
dt <- data.table(DF) 
dt$grp <- rep(NA,nrow(dt)) 
for (i in 1:nrow(dt)){ 
    if (i == 1){ 
     dt$grp[i] = 1 
    } 
    else { 
     if(dt$z[i-1] == dt$z[i] & (dt$x[i-1] == dt$x[i] | dt$y[i-1] == dt$y[i])){ 
     dt$grp[i] = dt$grp[i-1] 
     }else{ 
     dt$grp[i] = dt$grp[i-1] + 1 
     } 
    } 
} 
dt 

    x y z grp 
1: a 1 M 1 
2: a 3 M 1 
3: a 2 M 1 
4: b 8 F 2 
5: c 8 F 2 
6: d 4 M 3 
7: e 4 M 3 
8: f 6 F 4 
9: f 0 F 4 

diesen Versuch auf den data.table in @ Frank Kommentar, gibt das erwartete Ergebnis auch:

dt<-data.table(x = c("b", "a", "a"), y = c(1, 1, 2), z = c("F", "F", "F")) 
dt$grp <- rep(NA,nrow(dt)) 
for (i in 1:nrow(dt)){ 
    if (i == 1){ 
     dt$grp[i] = 1 
    } 
    else { 
     if(dt$z[i-1] == dt$z[i] & (dt$x[i-1] == dt$x[i] | dt$y[i-1] == dt$y[i])){ 
     dt$grp[i] = dt$grp[i-1] 
     }else{ 
     dt$grp[i] = dt$grp[i-1] + 1 
     } 
    } 
} 
dt 

    x y z grp 
1: b 1 F 1 
2: a 1 F 1 
3: a 2 F 1 
0

BEARBEITET ZU ADDIEREN: Diese Lösung ist in mancher Hinsicht eine ausführlichere Version von der, die von djhurio above befürwortet wird. Ich denke, es zeigt, was passiert, ein bisschen mehr, also werde ich es verlassen.

Ich denke, das ist eine Aufgabe einfacher zu tun, wenn es ein wenig zusammengebrochen ist. Der folgende Code erstellt zunächst zwei Indizes, einen für Änderungen in x (verschachtelt in z) und einen für Änderungen in y (verschachtelt in z). Wir finden dann die erste Reihe von jedem dieser Indizes. Die kumulative Summe des Falles, in dem sowohl FIRST.x als auch FIRST.y den Wert true haben, sollte den gewünschten Index ergeben.

library(data.table) 

dt_example <- data.table(x = c("a","a","a","b","c","d","e","f","f"), 
         y = c(1,3,2,8,8,4,4,6,0), 
         z = c("M","M","M","F","F","M","M","F","F")) 

dt_example[,Index_x := .GRP,by = c("z","x")] 
dt_example[,Index_y := .GRP,by = c("z","y")] 

dt_example[,FIRST.x := !duplicated(Index_x)] 
dt_example[,FIRST.y := !duplicated(Index_y)] 

dt_example[,Index := cumsum(FIRST.x & FIRST.y)] 
dt_example 

    x y z Index_x Index_y FIRST.x FIRST.y Index 
1: a 1 M  1  1 TRUE TRUE  1 
2: a 3 M  1  2 FALSE TRUE  1 
3: a 2 M  1  3 FALSE TRUE  1 
4: b 8 F  2  4 TRUE TRUE  2 
5: c 8 F  3  4 TRUE FALSE  2 
6: d 4 M  4  5 TRUE TRUE  3 
7: e 4 M  5  5 TRUE FALSE  3 
8: f 6 F  6  6 TRUE TRUE  4 
9: f 0 F  6  7 FALSE TRUE  4 
0

Dieser Ansatz sucht nach Änderungen in x & z | y & z. Die zusätzlichen Spalten verbleiben in der data.table, um die Berechnungen anzuzeigen.

DF[, c("Ix", "Iy", "Iz", "dx", "dy", "min.change", "Index") := 
    #Create index of values based on consecutive order 
    list(ix <- rleid(x), iy <- rleid(y), iz <- rleid(z), 
      #Determine if combinations of x+z OR y+z change 
      ix1 <- c(0, diff(rleid(ix+iz))), 
      iy1 <- c(0, diff(rleid(iy+iz))), 
      #Either combination is constant (no change)? 
      change <- pmin(ix1, iy1), 
      #New index based on change 
      cumsum(change) + 1 
     )] 

    x y z Ix Iy Iz dx dy min.change Index 
1: a 1 M 1 1 1 0 0   0  1 
2: a 3 M 1 2 1 0 1   0  1 
3: a 2 M 1 3 1 0 1   0  1 
4: b 8 F 2 4 2 1 1   1  2 
5: c 8 F 3 4 2 1 0   0  2 
6: d 4 M 4 5 3 1 1   1  3 
7: e 4 M 5 5 3 1 0   0  3 
8: f 6 F 6 6 4 1 1   1  4 
9: f 0 F 6 7 4 0 1   0  4