Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Wie rufe ich R-Funktionen auf, wie selektiere ich Daten, ich weiß nicht genau ....

Moderatoren: EDi, jogo

Antworten
Lialo

Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Beitrag 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:
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Beitrag 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
Lialo

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Beitrag 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?
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Beitrag 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
Lialo

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Beitrag 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 :?
jogo
Beiträge: 2085
Registriert: Fr Okt 07, 2016 8:25 am

Re: Anzahl aufeinanderfolgender Werte ungleich null pro Reihe

Beitrag 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
Antworten