Seite 1 von 1

Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Verfasst: Mo Apr 02, 2018 9:18 pm
von Lialo
Sehr geehrte R-User,

ich habe folgendes Problem:

Code: Alles auswählen

x <- c(4,3,6,7,8,8,0,8,0,8,0,6,0,0,0,0,4,3,6,7,8,8,0,8,0,8,0,6,0,8,0,8,0,6,0,0,0,0,4, 
3,6,7,8,8,0,8,0,8,0,6,0,8,0,8,0,6,0,0,0,0,4,3,6,7,8,8,0,8,0,8,0,6,0,0,0,0,6,0,0,0,0,4,3,6,7, 
8,8,0,8,0,0,8,0,8,0,6,0,0,0,0,4,3,6,7,8,8,0,8,0,8,0,68,0,6,0,0,0,0,0,0)
df <- data.frame(matrix (x, ncol = 8))
Der beispielhafte dataframe sieht so aus:

Code: Alles auswählen

   X1 X2 X3 X4 X5 X6 X7 X8
1   4  0  0  8  4  0  0  8
2   3  4  8  0  3  6  8  0
3   6  3  0  8  6  0  0  8
4   7  6  6  0  7  0  8  0
5   8  7  0  6  8  0  0  8
6   8  8  0  0  8  0  6  0
7   0  8  0  8  0  4  0 68
8   8  0  0  0  8  3  0  0
9   0  8  4  8  0  6  0  6
10  8  0  3  0  8  7  0  0
11  0  8  6  6  0  8  4  0
12  6  0  7  0  6  8  3  0
13  0  6  8  0  0  0  6  0
14  0  0  8  0  0  8  7  0
15  0  8  0  0  0  0  8  0
Nun möchte ich eine Spalte mit cbind an den Dataframe anheften. Diese soll zählen wie oft ein Wert hintereinander (also pro Reihe) existiert, ausgenommen die null. Also wie oft gibt es hintereinander einen anderen Wert als 0. Da es in mancher Reihe mehrere Unterbrechungen gibt, soll nur die maximale Anzahl zusammenhängender Zahlen in der neuen Spalte ausgegeben werden.

X1 X2 X3 X4 X5 X6 X7 X8
1 4 0 0 8 4 0 0 8 2
2 3 4 8 0 3 6 8 0 3
3 6 3 0 8 6 0 0 8 2
4 7 6 6 0 7 0 8 0 3
5 8 7 0 6 8 0 0 8 2
6 8 8 0 0 8 0 6 0 2
7 0 8 0 8 0 4 0 68 1
8 8 0 0 0 8 3 0 0 2
9 0 8 4 8 0 6 0 6 3
10 8 0 3 0 8 7 0 0 2
11 0 8 6 6 0 8 4 0 3
12 6 0 7 0 6 8 3 0 3
13 0 6 8 0 0 0 6 0 2
14 0 0 8 0 0 8 7 0 2
15 0 8 0 0 0 0 8 01

Hat jemand eine Idee dieses Problem zu lösen? :idea:

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Verfasst: Mo Apr 02, 2018 9:29 pm
von jogo
Hallo Lialo,

es gibt die schöne Funktion rle() - die kann das KernStück werden von einer Funktion, die das entsprechende Resultat für einen Vektor liefert. Diese Funktion kannst Du dann per apply(df, 1, FUN=...) auf die Zeilen des Dataframes anwenden und dann der neuen Spalte zuweisen, also:

Code: Alles auswählen

df$resultat <- apply(df, 1, FUN=...)
...
Nachtrag:
Die Funktion sieht bei mir so aus:

Code: Alles auswählen

F <- function(x) {
  r <- rle(x!=0)
  max(r$lengths[r$values==TRUE])
}
jetzt nur noch

Code: Alles auswählen

df$resultat <- apply(df, 1, F)
Die Funktion ober erzeugt Fehler, falls der zu untersuchende Vektor ausschließlich aus Nullen besteht; hier eine verbesserte Version:

Code: Alles auswählen

F <- function(x) {
  r <- rle(x!=0)
  l <- r$lengths[r$values==TRUE]
  if (length(l)==0) return(0)
  max(l)
}
... und noch etwas:
bitte lies viewtopic.php?f=20&t=29
und formatiere zukünftig entsprechende Teile Deiner Nachrichten :!:

Gruß, Jörg

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Verfasst: Di Apr 03, 2018 8:29 am
von Lialo
Hallo Jörg,
erst einmal vielen Dank, das hat tatsächlich super funktioniert!

