如何用缺失值前后的平均值填充向量中的缺失值
how to fill missing values in a vector with the mean of value before and after the missing one
目前我正在尝试在 R 中估算向量中的值。条件
的归责是。
- 查找所有 NA 值
- 然后检查它们前后是否有现存值
- 同时检查NA后面的值是否大于
NA
之前的值
- 如果满足条件,取之前的值计算一个平均值
之后。
- 用估算值替换 NA 值
# example one
input_one = c(1,NA,3,4,NA,6,NA,NA)
# example two
input_two = c(NA,NA,3,4,5,6,NA,NA)
# example three
input_three = c(NA,NA,3,4,NA,6,NA,NA)
我开始编写代码来检测可以
归咎于。但是我遇到了以下问题。
# incomplete function to detect the values
sapply(split(!is.na(input[c(rbind(which(is.na(c(input)))-1, which(is.na(c(input)))+1))]),
rep(1:(length(!is.na(input[c(which(is.na(c(input)))-1, which(is.na(c(input)))+1)]))/2), each = 2)), all)
然而,这只会检测到可能是
imputable 并且它只适用于示例一。它是不完整的并且
不幸的是超级难以阅读和理解。
如有任何帮助,我们将不胜感激。
我们可以为此使用 dplyr
s lag
和 lead
函数:
input_three = c(NA,NA,3,4,NA,6,NA,NA)
library(dplyr)
ifelse(is.na(input_three) & lead(input_three) > lag(input_three),
(lag(input_three) + lead(input_three))/ 2,
input_three)
返回:
[1] NA NA 3 4 5 6 NA NA
编辑
解释:
我们使用 ifelse
,它是 if
的向量化版本。 IE。 ifelse
中的所有内容都将应用于向量的每个元素。
首先,我们测试元素是否为 NA
以及下一个元素是否大于前一个元素。要获取前一个和后一个元素,我们可以使用 dplyr
lead
和 lag
函数:
lag
向右偏移向量(默认为 1 步):
lag(1:5)
Returns:
[1] NA 1 2 3 4
lead
向左偏移向量:
lead(1:5)
Returns:
[1] 2 3 4 5 NA
现在到 ifelse
的 'test' 子句:
is.na(input_three) & lead(input_three) > lag(input_three)
哪个 returns:
[1] NA NA FALSE FALSE TRUE FALSE NA NA
然后如果 ifelse
子句的计算结果为 TRUE
我们想要 return 前后元素的总和除以 2,否则 return 原始元素
这是使用 zoo::rollapply()
的替代方法:
library(zoo)
fill_sandwiched_na <- function(f) rollapply(f, 3, FUN = function(x) {
y <- mean(x[-2]); if(is.na(y)) x[2] else y
}, fill = NA, partial = TRUE)
fill_sandwiched_na(input_one)
[1] 1 2 3 4 5 6 NA NA
fill_sandwiched_na(input_two)
[1] NA NA 3 4 5 6 NA NA
fill_sandwiched_na(input_three)
[1] NA NA 3 4 5 6 NA NA
这是一个使用 imputeTS
库的示例。它考虑了序列中的多个 NA
,确保在下一个有效观察值大于最后一个有效观察值时计算平均值,并且还会忽略开头和结尾的 NA
。
library(imputeTS)
myimpute <- function(series) {
# Find where each NA is
nalocations <- is.na(series)
# Find the last and the previous observation for each row
last1 <- lag(series)
next1 <- lead(series)
# Carry forward the last and next observations over sequences of NA
# Each row will then get a last and next that can be averaged
cflast <- na_locf(last1, na_remaining = 'keep')
cfnext <- na_locf(next1, option = 'nocb', na_remaining = 'keep')
# Make a data frame
df <- data.frame(series, nalocations, last1, cflast, next1, cfnext)
# Calculate the mean where there is currently a NA
# making sure that the next is greater than the last
df$mean <- ifelse(df$nalocations, ifelse(df$cflast < df$cfnext, (df$cflast+df$cfnext)/2, NA), NA)
imputedseries <- ifelse(df$nalocations, ifelse(!is.na(df$mean), df$mean, NA), series)
#list(df, imputedseries) # comment this in and return it to see the intermediate data frame for debugging
imputedseries
}
myimpute(c(NA,NA,3,4,NA,NA,6,NA,NA,8,NA,7,NA,NA,9,NA,11,NA,NA))
# [1] NA NA 3 4 5 5 6 7 7 8 NA 7 8 8 9 10 11 NA NA
imputeTS 包中还有 na_ma
函数用于估算移动平均线。
在您的情况下,这将使用以下设置:
na_ma(x, k = 1, weighting = "simple")
- k = 1(表示考虑了 NA 之前的 1 个值和 NA 之后的 1 个值)
- weighting = "simple"(计算这两个值的平均值)
基本上只需 1 行代码就可以很容易地应用它:
library(imputeTS)
na_ma(yourData, k = 1, weighting = "simple")
您也可以选择考虑 NA 前后的更多值,例如k=3。如果您考虑每一方的值超过 1 个,则有趣的功能是可以选择不同的权重,例如weighting = "linear" weights 在算术级数中减少(线性加权移动平均线) - 这意味着它们的值离 NA 越远,它们的影响就越小。
目前我正在尝试在 R 中估算向量中的值。条件 的归责是。
- 查找所有 NA 值
- 然后检查它们前后是否有现存值
- 同时检查NA后面的值是否大于 NA 之前的值
- 如果满足条件,取之前的值计算一个平均值 之后。
- 用估算值替换 NA 值
# example one
input_one = c(1,NA,3,4,NA,6,NA,NA)
# example two
input_two = c(NA,NA,3,4,5,6,NA,NA)
# example three
input_three = c(NA,NA,3,4,NA,6,NA,NA)
我开始编写代码来检测可以 归咎于。但是我遇到了以下问题。
# incomplete function to detect the values
sapply(split(!is.na(input[c(rbind(which(is.na(c(input)))-1, which(is.na(c(input)))+1))]),
rep(1:(length(!is.na(input[c(which(is.na(c(input)))-1, which(is.na(c(input)))+1)]))/2), each = 2)), all)
然而,这只会检测到可能是 imputable 并且它只适用于示例一。它是不完整的并且 不幸的是超级难以阅读和理解。
如有任何帮助,我们将不胜感激。
我们可以为此使用 dplyr
s lag
和 lead
函数:
input_three = c(NA,NA,3,4,NA,6,NA,NA)
library(dplyr)
ifelse(is.na(input_three) & lead(input_three) > lag(input_three),
(lag(input_three) + lead(input_three))/ 2,
input_three)
返回:
[1] NA NA 3 4 5 6 NA NA
编辑
解释:
我们使用 ifelse
,它是 if
的向量化版本。 IE。 ifelse
中的所有内容都将应用于向量的每个元素。
首先,我们测试元素是否为 NA
以及下一个元素是否大于前一个元素。要获取前一个和后一个元素,我们可以使用 dplyr
lead
和 lag
函数:
lag
向右偏移向量(默认为 1 步):
lag(1:5)
Returns:
[1] NA 1 2 3 4
lead
向左偏移向量:
lead(1:5)
Returns:
[1] 2 3 4 5 NA
现在到 ifelse
的 'test' 子句:
is.na(input_three) & lead(input_three) > lag(input_three)
哪个 returns:
[1] NA NA FALSE FALSE TRUE FALSE NA NA
然后如果 ifelse
子句的计算结果为 TRUE
我们想要 return 前后元素的总和除以 2,否则 return 原始元素
这是使用 zoo::rollapply()
的替代方法:
library(zoo)
fill_sandwiched_na <- function(f) rollapply(f, 3, FUN = function(x) {
y <- mean(x[-2]); if(is.na(y)) x[2] else y
}, fill = NA, partial = TRUE)
fill_sandwiched_na(input_one)
[1] 1 2 3 4 5 6 NA NA
fill_sandwiched_na(input_two)
[1] NA NA 3 4 5 6 NA NA
fill_sandwiched_na(input_three)
[1] NA NA 3 4 5 6 NA NA
这是一个使用 imputeTS
库的示例。它考虑了序列中的多个 NA
,确保在下一个有效观察值大于最后一个有效观察值时计算平均值,并且还会忽略开头和结尾的 NA
。
library(imputeTS)
myimpute <- function(series) {
# Find where each NA is
nalocations <- is.na(series)
# Find the last and the previous observation for each row
last1 <- lag(series)
next1 <- lead(series)
# Carry forward the last and next observations over sequences of NA
# Each row will then get a last and next that can be averaged
cflast <- na_locf(last1, na_remaining = 'keep')
cfnext <- na_locf(next1, option = 'nocb', na_remaining = 'keep')
# Make a data frame
df <- data.frame(series, nalocations, last1, cflast, next1, cfnext)
# Calculate the mean where there is currently a NA
# making sure that the next is greater than the last
df$mean <- ifelse(df$nalocations, ifelse(df$cflast < df$cfnext, (df$cflast+df$cfnext)/2, NA), NA)
imputedseries <- ifelse(df$nalocations, ifelse(!is.na(df$mean), df$mean, NA), series)
#list(df, imputedseries) # comment this in and return it to see the intermediate data frame for debugging
imputedseries
}
myimpute(c(NA,NA,3,4,NA,NA,6,NA,NA,8,NA,7,NA,NA,9,NA,11,NA,NA))
# [1] NA NA 3 4 5 5 6 7 7 8 NA 7 8 8 9 10 11 NA NA
imputeTS 包中还有 na_ma
函数用于估算移动平均线。
在您的情况下,这将使用以下设置:
na_ma(x, k = 1, weighting = "simple")
- k = 1(表示考虑了 NA 之前的 1 个值和 NA 之后的 1 个值)
- weighting = "simple"(计算这两个值的平均值)
基本上只需 1 行代码就可以很容易地应用它:
library(imputeTS)
na_ma(yourData, k = 1, weighting = "simple")
您也可以选择考虑 NA 前后的更多值,例如k=3。如果您考虑每一方的值超过 1 个,则有趣的功能是可以选择不同的权重,例如weighting = "linear" weights 在算术级数中减少(线性加权移动平均线) - 这意味着它们的值离 NA 越远,它们的影响就越小。