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

2020-02-14 r imputation

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

但是,这仅检测到可能是 可归因的,并且仅适用于示例一。它不完整且 不幸的是很难阅读和理解。

任何帮助,将不胜感激。

Answers

我们可以dplyr使用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以及后一个元素是否大于前一个。为了获得上一个和下一个元素,我们可以使用dplyr leadlag函数:

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,否则返回原始元素

这是使用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都考虑在内)
  • 权重=“简单”(计算这两个值的平均值)

基本上只需一行代码即可轻松实现:

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

您还可以选择在NA之前和之后考虑更多的值,例如k = 3。有趣的功能是,如果考虑到每一侧的值都超过1,则可以选择其他权重,例如,权重=“线性”时,权重在算术级数中减小(线性加权移动平均值)-意味着它们的值越远离NA对其影响较小。

Related