计算数据集的居中移动平均值,忽略 NA,输出与输入长度相同?
Calculate centered moving average of dataset, ignoring NAs, output same length as input?
最终我想为我的数据集创建一个 15 小时的移动平均线。我正在处理的数据每 15 分钟就有一个日期和时间。我需要 window 居中(所以 30 个时间步 before/after 我正在查看的行)。我还需要能够 link 将移动平均数据与我的日期时间数据一起返回,因此我需要它的长度与我的原始数据帧相同。
我已经尝试使用许多函数(movag、MAVE、rollmean 等),但未能找到正确的组合来进行居中平均并用适当的数字填充结果NA 结果。
您可以定义一个函数来计算您选择的任何 window 大小的移动平均值,如果您只希望滚动平均值包含完整 window的价值。如果您希望它对部分 window 内的值取平均值,您也可以指定它。
它将处理输入中的任何 NAs
,如果特定 window 中的所有输入都是 NA
,它将 return 和 NA
在输出向量的适当点。
这个函数可能会短很多,但为了清楚起见,我已经这样写了,并且包含了基本的错误检查和解释性注释。
moving_average <- function(vec, window, full.window.only = TRUE)
{
# Define the size of the window on either side
half_window <- window %/% 2
# Ensure the vector is long enough to have at least one window
stopifnot(length(vec) > window)
# Get the indices we want to average
indices <- lapply(seq_along(vec),
function(y) {
z <- y + 0:(2 * half_window) - half_window;
z[z > 0 & z <= length(vec)]})
# Get the rolling mean at each of our indices, handling NAs as we go
result <- sapply(indices,
function(x){
if(all(is.na(vec[x]))) return(NA)
else return(mean(vec[x], na.rm = TRUE))})
# Insert NAs if we don't want partial means at either end
if(full.window.only)
{
result[1:half_window] <- NA
result[(length(vec) - half_window + 1):length(vec)] <- NA
}
return(result)
}
我将在此处展示一个示例,尝试根据您的描述重新创建一些示例数据:
set.seed(1) # Ensures the random numbers are reproducible
df <- data.frame(times = as.POSIXct("2019-12-25 09:00:00") + 1:20 * 900,
values = rnorm(20, 20, 4))
数据框如下所示:
times values
1 2019-12-25 09:20:00 17.49418
2 2019-12-25 09:40:00 20.73457
3 2019-12-25 10:00:00 16.65749
4 2019-12-25 10:20:00 26.38112
5 2019-12-25 10:40:00 21.31803
6 2019-12-25 11:00:00 16.71813
7 2019-12-25 11:20:00 21.94972
8 2019-12-25 11:40:00 22.95330
9 2019-12-25 12:00:00 22.30313
10 2019-12-25 12:20:00 18.77845
11 2019-12-25 12:40:00 26.04712
12 2019-12-25 13:00:00 21.55937
13 2019-12-25 13:20:00 17.51504
14 2019-12-25 13:40:00 11.14120
15 2019-12-25 14:00:00 24.49972
16 2019-12-25 14:20:00 19.82027
17 2019-12-25 14:40:00 19.93524
18 2019-12-25 15:00:00 23.77534
19 2019-12-25 15:20:00 23.28488
20 2019-12-25 15:40:00 22.37561
出于此示例的目的,我将 window 大小设置为 5(值及其前后的两个测量值)。你会想要将你的设置为 30(或者可能是 60,我不确定你的问题)。我所要做的就是:
df$rolling_average <- moving_average(df$values, 5)
现在 df
看起来像这样:
times values rolling_average
1 2019-12-25 09:15:00 17.49418 NA
2 2019-12-25 09:30:00 20.73457 NA
3 2019-12-25 09:45:00 16.65749 20.51708
4 2019-12-25 10:00:00 26.38112 20.36187
5 2019-12-25 10:15:00 21.31803 20.60490
6 2019-12-25 10:30:00 16.71813 21.86406
7 2019-12-25 10:45:00 21.94972 21.04846
8 2019-12-25 11:00:00 22.95330 20.54054
9 2019-12-25 11:15:00 22.30313 22.40634
10 2019-12-25 11:30:00 18.77845 22.32827
11 2019-12-25 11:45:00 26.04712 21.24062
12 2019-12-25 12:00:00 21.55937 19.00824
13 2019-12-25 12:15:00 17.51504 20.15249
14 2019-12-25 12:30:00 11.14120 18.90712
15 2019-12-25 12:45:00 24.49972 18.58229
16 2019-12-25 13:00:00 19.82027 19.83435
17 2019-12-25 13:15:00 19.93524 22.26309
18 2019-12-25 13:30:00 23.77534 21.83827
19 2019-12-25 13:45:00 23.28488 NA
20 2019-12-25 14:00:00 22.37561 NA
为了直观地检查结果,让我们将滚动平均值绘制为点上的一条线:
plot(df$times, df$values, xlab = "Time", ylab = "Value", main = "Moving average")
lines(df$times, df$rolling_average, col = "red")
看起来像这样:
最终我想为我的数据集创建一个 15 小时的移动平均线。我正在处理的数据每 15 分钟就有一个日期和时间。我需要 window 居中(所以 30 个时间步 before/after 我正在查看的行)。我还需要能够 link 将移动平均数据与我的日期时间数据一起返回,因此我需要它的长度与我的原始数据帧相同。
我已经尝试使用许多函数(movag、MAVE、rollmean 等),但未能找到正确的组合来进行居中平均并用适当的数字填充结果NA 结果。
您可以定义一个函数来计算您选择的任何 window 大小的移动平均值,如果您只希望滚动平均值包含完整 window的价值。如果您希望它对部分 window 内的值取平均值,您也可以指定它。
它将处理输入中的任何 NAs
,如果特定 window 中的所有输入都是 NA
,它将 return 和 NA
在输出向量的适当点。
这个函数可能会短很多,但为了清楚起见,我已经这样写了,并且包含了基本的错误检查和解释性注释。
moving_average <- function(vec, window, full.window.only = TRUE)
{
# Define the size of the window on either side
half_window <- window %/% 2
# Ensure the vector is long enough to have at least one window
stopifnot(length(vec) > window)
# Get the indices we want to average
indices <- lapply(seq_along(vec),
function(y) {
z <- y + 0:(2 * half_window) - half_window;
z[z > 0 & z <= length(vec)]})
# Get the rolling mean at each of our indices, handling NAs as we go
result <- sapply(indices,
function(x){
if(all(is.na(vec[x]))) return(NA)
else return(mean(vec[x], na.rm = TRUE))})
# Insert NAs if we don't want partial means at either end
if(full.window.only)
{
result[1:half_window] <- NA
result[(length(vec) - half_window + 1):length(vec)] <- NA
}
return(result)
}
我将在此处展示一个示例,尝试根据您的描述重新创建一些示例数据:
set.seed(1) # Ensures the random numbers are reproducible
df <- data.frame(times = as.POSIXct("2019-12-25 09:00:00") + 1:20 * 900,
values = rnorm(20, 20, 4))
数据框如下所示:
times values
1 2019-12-25 09:20:00 17.49418
2 2019-12-25 09:40:00 20.73457
3 2019-12-25 10:00:00 16.65749
4 2019-12-25 10:20:00 26.38112
5 2019-12-25 10:40:00 21.31803
6 2019-12-25 11:00:00 16.71813
7 2019-12-25 11:20:00 21.94972
8 2019-12-25 11:40:00 22.95330
9 2019-12-25 12:00:00 22.30313
10 2019-12-25 12:20:00 18.77845
11 2019-12-25 12:40:00 26.04712
12 2019-12-25 13:00:00 21.55937
13 2019-12-25 13:20:00 17.51504
14 2019-12-25 13:40:00 11.14120
15 2019-12-25 14:00:00 24.49972
16 2019-12-25 14:20:00 19.82027
17 2019-12-25 14:40:00 19.93524
18 2019-12-25 15:00:00 23.77534
19 2019-12-25 15:20:00 23.28488
20 2019-12-25 15:40:00 22.37561
出于此示例的目的,我将 window 大小设置为 5(值及其前后的两个测量值)。你会想要将你的设置为 30(或者可能是 60,我不确定你的问题)。我所要做的就是:
df$rolling_average <- moving_average(df$values, 5)
现在 df
看起来像这样:
times values rolling_average
1 2019-12-25 09:15:00 17.49418 NA
2 2019-12-25 09:30:00 20.73457 NA
3 2019-12-25 09:45:00 16.65749 20.51708
4 2019-12-25 10:00:00 26.38112 20.36187
5 2019-12-25 10:15:00 21.31803 20.60490
6 2019-12-25 10:30:00 16.71813 21.86406
7 2019-12-25 10:45:00 21.94972 21.04846
8 2019-12-25 11:00:00 22.95330 20.54054
9 2019-12-25 11:15:00 22.30313 22.40634
10 2019-12-25 11:30:00 18.77845 22.32827
11 2019-12-25 11:45:00 26.04712 21.24062
12 2019-12-25 12:00:00 21.55937 19.00824
13 2019-12-25 12:15:00 17.51504 20.15249
14 2019-12-25 12:30:00 11.14120 18.90712
15 2019-12-25 12:45:00 24.49972 18.58229
16 2019-12-25 13:00:00 19.82027 19.83435
17 2019-12-25 13:15:00 19.93524 22.26309
18 2019-12-25 13:30:00 23.77534 21.83827
19 2019-12-25 13:45:00 23.28488 NA
20 2019-12-25 14:00:00 22.37561 NA
为了直观地检查结果,让我们将滚动平均值绘制为点上的一条线:
plot(df$times, df$values, xlab = "Time", ylab = "Value", main = "Moving average")
lines(df$times, df$rolling_average, col = "red")
看起来像这样: