【问题标题】:fill NA values with mean of preceding and subsequent values用前后值的平均值填充 NA 值
【发布时间】:2020-06-08 15:22:14
【问题描述】:

我正在处理一个包含一些缺失值的天气变量(温度、降水等)数据集。由于我的特定方法(在几天内对这些变量求和),我需要处理数据集中的 NA 值。

当缺少每日值时,我想用前一天和后一天的平均值填充这一天。这里的假设是天气值从一天到另一天是相似的。是的,我意识到这是一个很大的假设。

我开发了以下内容:

maxTemp <- c(13.2, 10.7, NA, 17.9, 6.6, 10, 13, NA, NA, 8.8, 9.9, 14.9, 16.3, NA, 18, 9.9, 11.5, 15.3, 21.7, 23.9, 26.6, 27, 22.3, NA, 17.9)
weather <- as.data.frame(maxTemp)
weather %>% 
  mutate(maxTempNA = if_else(is.na(maxTemp),
                             (lag(maxTemp) + lead(maxTemp))/2,
                             maxTemp))

但是,在某些情况下,我连续几天有两个 NA 值,所以这不起作用。关于编码方法的任何想法,以便当连续有两个(或更多)NA时,平均值使用'bookending'值来填充NA?

最终的结果应该是这样的:

maxTemp <- c(13.2, 10.7, 14.3, 17.9, 6.6, 10, 13, 10.9, 10.9, 8.8, 9.9, 14.9, 16.3, 17.15, 18, 9.9, 11.5, 15.3, 21.7, 23.9, 26.6, 27, 22.3, 20.1, 17.9)

【问题讨论】:

    标签: r replace interpolation na


    【解决方案1】:

    如何使用approxNAs 替换为插值;默认情况下,approx 使用线性插值,因此这应该与您的手动平均替换结果相匹配。

    weather %>%
        mutate(maxTemp_interp = approx(1:n(), maxTemp, 1:n())$y)
    #    maxTemp maxTemp_interp
    # 1     13.2          13.20
    # 2     10.7          10.70
    # 3       NA          14.30
    # 4     17.9          17.90
    # 5      6.6           6.60
    # 6     10.0          10.00
    # 7     13.0          13.00
    # 8       NA          11.60
    # 9       NA          10.20
    # 10     8.8           8.80
    # 11     9.9           9.90
    # 12    14.9          14.90
    # 13    16.3          16.30
    # 14      NA          17.15
    # 15    18.0          18.00
    # 16     9.9           9.90
    # 17    11.5          11.50
    # 18    15.3          15.30
    # 19    21.7          21.70
    # 20    23.9          23.90
    # 21    26.6          26.60
    # 22    27.0          27.00
    # 23    22.3          22.30
    # 24      NA          20.10
    # 25    17.9          17.90
    

    我在这里创建了一个新列,以便于与原始数据进行比较。


    更新

    Markus 在 cmets 中指出(感谢 @markus),要重现您的预期输出,您实际上需要 method = "constant"f = 0.5

    weather %>%
        mutate(maxTemp_interp = approx(1:n(), maxTemp, 1:n(), method = "constant", f = 0.5)$y)
    #    maxTemp maxTemp_interp
    # 1     13.2          13.20
    # 2     10.7          10.70
    # 3       NA          14.30
    # 4     17.9          17.90
    # 5      6.6           6.60
    # 6     10.0          10.00
    # 7     13.0          13.00
    # 8       NA          10.90
    # 9       NA          10.90
    # 10     8.8           8.80
    # 11     9.9           9.90
    # 12    14.9          14.90
    # 13    16.3          16.30
    # 14      NA          17.15
    # 15    18.0          18.00
    # 16     9.9           9.90
    # 17    11.5          11.50
    # 18    15.3          15.30
    # 19    21.7          21.70
    # 20    23.9          23.90
    # 21    26.6          26.60
    # 22    27.0          27.00
    # 23    22.3          22.30
    # 24      NA          20.10
    # 25    17.9          17.90
    

    【讨论】:

    • 预期输出略有不同(注意第 8 行和第 9 行)。你需要approx(maxTemp, method = "const", f = .5, n = length(maxTemp))$y
    • 感谢@Maurits Evers。我意识到线性插值并不是我最初的想法,但它可能更适合我有多个 NA 值的情况。
    • @markus 感谢您指出这一点;我没有意识到输出不匹配(OP 在编辑中添加了输出)。我已经进行了编辑。
    • @tnt 是的,直到 Markus 发表评论,我才意识到输出不匹配。您可以使用approxmethod = "const" 重现您的预期输出(请参阅他的评论)。我已经进行了编辑。
    【解决方案2】:

    如果您想使用最近的非 NA 值的平均值来回移动,您可以使用 data.table::nafill() 之类的东西来向下和向上填充值,然后取平均值:

    weather$prevTemp = data.table::nafill(weather$maxTemp, type = "locf")
    weather$nextTemp = data.table::nafill(weather$maxTemp, type = "nocb")
    weather$maxTemp[is.na(weather$maxTemp)] = ((weather$prevTemp + weather$nextTemp) / 2)[is.na(weather$maxTemp)]
    

    【讨论】:

      猜你喜欢
      • 2019-03-31
      • 1970-01-01
      • 1970-01-01
      • 2020-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-04
      • 2021-10-25
      相关资源
      最近更新 更多