【问题标题】:replace NAs with previous or following values for big dataframes用大数据帧的前一个或后一个值替换 NA
【发布时间】:2020-06-19 17:31:01
【问题描述】:

我有一个 1500 obs 的 df。以及超过 600 个变量。 df 中有很多 NA,到目前为止我还没有找到替换它们的解决方案。我希望 NA 采用以前的值。如果没有之前的值,就取下面的值。

不幸的是,我已经尝试了一些解决方案,例如na.locf 等,但都没有成功。我有一个适用于平均值的解决方案。我只是无法以解决我的问题的方式重写它。

for (i in seq_len(ncol(df))) {
  df[is.na(df[,i]), i] <- mean(df[,i], na.rm = TRUE)
}

也许这里有人已经使用它并且可以帮助我。

这是一个例子:

            Share1 Share2  Share3 Share4 Share5
2016-01-04 49.5010 21.640 90.0100 93.676     NA
2016-01-05 49.7855 21.987 88.5695 92.329 82.459
2016-01-06 49.0595     NA 87.4735 88.601 81.432
2016-01-07 47.7785     NA 82.8735 83.725 78.934
2016-01-08 47.7435 20.260 82.9275 82.609 79.000
2016-01-09      NA 20.380 83.0530 83.503     NA
2016-01-10 47.7770 20.475 82.9860 83.325 79.645
2016-01-11 48.8095 20.844 83.0320 83.513 78.672
2016-01-12 48.9545     NA 83.7325 85.732 81.090
2016-01-13 48.0195 20.464 82.6305 81.151 81.178

【问题讨论】:

    标签: r dataframe na


    【解决方案1】:

    R 的“惯用”方式是使用 lapply 来完成您的要求:

    df[] <- lapply(df, function(x) zoo::na.locf(zoo::na.locf(x, na.rm = FALSE), fromLast = TRUE))
    df
    #             Share1 Share2  Share3 Share4 Share5
    # 2016-01-04 49.5010 21.640 90.0100 93.676 82.459
    # 2016-01-05 49.7855 21.987 88.5695 92.329 82.459
    # 2016-01-06 49.0595 21.987 87.4735 88.601 81.432
    # 2016-01-07 47.7785 21.987 82.8735 83.725 78.934
    # 2016-01-08 47.7435 20.260 82.9275 82.609 79.000
    # 2016-01-09 47.7435 20.380 83.0530 83.503 79.000
    # 2016-01-10 47.7770 20.475 82.9860 83.325 79.645
    # 2016-01-11 48.8095 20.844 83.0320 83.513 78.672
    # 2016-01-12 48.9545 20.844 83.7325 85.732 81.090
    # 2016-01-13 48.0195 20.464 82.6305 81.151 81.178
    

    内部的zoo::na.locf 需要na.rm=FALSE,因为没有它Share5 的第一个元素将被剥离:

    lengths(lapply(df, zoo::na.locf))
    # Share1 Share2 Share3 Share4 Share5 
    #     10     10     10     10      9 
    lengths(lapply(df, zoo::na.locf, na.rm = FALSE))
    # Share1 Share2 Share3 Share4 Share5 
    #     10     10     10     10     10 
    

    如果您更喜欢 for 循环,那么也许

    for (i in seq_along(df)) {
      df[[i]] <- zoo::na.locf(zoo::na.locf(df[[i]], na.rm = FALSE), fromLast = TRUE)
    }
    

    (意识到seq_along(df) 实际上与seq_len(ncol(df)) 相同。)

    正如@G.Grothendieck 刚刚提醒我的那样,zoo:::na.locf 有一个适用于整个帧的方法,所以上面可以简化为

    na.locf(na.locf(df, na.rm = FALSE), fromLast = TRUE)
    

    【讨论】:

    • na.locf(na.locf(df, na.rm = FALSE), fromLast = TRUE)
    • data.table::setnafill: setnafill(setnafill(d, type = "locf"), type = "nocb")
    【解决方案2】:

    您还可以使用 tidyr 包中的函数 fill 函数,将参数 .direction 指定为 .direction = "downup"。要将函数一次应用于所有列,您可以将列指定为 tidy-selector everything(),它从当前选择上下文中选择所有列。

    所以,在你的情况下,它会是

    df <- fill(df, everything(), .direction = "downup")
    

    要了解更多关于fill 函数的信息,请访问this,要了解更多关于everything() 函数的信息,请访问that

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 2016-07-24
      • 2015-04-25
      • 1970-01-01
      • 2021-05-29
      • 2021-06-27
      相关资源
      最近更新 更多