Ich arbeite nun an einer Möglichkeit, nur den längsten Strang einer aufeinanderfolgenden Reihe stehen zu lassen und den Rest der Reihe auf 0 zu setzen, komme aber auch dort nicht weiter.

Ich versuche gerade eine Funktion mit dem Kernstück subset () zu bauen, hat jemand noch andere Vorschläge?

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Verfasst: Di Apr 03, 2018 8:35 am
von jogo
Kannst Du das bitte an einem Beispielvektor demonstrieren, wie das gewünschte Ergebnis aussehen soll :?:
Vielleicht kann man sehr gut die zu rle() inverse Funktion verwenden.

Gruß, Jörg

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Verfasst: Di Apr 03, 2018 8:47 am
von Lialo
Natürlich,
also gleiche Ausgangslage wie oben beschrieben:

Code: Alles auswählen

x <- c(4,3,6,7,8,8,0,8,0,8,0,6,0,0,0,0,4,3,6,7,8,8,0,8,0,8,0,6,0,8,0,8,0,6,0,0,0,0,4, 
3,6,7,8,8,0,8,0,8,0,6,0,8,0,8,0,6,0,0,0,0,4,3,6,7,8,8,0,8,0,8,0,6,0,0,0,0,6,0,0,0,0,4,3,6,7, 
8,8,0,8,0,0,8,0,8,0,6,0,0,0,0,4,3,6,7,8,8,0,8,0,8,0,68,0,6,0,0,0,0,0,0)
df <- data.frame(matrix (x, ncol = 8))
Ergibt diesen Dataframe:

Code: Alles auswählen

   X1 X2 X3 X4 X5 X6 X7 X8
1   4  0  0  8  4  0  0  8
2   3  4  8  0  3  6  8  0
3   6  3  0  8  6  0  0  8
4   7  6  6  0  7  0  8  0
5   8  7  0  6  8  0  0  8
6   8  8  0  0  8  0  6  0
7   0  8  0  8  0  4  0 68
8   8  0  0  0  8  3  0  0
9   0  8  4  8  0  6  0  6
10  8  0  3  0  8  7  0  0
11  0  8  6  6  0  8  4  0
12  6  0  7  0  6  8  3  0
13  0  6  8  0  0  0  6  0
14  0  0  8  0  0  8  7  0
15  0  8  0  0  0  0  8  0
und dieser soll danach nur noch die jeweils längste aufeinanderfolgende Zahlenfolge ungleich null pro Reihe haben:

Code: Alles auswählen

   X1 X2 X3 X4 X5 X6 X7 X8
1   0  0  0  8  4  0  0  0
2   3  4  8  0  0  0  0  0
3   6  3  0  0  0  0  0  0
4   7  6  6  0  0  0  0  0
5   8  7  0  0  0  0  0  0
6   8  8  0  0  0  0  0  0
7   0  8  0  0  0  0  0 0
8   0  0  0  0  8  3  0  0
9   0  8  4  8  0  0  0  0
10  0  0  0  0  8  7  0  0
11  0  8  6  6  0  0  0  0
12  0  0  0  0  6  8  3  0
13  0  6  8  0  0  0  0  0
14  0  0  0  0  0  8  7  0
15  0  8  0  0  0  0  0  0
Da es wie in Zeile 2 manchmal vorkommt, dass zwei gleichlange "Wertereihen" existieren (hier zwei mal jeweils drei Zahlen hintereinander) soll davon nur die erstere stehen bleiben.

Verstehst du mein Anliegen? Ich bastel schon seit gestern Abend an einer Lösung :?

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Verfasst: Di Apr 03, 2018 8:55 am
von jogo
Du hast Dein Anliegen gut erklärt.
Meine Idee dazu ist folgende:
1. r <- rle(...) so wie vorher in der Funktion F()
2. Die Struktur r manipulieren.
3. mit inverse.rle(r) einen Vektor mit logical erzeugen, den man als Index für den ursprünglichen Vektor verwenden kann.
(indexing by logical)

Nachtrag:
Bei mir sieht das jetzt so aus

Code: Alles auswählen

F2 <- function(x) {
  r <- rle(x!=0)
  if (sum(r$values==TRUE)==0) return(x)
  
  r$lengths <- ifelse(r$values==FALSE, -r$lengths, r$lengths)
  i <- which.max(r$lengths)
  r$values[-i] <- FALSE
  r$lengths <- abs(r$lengths)
  rinv <- inverse.rle(r)
  x[!rinv] <- 0
  return(x)
}
df[] <- t(apply(df, 1, F2))
Gruß, Jörg