I'm trying to calculate a z-score over a moving window of 8 observations using zoo::rollapply
. My example code below is what I'm attempting to implement, but the end result is not right.
The only caveat to this is my real data has some NA values which I wish to ignore. I'd also prefer the window to increase in size until it hits 8 observations.
library(zoo)
df <- as.data.frame(
matrix(round(runif(n = 120, min = 1, max = 20), 0), nrow = 20)
)
z_score <- function(x){
as.numeric(round(scale(x), 2))
}
df_scaled <- df %>%
mutate_at(
vars(1:6),
~rollapply(.x, width = 8, FUN = z_score, by.column = TRUE, partial = TRUE,
align = "right"
)
)
z_score
should be returning a scalar. Note use of last
. Also scale
already removes NA's when computing the mean and sd.
library(dplyr)
library(zoo)
set.seed(123) # for reproducibility
df <- as.data.frame(
matrix(round(runif(n = 120, min = 1, max = 20), 0), nrow = 20)
)
z_score <- function(x) c(last(round(scale(x), 2)))
df %>%
mutate(across(everything(), ~ rollapplyr(.x, 8, z_score, partial = TRUE)))
or
df %>% rollapplyr(8, z_score, partial = TRUE) %>% as.data.frame
Either gives
V1 V2 V3 V4 V5 V6
1 NaN NaN NaN NaN NaN NaN
2 0.71 -0.71 0.71 -0.71 0.71 -0.71
3 -0.26 -0.76 0.58 -0.06 -0.16 0.13
4 1.01 1.13 0.21 -0.38 1.04 1.37
5 0.94 -0.81 -1.08 1.21 -1.22 -0.36
6 -1.38 -0.45 -0.90 0.10 -0.10 1.11
7 -0.09 -1.18 -0.47 1.09 1.51 0.95
8 0.89 -0.77 1.29 0.95 1.02 -0.08
9 -0.34 -1.78 -0.36 0.87 0.79 -0.85
10 -0.39 -1.55 2.11 -0.73 -1.21 -1.61
11 0.91 1.19 -1.05 0.50 -1.13 0.93
12 -0.43 1.13 0.39 -0.30 0.28 -0.93
13 0.40 0.33 1.34 0.14 -0.55 -1.38
14 -0.32 0.65 -0.98 -2.21 0.13 1.11
15 -1.81 -1.51 0.47 -0.35 -0.60 0.61
16 1.16 -0.15 -0.65 -1.03 -0.73 -0.85
17 -1.00 0.44 -0.89 -0.29 1.53 0.13
18 -1.32 -1.13 1.21 0.64 -1.11 1.00
19 -0.36 -0.63 1.31 -0.22 0.14 0.14
20 1.35 -0.75 -0.33 -1.03 0.44 -0.38