使用滚动窗口替换NA值

时间:2018-03-18 20:35:20

标签: r

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

谢谢!

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

=================== ADD ON =================== 谢谢大家回答这个问题!回复晚了非常抱歉。这只是数据帧的一部分(10000 * 91),我只从第一列中取出前10行以简化问题。我认为大卫和MKR的结果是我应该拥有的。

3 个答案:

答案 0 :(得分:2)

此函数根据滚动窗口中从第一个元素到下一个元素的非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循环并依赖于对象的结构现在跳到我的脑海。

答案 1 :(得分:2)

这是一种使用基础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。

答案 2 :(得分:1)

基于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循环可以实现相同的功能。