Я пытаюсь вычислить z-показатель в скользящем окне из 8 наблюдений, используя zoo::rollapply
. Мой пример кода ниже — это то, что я пытаюсь реализовать, но конечный результат неправильный.
Единственное предостережение: мои реальные данные содержат некоторые значения NA, которые я хочу игнорировать. Я также предпочел бы, чтобы окно увеличивалось в размере, пока оно не достигнет 8 наблюдений.
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
должен возвращать скаляр. Обратите внимание на использование last
. Кроме того, scale
уже удаляет NA при вычислении среднего и стандартного отклонения.
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)))
или
df %>% rollapplyr(8, z_score, partial = TRUE) %>% as.data.frame
Либо дает
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
Вот решение purrr
с учетом наблюдения @G.Grotendieck[1] и тех же игрушечных данных, но явно удаляющих NA
, чтобы не полагаться на scale
(или любую другую функцию) внутри z_score
для этого:
library(purrr)
# ---------------
z_score <- \(x) c(last(round(scale(x), 2)))
new_df <- map_dfc(
df,
\(col) map_dbl(seq_along(col), \(x) z_score(tail(discard(col[0:(x)], is.na), 8))))
Выход:
> new_df
# A tibble: 20 × 6
V1 V2 V3 V4 V5 V6
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
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.9 0.1 -0.1 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.5 -1.13 0.93
12 -0.43 1.13 0.39 -0.3 0.28 -0.93
13 0.4 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.6 0.61
16 1.16 -0.15 -0.65 -1.03 -0.73 -0.85
17 -1 0.44 -0.89 -0.29 1.53 0.13
18 -1.32 -1.13 1.21 0.64 -1.11 1
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
[1] > z_score
должен возвращать скаляр. Обратите внимание на использование last
.