2017-12-29 8 views
0

Unten ist mein Dataframe. Es hat Zeilen- und Spaltennamen.Anzahl der aufeinander folgenden Nullen in einem Datenrahmen

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
    row1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 
    row2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 

Ich mag würde eine Spalte Test basierend abzuleiten an aufeinanderfolgenden Nullen (vom letzten Spalte, über die Spalten für jede Reihe. Im Folgenden ist ein Beispiel. Für die erste Reihe, gibt 8 aufeinanderfolgende Nullen sind, so dass der Wert in der Test Reihe soll 8. für die zweite Reihe sein, sollte das Ergebnis 1 sein als nur eine Null. (I 15 bis betrachten will und gehen zurück bis in denen Nullen gestartet werden).

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 test 
    row1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 8 
    row2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 

Was ist der beste Weg, dies zu erreichen?

+0

Was ist das Ergebnis für 'c (0, 0, 0, 1, 0, 0)'? – PoGibas

+0

sollte es 2 sein. – 221B

+0

Können Sie erklären, warum nicht 3? – PoGibas

Antwort

4

Lösung rle mit:

getConsecZeroRle <- function(x) { 
    foo <- rle(x) 
    foo$lengths[tail(which(foo$values), 1)] 
} 
result <- apply(df[, -1] == 0, 1, function(x) getConsecZeroRle(x)) 
df$test <- as.numeric(result) 
df$test[is.na(df$test)] <- 0 

Erläuterung:

Verwenden apply iterieren die Teilmenge der Datenrahmen. Berechnen Sie für jede Zeile die Länge aufeinanderfolgender Nullen (rle) und extrahieren Sie den letzten Wert mit tail. Zeilen, die keine Nullen haben, erzeugen NA (mit is.na(df$test)), um sie durch Nullen zu ersetzen.


Lösung sum:

getConsecZeroSum <- function(x) { 
    x[1:tail(which(!x), 1)] <- FALSE 
    sum(x) 
} 
df$test <- apply(df[, -1] == 0, 1, function(x) getConsecZeroSum(x)) 

Erläuterung:

Extract letzten FALSE Wert in jeder Zeile und drehen alles FALSE bevor es (x[1:tail(which(!x), 1)] <- FALSE) dann sum verwenden Nullwerte von den zählen Ende.

Ergebnis:

#  a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 test 
# 1 row1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 8 
# 2 row2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 
+0

Hier ist mein Datenframe mit nur einer Zeile (er hat einige Zeilen- und Spaltennamen) 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 Wenn ich den Code durchführe, erhalte ich die Ergebnis-Ganzzahl (0) als Ausgabe, aber ich erwarte 8. – 221B

+0

@ 221B Ich habe meine Lösung so bearbeitet, dass sie zu Ihren Daten passt – PoGibas

+1

danke, Sie fragen sich, was das Problem früher war? – 221B

1

Sie einfach den Index des ersten Wertes finden konnte, die nicht gleich 0 tut (aus der letzten Spalte Start) und dann subtrahieren:

df$test2 <- apply(df[,ncol(df):1]==0, 1, which.min) - 1 

df 
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 test2 
#1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0  8 
#2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0  1 

Eine andere Antwort:

Da war ich neugierig auf einen Weg, dies ohnezu tun-über Zeilen hinweg kam ich mit einer (zugegebenermaßen komplizierten) Reduce Lösung. Nicht eine Lösung, die ich empfehlen, aber man hat mich interessiert, um zu sehen, ob es einen Weg, es zu tun:

iniCol <- setNames(df[,ncol(df)] == 0, as.numeric(df[,ncol(df)] == 0)) 
df$test2 <- Reduce(function(ini, add) {temp <- ifelse(pmin(as.numeric(names(ini)), add==0) == 0, ini, rowSums(cbind(ini, add == 0))) 
             ini <- setNames(temp, pmin(as.numeric(names(ini)), add==0))}, 
        df[,(ncol(df)-1):1], 
        ini = iniCol) 

Die Idee dahinter ist, das names Attribut zu verwenden, ob eine Spalte je 0 war zu verfolgen. Wenn es dann war, hören wir auf zu zählen, ansonsten zählen wir weiter.

Verwandte Themen