Ich habe einen Datenrahmen, der Bankaktiva für mehrere Daten (Zeiten) enthält. Jede Bank hat eine eindeutige ID:R - Schnelle Methode zur Berechnung des rollenden Mittelwerts bei unterschiedlicher Breite
# Sample Data
time <- c(51, 52, 53, 55, 56, 51, 52, 51, 52, 53)
id <- c(1234, 1234, 1234, 1234, 1234, 2345, 2345, 3456, 3456, 3456)
name <- c("BANK A", "BANK A", "BANK A", "BANK A", "BANK A", "BANK B", "BANK B", "BANK C",
"BANK C", "BANK C")
assets <- c(5000, 6000, 4000, 7000, 8000, 10000, 12000, 30000, 35000, 40000)
df <- data.frame(time, id, name, assets)
> df
time id name assets
1 51 1234 BANK A 5000
2 52 1234 BANK A 6000
3 53 1234 BANK A 4000
4 55 1234 BANK A 7000
5 56 1234 BANK A 8000
6 51 2345 BANK B 10000
7 52 2345 BANK B 12000
8 51 3456 BANK C 30000
9 52 3456 BANK C 35000
10 53 3456 BANK C 40000
Für jede Bank ich die Roll Mittel der Vermögenswerte berechnet werden soll, variiert die Breite entsprechend der Anzahl von aufeinanderfolgenden Zeitwerte. Der rollierende Mittelwert muss also alle verfügbaren aufeinanderfolgenden vorherigen Werte der Asssets einer Bank enthalten. Wenn für eine Bank kein vorheriger Wert verfügbar ist, entspricht sie den Aktiva. Deshalb füge ich eine Spalte, die die Anzahl von aufeinanderfolgenden Zeit-Werte zählt und als verwenden rollapplyr
aus dem Zoo-Paket, das mir das gewünschte Ergebnis liefert, aber mit einem großen Datensatz es ist viel zu langsam:
# Calculate number of consecutive times
require(dplyr)
df <- df %>%
mutate(number.time = 1) %>% # insert column for number.time, start value = 1
group_by(id) %>%
arrange(time) # correct order for moving average
for(i in 2:nrow(df)) # Start loop in second row, end in last row of df
df$number.time[i] <-
ifelse(df$time[i] == df$time[i-1]+1, # Is time consecutive?
df$number.time[i - 1] + 1, # If yes: add 1 to previous number.time
1) # If no: set number.time = 1
# Moving Average
require(zoo)
df %>%
mutate(mov.average = rollapplyr(data = assets,
width = number.time, # use number.time for width
FUN = mean,
fill = NA,
na.rm = TRUE))
Source: local data frame [10 x 6]
Groups: id [3]
time id name assets number.time mov.average
(dbl) (dbl) (fctr) (dbl) (dbl) (dbl)
1 51 1234 BANK A 5000 1 5000
2 52 1234 BANK A 6000 2 5500
3 53 1234 BANK A 4000 3 5000
4 55 1234 BANK A 7000 1 7000
5 56 1234 BANK A 8000 2 7500
6 51 2345 BANK B 10000 1 10000
7 52 2345 BANK B 12000 2 11000
8 51 3456 BANK C 30000 1 30000
9 52 3456 BANK C 35000 2 32500
10 53 3456 BANK C 40000 3 35000
Wie Könnte ich diese Ausgabe mit einer schnelleren Funktion erhalten? Ich kenne rollmean
von Zoo sowie SMA
von TTR und ma
von der Vorhersage, aber diese erlauben nicht für unterschiedliche Breite. Meine Frage könnte auch mit this question und dieser rblog zusammenhängen, aber ich bin nicht vertraut mit C++ noch weiß ich viel über das Schreiben von Funktionen, so dass ich diese Beiträge nicht wirklich verstehe.
EDIT 1: Beachten Sie, dass in meinem Code oben ist es nicht die for
-Schleife, aber die Rollapplyr, die eine Menge Zeit braucht.
EDIT 2: Der Rollmittelwert darf nicht mehr als die letzten 4 Werte enthalten. Das sind so viele aufeinanderfolgende Werte, wie es nach der Zeitvariablen, aber nicht mehr als die letzten 4 Werte gibt. Entschuldigung für die ungenaue Frage! :/Meine Formulierung basierte auf der Annahme, die "number.time" -Spalte zu verwenden, in der es einfach gewesen wäre, alle Werte auf maximal = 4 zu begrenzen.
Sie könnten anwenden müssen 'cumsum (Aktiva)/seq_along (Aktiva)' durch (1) 'id 'und (2)' ave (df $ Zeit, df $ id, FUN = Funktion (x) cumsum (c (WAHR, (x [-1] - x [-Länge (x)])! = 1))) ' –
Das funktioniert perfekt und ist natürlich sehr schnell. Leider habe ich festgestellt, dass meine Frage ungenau war: Ich möchte den Durchschnittswert von nicht mehr als den letzten 4 Werten berechnen, das sind so viele wie es sind, aber nicht mehr als die letzten 4 Werte. Sehen Sie eine Möglichkeit, diese Einschränkung in Ihren Code zu implementieren? Meine obige Frage basierte auf der Annahme, dass ich die Spalte "number.time" verwenden würde, so dass ich sie einfach auf 4 beschränken konnte, sorry dafür ...:/ – jb123