2017-08-17 7 views
0

Ich muss einen Zähler implementieren, der dec_cnt um 1 basierend auf bestimmten Bedingungen dekrementiert.Implementieren eines sequentiellen Zählers mit abnehmenden Werten

Unten ist mein Datenrahmen df.

ID A 
    1 0 
    2 0 
    3 0 
    4 1 
    5 1 
    6 0 
    7 0 
    8 0 
    9 0 
10 0 
11 0 
12 0 
13 0 
14 0 
15 0 
16 -1 
17 1 
18 0 
19 1 
20 0 
21 -1 
22 0 
23 0 
24 -1 
25 0 
26 0 
27 0 
28 0 
29 0 
30 0 
31 0 
32 0 
33 0 
34 0 

Die Bedingungen sind
ein. Der Zähler sollte aus dem Datenpunkt beginnen, wo die A==1 or -1 und Erniedrigen die Zähler für die nächsten 16 Werte, zum Beispiel Wert von A == 1 bei ID 4 beginnen, so von ID == 4 bis ID==19 sollte der Dekrementierungszähler von Startwert umgesetzt werden 15 bis Zähler 0. Beachten Sie auch, dass wenn dieser Bereich zwischen A== 1/-1 liegt, er ignoriert werden sollte. b. Ich muss auch retain_A Spalte implementieren, die den Wert von A über die counter behält.

Unten ist meine erwartete Ausgabe. wenn die Datenpunkte

ID A  retain_A dec_cnt 
    1 0   NA   NA 
    2 0   NA   NA 
    3 0   NA   NA 
    4 1   1   15 
    5 1   1   14 
    6 0   1   13 
    7 0   1   12 
    8 0   1   11 
    9 0   1   10 
10 0   1   9 
11 0   1   8 
12 0   1   7 
13 0   1   6 
14 0   1   5 
15 0   1   4 
16 -1   1   3 
17 1   1   2 
18 0   1   1 
19 1   1   0   
20 0   NA   NA 
21 -1   -1   15 
22 0   -1   14 
23 0   -1   13 
24 -1   -1   12 
25 0   -1   11 
26 0   -1   10 
27 0   -1   9 
28 0   -1   8 
29 0   -1   7 
30 0   -1   6 
31 0   -1   5 
32 0   -1   4 
33 0   -1   3 
34 0   -1   2 

Die ähnliche Art von Frage vor einigen Tagen hatte geschrieben, wo die Lösung for loop verwendet, auch die loop nicht mehr als 35 sind auszuführen. Ich wollte vermeiden, for loop, weil seine Ausführungszeit wird mehr sein, wenn wir mit riesigen Datenmengen zu tun haben.

Der Datenrahmen wird von der Frage here

unten geschrieben nehmen ist das Skript, das ich den oben genannten Beitrag versucht, mit.

dec_cnt <- 0 
    Retain_A <- NA 
    for (i in seq_along(df$A)) { 
    if (dec_cnt == 0) { 
     if (df$A[i] == 0) next 
    dec_cnt <- 15 
    Retain_A <- df$A[i] 
    df$Retain_A[i] <- df$A[i] 
    df$dec_cnt[i] <- dec_cnt 
    } else { 
    dec_cnt <- dec_cnt - 1 
    df$Retain_A[i] <- Retain_A 
    df$dec_cnt[i] <- dec_cnt 
    } 
} 
+0

Warum findest du nicht einfach alle ersten '1' und' -1', Subset 16 Zeilen danach und füge eine Sequenz (und '1' /' -1') hinzu? Können Sie Ihr Beispiel in einer einfach zu findenden Form wie 'dput()' bereitstellen? –

Antwort

2

Ich glaube nicht, es ist realistisch, jede Art von Schleife zu vermeiden, for oder auf andere Weise. Vielleicht wäre ein realistischeres Ziel, Schleifen zu vermeiden, die über jeden einzelnen Wert iterieren, unabhängig davon, ob es relevant ist.

Angefangen von der 2-Säulen-Eingang, lassen Sie uns die leeren Spalten voreingestellt:

dat$retain_A <- NA 
dat$dec_cnt <- NA 

Hier, wo wir einige Effizienz gewinnen können: Statt Vergleiche immer wieder machen, können wir wissen, ob es passt - 1/1 jetzt:

ind <- which(dat$A %in% c(-1,1)) 
last_match <- 0 
ind 
# [1] 4 5 16 17 19 21 24 

der Trick ist, den Überblick über die last_match zu halten und alle Indizes zwischen ihm und den nächsten 15 Eingaben zu verwerfen.

ind <- ind[ind > last_match] 
while (length(ind) > 0) { 
    i <- seq(ind[1], min(ind[1] + 15, nrow(dat))) 
    dat$dec_cnt[i] <- head(15:0, n = length(i)) 
    dat$retain_A[i] <- dat$A[ ind[1] ] 
    last_match <- ind[1] + 15 
    ind <- ind[ind > last_match] 
} 
dat 
# ID A retain_A dec_cnt 
# 1 1 0  NA  NA 
# 2 2 0  NA  NA 
# 3 3 0  NA  NA 
# 4 4 1  1  15 
# 5 5 1  1  14 
# 6 6 0  1  13 
# 7 7 0  1  12 
# 8 8 0  1  11 
# 9 9 0  1  10 
# 10 10 0  1  9 
# 11 11 0  1  8 
# 12 12 0  1  7 
# 13 13 0  1  6 
# 14 14 0  1  5 
# 15 15 0  1  4 
# 16 16 -1  1  3 
# 17 17 1  1  2 
# 18 18 0  1  1 
# 19 19 1  1  0 
# 20 20 0  NA  NA 
# 21 21 -1  -1  15 
# 22 22 0  -1  14 
# 23 23 0  -1  13 
# 24 24 -1  -1  12 
# 25 25 0  -1  11 
# 26 26 0  -1  10 
# 27 27 0  -1  9 
# 28 28 0  -1  8 
# 29 29 0  -1  7 
# 30 30 0  -1  6 
# 31 31 0  -1  5 
# 32 32 0  -1  4 
# 33 33 0  -1  3 
# 34 34 0  -1  2 

Sie werden feststellen, dass Ihre erste Schleife wiederholt einmal pro Zeile Diese Lösung iteriert nur einmal pro Nicht-Null.

+0

@Yeah Es hat funktioniert !!! Und vielen Dank für die Erklärung. :) – Tareva

+0

@ r2evans, können Sie auch 'rev (0:15)' anstelle von 'Kopf (15: 0, n = Länge (i))' – parth

+0

Nein, nicht ganz verwenden. Sie können '15: 0' durch' rev (0:15) 'ersetzen, aber Sie verpassen die Absicht,' head' zu verwenden. – r2evans

Verwandte Themen