r 根据值(不是行数或 date/time 变量)用 window 计算滚动平均值
r calculating rolling average with window based on value (not number of rows or date/time variable)
我对所有用于在 R 中计算滚动平均值的包都很陌生,我希望你能告诉我正确的方向。
我有以下数据为例:
ms <- c(300, 300, 300, 301, 303, 305, 305, 306, 308, 310, 310, 311, 312,
314, 315, 315, 316, 316, 316, 317, 318, 320, 320, 321, 322, 324,
328, 329, 330, 330, 330, 332, 332, 334, 334, 335, 335, 336, 336,
337, 338, 338, 338, 340, 340, 341, 342, 342, 342, 342)
correct <- c(1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
1, 0, 0, 1, 0, 0, 1, 1, 0, 0)
df <- data.frame(ms, correct)
ms
是以毫秒为单位的时间点,correct
是特定动作是否正确执行
(1 = 正确,0 = 不正确)。
我现在的目标是计算在设定的毫秒数 windows 内的正确(或平均值)百分比。正如您所看到的,某些时间点缺失,某些时间点出现多次。因此,我不想根据行号进行过滤。我研究了一些包,例如 "tidyquant" 但在我看来,这类包需要一个 time/date 变量而不是一个数值变量来确定 window 值的平均值.有没有办法在df$ms
的数值上指定window?
你可以试试'cut'。例如,如果你想将 ms 划分为总共 5 个组,那么你可以这样做:
df$ms_factor <- cut(df$ms, 5)
df_new <- df %>% group_by(ms_factor) %>% summarise(mean = mean(correct))
试用:
library(dplyr)
# count the number of values per ms
df <- df %>%
group_by(ms) %>%
mutate(Nb.values = n())
# consider a window of 1 ms and compute the percentage for each window
df2 <- setNames(aggregate(correct ~ factor(df$ms, levels = as.character(seq(min(df$ms), max(df$ms), 1))),
df, sum),
c("ms", "Count.correct"))
# complete data frame (including unused levels)
df2 <- tidyr::complete(df2, ms)
df2$ms <- as.numeric(levels(df2$ms))[df2$ms]
df2 <- df2 %>% left_join(distinct(df[, c(1, 3)]), "ms")
# compute a rolling mean of the percentage of correct, with a width of 5
df2 %>%
mutate(Window = paste(ms, ms+4, sep = "-"), # add windows
Rolling.correct = zoo::rollapply(Count.correct, 5, sum, na.rm = T,
partial = TRUE, fill = NA, align = "left") /
zoo::rollapply(Nb.values, 5, sum, na.rm = T, partial = TRUE,
fill = NA, align = "left")) # add rolling mean
# A tibble: 43 x 5
ms Count.correct Nb.values Window Rolling.correct
<dbl> <dbl> <int> <chr> <dbl>
1 300 2 3 300-304 0.40
2 301 0 1 301-305 0.00
3 302 NA NA 302-306 0.25
4 303 0 1 303-307 0.25
5 304 NA NA 304-308 0.25
6 305 0 2 305-309 0.25
7 306 1 1 306-310 0.25
8 307 NA NA 307-311 0.00
9 308 0 1 308-312 0.20
10 309 NA NA 309-313 0.25
# ... with 33 more rows
这可以用base R
来完成:
calculate_irregular_ratio <- function(df, time_var = "ms", window_var = 5, calc_var = "correct") {
sapply(df[[time_var]], function(x) round(mean(df[[calc_var]][df[[time_var]] >= (x - window_var) & df[[time_var]] <= x]), 2))
}
您可以按如下方式应用它(默认设置为 5 毫秒,您可以通过更改 window_var
参数来更改它):
df$window_5_ratio <- calculate_irregular_ratio(df, window_var = 5)
在您的情况下,您会得到(仅显示前 10 行):
ms correct window_5_ratio
1 300 1 0.67
2 300 1 0.67
3 300 0 0.67
4 301 0 0.50
5 303 0 0.40
6 305 0 0.29
7 305 0 0.29
8 306 1 0.20
9 308 0 0.20
10 310 0 0.17
它的行为类似于滚动平均值,但它不依赖于行。相反,它根据列中的值采用 window。
例如,在第 6 行和第 7 行,它采用当前行的值(305 毫秒),并计算数据框中所有 305 和 - 5 值的比率,即在 305 和 300 之间,产生0.29.
您当然可以随时自己修改功能,例如如果您希望 window 5 实际上表示 301 - 305 而不是 300 - 305,您可以在 x - window_var
之后设置 + 1,等等
为了完整起见,这里有一个答案,它使用 data.table 来 在非等值连接中聚合 。
OP 已在 中澄清,他正在寻找 5 毫秒的滑动 window,即 windows 300-304, 301-305、302-306 等.
由于OP的数据集中没有302ms的数据点,需要补缺值
library(data.table)
ws <- 5 # define window size
setDT(df)[SJ(start = seq(min(ms), max(ms), 1))[, end := start + ws - 1],
on = .(ms >= start, ms <= end),
.(share_correct = mean(correct)), by = .EACHI]
ms ms share_correct
1: 300 304 0.4000000
2: 301 305 0.0000000
3: 302 306 0.2500000
4: 303 307 0.2500000
5: 304 308 0.2500000
6: 305 309 0.2500000
7: 306 310 0.2500000
8: 307 311 0.0000000
9: 308 312 0.2000000
10: 309 313 0.2500000
11: 310 314 0.2000000
12: 311 315 0.4000000
13: 312 316 0.4285714
14: 313 317 0.2857143
15: 314 318 0.3750000
16: 315 319 0.4285714
17: 316 320 0.4285714
18: 317 321 0.4000000
19: 318 322 0.4000000
20: 319 323 0.2500000
21: 320 324 0.4000000
22: 321 325 0.3333333
23: 322 326 0.5000000
24: 323 327 1.0000000
25: 324 328 1.0000000
26: 325 329 0.5000000
27: 326 330 0.2000000
28: 327 331 0.2000000
29: 328 332 0.4285714
30: 329 333 0.3333333
31: 330 334 0.2857143
32: 331 335 0.5000000
33: 332 336 0.3750000
34: 333 337 0.2857143
35: 334 338 0.3000000
36: 335 339 0.3750000
37: 336 340 0.3750000
38: 337 341 0.4285714
39: 338 342 0.4000000
40: 339 343 0.4285714
41: 340 344 0.4285714
42: 341 345 0.4000000
43: 342 346 0.5000000
ms ms share_correct
如果 OP 只对 windows 感兴趣,其中起点存在于数据集中,则可以简化代码:
setDT(df)[SJ(start = unique(ms))[, end := start + ws - 1],
on = .(ms >= start, ms <= end),
.(share_correct = mean(correct)), by = .EACHI]
ms ms share_correct
1: 300 304 0.4000000
2: 301 305 0.0000000
3: 303 307 0.2500000
4: 305 309 0.2500000
5: 306 310 0.2500000
6: 308 312 0.2000000
7: 310 314 0.2000000
8: 311 315 0.4000000
9: 312 316 0.4285714
10: 314 318 0.3750000
11: 315 319 0.4285714
12: 316 320 0.4285714
13: 317 321 0.4000000
14: 318 322 0.4000000
15: 320 324 0.4000000
16: 321 325 0.3333333
17: 322 326 0.5000000
18: 324 328 1.0000000
19: 328 332 0.4285714
20: 329 333 0.3333333
21: 330 334 0.2857143
22: 332 336 0.3750000
23: 334 338 0.3000000
24: 335 339 0.3750000
25: 336 340 0.3750000
26: 337 341 0.4285714
27: 338 342 0.4000000
28: 340 344 0.4285714
29: 341 345 0.4000000
30: 342 346 0.5000000
ms ms share_correct
在这两种情况下,包含间隔 [start, end]
的 data.table 会即时创建并右连接到 df
。在 non-equi join 期间,中间结果立即按连接参数 (by = .EACHI
) 分组并聚合。请注意,闭区间 用于符合 OP 的预期。
我对所有用于在 R 中计算滚动平均值的包都很陌生,我希望你能告诉我正确的方向。
我有以下数据为例:
ms <- c(300, 300, 300, 301, 303, 305, 305, 306, 308, 310, 310, 311, 312,
314, 315, 315, 316, 316, 316, 317, 318, 320, 320, 321, 322, 324,
328, 329, 330, 330, 330, 332, 332, 334, 334, 335, 335, 336, 336,
337, 338, 338, 338, 340, 340, 341, 342, 342, 342, 342)
correct <- c(1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
1, 0, 0, 1, 0, 0, 1, 1, 0, 0)
df <- data.frame(ms, correct)
ms
是以毫秒为单位的时间点,correct
是特定动作是否正确执行
(1 = 正确,0 = 不正确)。
我现在的目标是计算在设定的毫秒数 windows 内的正确(或平均值)百分比。正如您所看到的,某些时间点缺失,某些时间点出现多次。因此,我不想根据行号进行过滤。我研究了一些包,例如 "tidyquant" 但在我看来,这类包需要一个 time/date 变量而不是一个数值变量来确定 window 值的平均值.有没有办法在df$ms
的数值上指定window?
你可以试试'cut'。例如,如果你想将 ms 划分为总共 5 个组,那么你可以这样做:
df$ms_factor <- cut(df$ms, 5)
df_new <- df %>% group_by(ms_factor) %>% summarise(mean = mean(correct))
试用:
library(dplyr)
# count the number of values per ms
df <- df %>%
group_by(ms) %>%
mutate(Nb.values = n())
# consider a window of 1 ms and compute the percentage for each window
df2 <- setNames(aggregate(correct ~ factor(df$ms, levels = as.character(seq(min(df$ms), max(df$ms), 1))),
df, sum),
c("ms", "Count.correct"))
# complete data frame (including unused levels)
df2 <- tidyr::complete(df2, ms)
df2$ms <- as.numeric(levels(df2$ms))[df2$ms]
df2 <- df2 %>% left_join(distinct(df[, c(1, 3)]), "ms")
# compute a rolling mean of the percentage of correct, with a width of 5
df2 %>%
mutate(Window = paste(ms, ms+4, sep = "-"), # add windows
Rolling.correct = zoo::rollapply(Count.correct, 5, sum, na.rm = T,
partial = TRUE, fill = NA, align = "left") /
zoo::rollapply(Nb.values, 5, sum, na.rm = T, partial = TRUE,
fill = NA, align = "left")) # add rolling mean
# A tibble: 43 x 5
ms Count.correct Nb.values Window Rolling.correct
<dbl> <dbl> <int> <chr> <dbl>
1 300 2 3 300-304 0.40
2 301 0 1 301-305 0.00
3 302 NA NA 302-306 0.25
4 303 0 1 303-307 0.25
5 304 NA NA 304-308 0.25
6 305 0 2 305-309 0.25
7 306 1 1 306-310 0.25
8 307 NA NA 307-311 0.00
9 308 0 1 308-312 0.20
10 309 NA NA 309-313 0.25
# ... with 33 more rows
这可以用base R
来完成:
calculate_irregular_ratio <- function(df, time_var = "ms", window_var = 5, calc_var = "correct") {
sapply(df[[time_var]], function(x) round(mean(df[[calc_var]][df[[time_var]] >= (x - window_var) & df[[time_var]] <= x]), 2))
}
您可以按如下方式应用它(默认设置为 5 毫秒,您可以通过更改 window_var
参数来更改它):
df$window_5_ratio <- calculate_irregular_ratio(df, window_var = 5)
在您的情况下,您会得到(仅显示前 10 行):
ms correct window_5_ratio
1 300 1 0.67
2 300 1 0.67
3 300 0 0.67
4 301 0 0.50
5 303 0 0.40
6 305 0 0.29
7 305 0 0.29
8 306 1 0.20
9 308 0 0.20
10 310 0 0.17
它的行为类似于滚动平均值,但它不依赖于行。相反,它根据列中的值采用 window。
例如,在第 6 行和第 7 行,它采用当前行的值(305 毫秒),并计算数据框中所有 305 和 - 5 值的比率,即在 305 和 300 之间,产生0.29.
您当然可以随时自己修改功能,例如如果您希望 window 5 实际上表示 301 - 305 而不是 300 - 305,您可以在 x - window_var
之后设置 + 1,等等
为了完整起见,这里有一个答案,它使用 data.table 来 在非等值连接中聚合 。
OP 已在
由于OP的数据集中没有302ms的数据点,需要补缺值
library(data.table)
ws <- 5 # define window size
setDT(df)[SJ(start = seq(min(ms), max(ms), 1))[, end := start + ws - 1],
on = .(ms >= start, ms <= end),
.(share_correct = mean(correct)), by = .EACHI]
ms ms share_correct 1: 300 304 0.4000000 2: 301 305 0.0000000 3: 302 306 0.2500000 4: 303 307 0.2500000 5: 304 308 0.2500000 6: 305 309 0.2500000 7: 306 310 0.2500000 8: 307 311 0.0000000 9: 308 312 0.2000000 10: 309 313 0.2500000 11: 310 314 0.2000000 12: 311 315 0.4000000 13: 312 316 0.4285714 14: 313 317 0.2857143 15: 314 318 0.3750000 16: 315 319 0.4285714 17: 316 320 0.4285714 18: 317 321 0.4000000 19: 318 322 0.4000000 20: 319 323 0.2500000 21: 320 324 0.4000000 22: 321 325 0.3333333 23: 322 326 0.5000000 24: 323 327 1.0000000 25: 324 328 1.0000000 26: 325 329 0.5000000 27: 326 330 0.2000000 28: 327 331 0.2000000 29: 328 332 0.4285714 30: 329 333 0.3333333 31: 330 334 0.2857143 32: 331 335 0.5000000 33: 332 336 0.3750000 34: 333 337 0.2857143 35: 334 338 0.3000000 36: 335 339 0.3750000 37: 336 340 0.3750000 38: 337 341 0.4285714 39: 338 342 0.4000000 40: 339 343 0.4285714 41: 340 344 0.4285714 42: 341 345 0.4000000 43: 342 346 0.5000000 ms ms share_correct
如果 OP 只对 windows 感兴趣,其中起点存在于数据集中,则可以简化代码:
setDT(df)[SJ(start = unique(ms))[, end := start + ws - 1],
on = .(ms >= start, ms <= end),
.(share_correct = mean(correct)), by = .EACHI]
ms ms share_correct 1: 300 304 0.4000000 2: 301 305 0.0000000 3: 303 307 0.2500000 4: 305 309 0.2500000 5: 306 310 0.2500000 6: 308 312 0.2000000 7: 310 314 0.2000000 8: 311 315 0.4000000 9: 312 316 0.4285714 10: 314 318 0.3750000 11: 315 319 0.4285714 12: 316 320 0.4285714 13: 317 321 0.4000000 14: 318 322 0.4000000 15: 320 324 0.4000000 16: 321 325 0.3333333 17: 322 326 0.5000000 18: 324 328 1.0000000 19: 328 332 0.4285714 20: 329 333 0.3333333 21: 330 334 0.2857143 22: 332 336 0.3750000 23: 334 338 0.3000000 24: 335 339 0.3750000 25: 336 340 0.3750000 26: 337 341 0.4285714 27: 338 342 0.4000000 28: 340 344 0.4285714 29: 341 345 0.4000000 30: 342 346 0.5000000 ms ms share_correct
在这两种情况下,包含间隔 [start, end]
的 data.table 会即时创建并右连接到 df
。在 non-equi join 期间,中间结果立即按连接参数 (by = .EACHI
) 分组并聚合。请注意,闭区间 用于符合 OP 的预期。