使用滚动窗口替换 NA 值

  • 本文关键字:NA 替换 窗口 滚动 r
  • 更新时间 :
  • 英文 :


如何将NA值替换为上一个非NA值和下一个非NA值的平均值?例如,我想将第一个 NA 值替换为 -0.873,将第 4/5 个替换为平均值 -0.497+53.200。

谢谢!

t <- c(NA, -0.873, -0.497, NA, NA, 53.200, NA, NA, NA, 26.100)
==================

添加于 ======================谢谢大家回答这个问题!很抱歉回复晚了。这只是数据帧(10000 * 91(的一部分,为了简化问题,我只从第一列中取出了前10行。我认为大卫和MKR有我期望的结果。

这是一种使用基本 R 的可能矢量化方法(某些步骤可能会改进,但我现在没有时间研究它(

x <- c(NA, -0.873, -0.497, NA, NA, 53.200, NA, NA, NA, 26.100)
# Store a boolean vector of NA locaiotns for firther use
na_vals <- is.na(x)
# Find the NAs location compaed to the non-NAs
start_ind <- findInterval(which(na_vals), which(!na_vals))
# Createa right limit
end_ind <- start_ind + 1L
# Replace zero locations with NAs
start_ind[start_ind == 0L] <- NA_integer_
# Calculate the means and replace the NAs
x[na_vals] <- rowMeans(cbind(x[!na_vals][start_ind], x[!na_vals][end_ind]), na.rm = TRUE)
x
# [1] -0.8730 -0.8730 -0.4970 26.3515 26.3515 53.2000 39.6500 39.6500 39.6500 26.1000

这应该适用于载体两侧的 NA。

此函数根据滚动窗口中从第一个元素到下一个元素的非NA值的平均值,插补向量中NA的值。

t <- c(NA, -0.873, -0.497, NA, NA, 53.200, NA, NA, NA, 26.100)
roll_impute <- function(x){
    n <- length(x)
    res <- x
    for (i in seq_along(x)){
        if (is.na(x[i])){
            res[i] <- mean(rep_len(x, i+1), na.rm = TRUE )
        }
    }
    if (is.na(x[n])) x[n] <- mean(x, na.rm = TRUE)
    res
}
roll_impute(t)
# [1] -0.87300 -0.87300 -0.49700 -0.68500 17.27667 53.20000 17.27667 17.27667 19.48250
# [10] 26.10000

roll_impute() 包括在最后一个元素被NA的情况下更正滚动窗口的代码,以便不回收向量。在您的示例中不是这种情况,但为了概括函数而需要这样做。欢迎对此功能进行任何改进:)它确实使用 for 循环,但不增长任何向量。现在没有简单的方法来避免 for 循环并依赖对象的结构。

一个基于dplyrtidyr的解决方案可以是:

  library(dplyr)
  library(tidyr)
  t <- c(NA, -0.873, -0.497, NA, NA, 53.200, NA, NA, NA, 26.100)
  data.frame(t) %>%
    mutate(last_nonNA = ifelse(!is.na(t), t, NA)) %>%
    mutate(next_nonNA = ifelse(!is.na(t), t, NA)) %>%
    fill(last_nonNA) %>%
    fill(next_nonNA, .direction = "up") %>%
    mutate(t = case_when(
                        !is.na(t)  ~ t,
                        !is.na(last_nonNA) & !is.na(next_nonNA) ~ (last_nonNA + next_nonNA)/2,
                        is.na(last_nonNA) ~ next_nonNA,
                        is.na(next_nonNA) ~ last_nonNA
                        )
           ) %>%
    select(t)
  # t
  # 1  -0.8730
  # 2  -0.8730
  # 3  -0.4970
  # 4  26.3515
  # 5  26.3515
  # 6  53.2000
  # 7  39.6500
  # 8  39.6500
  # 9  39.6500
  # 10 26.1000

注意:它看起来有点复杂,但它可以解决问题。人们可以通过 for 循环实现同样的事情。

最新更新