2017-07-26 6 views
4

Ich habe folgenden Datenrahmen mit , und NA s für IDs A einen Zeitraum von einem Jahr bis E über:Count Zahlenfolgen zeilenweise

dat <- data.frame(
id = c("A", "B", "C", "D", "E"), 
jan = c(0, 0, NA, 1, 0), 
feb = c(0, 1, 1, 0, 0), 
mar = c(0, 0, 1, 0, 1), 
apr = c(0, NA, 0, NA, 1), 
may = c(0, NA, 0, 0, 0), 
jun = c(0, 0, 0, 0, 0), 
jul = c(0, 0, 0, 0, 1), 
aug = c(NA, 0, 0, 1, 1), 
sep = c(NA, 0, 0, 1, NA), 
okt = c(NA, 0, 0, 0, NA), 
nov = c(NA, 0, 0, 0, 1), 
dez = c(NA, 0, 0, 0, 0) 
) 

> dat 
    id jan feb mar apr may jun jul aug sep okt nov dez 
    A 0 0 0 0 0 0 0 NA NA NA NA NA 
    B 0 1 0 NA NA 0 0 0 0 0 0 0 
    C NA 1 1 0 0 0 0 0 0 0 0 0 
    D 1 0 0 NA 0 0 0 1 1 0 0 0 
    E 0 0 1 1 0 0 1 1 NA NA 1 0 

Ich mag zählen das erste Auftreten eines 1 wird immer als 1 0.123.516 gezählt

  • : die Anzahl der 1s für jede ID über diesen Zeitraum von einem Jahr, aber die folgenden Bedingungen müssen erfüllt sein
  • NAs sollte als 0s
  • Ein zweites Auftreten eines 1 wird nur gezählt, behandelt werden, wenn sie durch sechs oder mehr 0s/NAs

In meinem Beispiel vorangeht, würde der Graf sein:

> dat 
    id jan feb mar apr may jun jul aug sep okt nov dez  count 
1 A 0 0 0 0 0 0 0 NA NA NA NA NA  => 0 
2 B 0 1 0 NA NA 0 0 0 0 0 0 0  => 1 
3 C NA 1 1 0 0 0 0 0 0 0 0 0  => 1 
4 D 1 0 0 NA 0 0 0 1 1 0 0 0  => 2 
5 E 0 0 1 1 0 0 1 1 NA NA 1 0  => 1 

Die Funktion sollte rowwise in Form von apply(dat[, -1], 1, my_fun) angewendet werden und einen Vektor zurückgeben, der die Anzahl enthält (dh 0, 1, 1, 2, 1). Hat jemand eine Idee, wie man das erreicht?

+0

Können Sie 3 oder 4 oder mehr in einer Reihe haben, die die Bedingungen erfüllen? Oder ist die Anzahl der Spalten, die Sie festgelegt haben, um nur ein Muster zu haben – Sotos

+0

Nein, es gibt immer 12 Spalten. Also ist die maximale Anzahl 2 (es kann nur eine Folge von 6 0 nach einer 1 geben). – piptoma

+2

In Bezug auf Ihre Bearbeitung: Sie können einige der Antworten unten leicht verwenden, um Ihre bearbeitete Frage zu lösen. Einige von ihnen arbeiten bereits mit mehr als sechs Nullen vor der 1. Und die Lösung von NAs ist am einfachsten, wenn NA an den entsprechenden Stellen durch Nullen ersetzt wird. Zum Beispiel 'dat [is.na (dat)] <- 0 'am Betteln oder' y [is.na (y)] <- 0' in meiner Antwort. – demirev

Antwort

4

Wie über rollapply vom Zoo-Paket mit:

library(zoo) 
library(magrittr) 

myfun <- function(y, pattern = c(0,0,0,0,0,0,1)){ 
    y[is.na(y)] <- 0 # to account for both 0s and NAs 
    first <- sum(y[1:(length(pattern)-1)])!=0 
    rest <- y %>% as.numeric() %>% rollapply(7, identical, pattern) %>% sum 
    return(first+rest) 
} 

apply(dat[,-1],1,myfun) 

[1] 0 1 1 2 1 

rollapply Der Teil wird jede Folge von sechs 0s durch eine 1 in jeder Reihe, gefolgt entsprechen.

Die einzige Sache ist, 1s in den ersten 6 Monaten zu berücksichtigen (die Sie zählen möchten, aber nicht durch das Rollapply übereinstimmen). Dies geschieht mit der ersten Zeile myfun.

2

Ich werde die Tatsache nutzen, dass Ihre Funktion maximal 2 pro Zeile zurückgeben kann, da es nie mehr als eine solche Folge von sechs Nullen geben kann. Es wird das Maximum erreichen, wenn irgendwo eine Sequenz von mindestens sechs Nullen existiert, die nicht am Anfang oder Ende am Ende der Zeile beginnt (seitdem wird sie von einer 1 auf beiden Seiten umgeben.)

yoursum <- function(x) 
{ 
    x[is.na(x)]<-0 
    booleans = with(rle(x),values==0 & lengths>5) 
    if(any(booleans)) 
    { 
    if(which(booleans)<length(booleans) & which(booleans)>1) 
     return(2) 
    } 

    if(any(x>0)) 
    return(1) 
    else 
    return(0) 
} 

apply(dat[,-1],1,yoursum) 

Ausgang:

[1] 0 1 1 2 1 
2

da Ihr Datensatz für Monate, dann mit 12 Monaten ist nur ein Muster aufweisen kann, wobei 1 als zweites 1, so die maximale Anzahl von 1s zählen, die Sie jemals haben werden, ist zwei. In diesem Fall brauchen Sie keine Schleife. Wir können dies tun, in eine voll vektorisiert Weise, dh

#Create the pattern to accept 6 or more 0 before the second 1 
#Compliments of @DavidArenburg 
ptn <- "10{6,}1" 


replace(grepl(ptn, do.call(paste0, dat[-1]))+1, rowSums(dat[-1]) == 0, 0) 
#[1] 0 1 1 2 1 

Oder es eine Funktion zu machen,

get_counts <- function(df, ptn = "10{6,}1"){ 
    v1 <- paste0(ptn, collapse = '') 
    replace(grepl(v1, do.call(paste0, df[-1]))+1, rowSums(df[-1]) == 0, 0) 
} 

get_counts(dat) 
#[1] 0 1 1 2 1 
1

Eine einfache Möglichkeit, dies zu nähern, ist einfach Schleife über die Zahlen jede Reihe und die Prüfung die vorherigen Einträge, um zu entscheiden, ob eine gefundene "1" gezählt werden soll oder nicht. Die Operatoren von R sind vektorisiert, so dass die Wiederholung von 12 Zahlen oder 12 Zahlenreihen keinen Unterschied macht.

Alle benötigen, den Überblick über die letzten zu halten gesehen:

last_seen_one = integer(nrow(dat)) 

und die Akkumulations Anzahl von Einsen:

ones_nr = integer(nrow(dat)) 

Dann wird in einen sehr einfachen Algorithmus zu übersetzen, wie:

for(j in 2:length(dat)) { 
    has_one = dat[[j]] == 1L 
    no_one = !last_seen_one 
    i = which(has_one & (no_one | ((j - last_seen_one) >= 6))) 
    ones_nr[i] = ones_nr[i] + 1L 
    last_seen_one[has_one] = j 
} 

Wir erhalten:

ones_nr 
#[1] 0 1 1 2 1 

Auf diese Weise wird nur eine Schleife über 12 Monate/Spalten anstelle einer Schleife über jede ID/Zeile benötigt.

Verwandte Themen