如何用缺失值之前和之后的数值的平均值填充向量中的缺失值

3

我目前正在尝试在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)

然而,这只能检测可能需要填充的缺失值,并且仅适用于示例一。它不完整,且非常难以阅读和理解。

如果有任何帮助,将不胜感激。


你能展示每个测试输入的预期输出吗?考虑到两侧没有元素,如何处理输入的第一个和最后一个元素?你能添加一个大于某个标准的例子吗? - G. Grothendieck
3个回答

1
我们可以使用dplyrlaglead函数来实现这一点:
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 的向量化版本。也就是说,ifelse 中的所有内容都将应用于向量的每个元素。 首先,我们测试元素是否为 NA,并且后面的元素是否大于前面的元素。要获取前一个和后一个元素,我们可以使用 dplyrleadlag 函数:

lag 将向量向右偏移(默认为 1 步):

lag(1:5)

返回:
[1] NA  1  2  3  4

"

lead向左偏移一个向量:

"
lead(1:5)

返回:
[1]  2  3  4  5 NA

现在来看 ifelse 的 'test' 子句:
is.na(input_three) & lead(input_three) > lag(input_three)

这会返回:

[1]    NA    NA FALSE FALSE  TRUE FALSE    NA    NA

如果ifelse子句评估为TRUE,则我们希望返回前一个和后一个元素的总和除以2,否则返回原始元素。

1
这是一个使用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

0

imputeTS包中还有na_ma函数可用于插补移动平均值。

在您的情况下,可以使用以下设置:

na_ma(x, k = 1, weighting = "simple")

  • k = 1(表示考虑NA之前和之后的1个值)
  • weighting = "simple"(计算这两个值的平均值)

这可以通过基本上一行代码轻松应用:

library(imputeTS)
na_ma(yourData, k = 1, weighting = "simple") 

您也可以选择考虑NA之前和之后的更多值,例如k=3。如果您在每一侧考虑超过1个值,则有一个有趣的特性,即可以选择不同的加权方式,例如使用加权="linear",权重会按算术级数递减(线性加权移动平均),这意味着距离NA越远的值对结果的影响越小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接