【问题标题】:Replacing NA with mean using loop in R用R中的循环替换NA
【发布时间】:2020-04-23 11:42:00
【问题描述】:

我必须在 R 中使用循环来解决这个问题(我知道你可以在没有循环的情况下更轻松地做到这一点,但它适用于学校......)。

所以我有这样的 NA 向量:

trades<-sample(1:500,150,T)
trades<-trades[order(trades)]
trades[sample(10:140,25)]<-NA

我必须创建一个 FOR 循环,它将 NA 替换为 NA 之前的 2 个数字和 NA 之后的 2 个数字的平均值。

这是我能够做到的,使用这样的循环:

for (i in 1:length(trades)) {
  if (is.na(trades[i])==T) {

      trades[i] <- mean(c(trades[c(i-1:2)], trades[c(i+1:2)]), na.rm = T)
     }
  }

但是作业还有另一部分。如果在前面的 2 个或后面的 2 个数字中有 NA,那么你必须用前面的 4 个数字和后面的 4 个数字的平均值替换 NA(我假设删除了 NA)。但我就是无法破解它......我在这个循环中得到了最好的结果:

for (i in 1:length(trades)) {
  if (is.na(trades[i])==T && is.na(trades[c(i-1:2)]==T || is.na(trades[c(i+1:2)]==T))) {
   trades[i] <- mean(c(trades[c(i-1:4)], trades[c(i+1:4)]), na.rm = T)
  }else if (is.na(trades[i])==T){
    trades[i] <- mean(c(trades[c(i-1:2)], trades[c(i+1:2)]))
  }

}

但它仍然错过了一些 NA。

提前感谢您的帮助。

【问题讨论】:

    标签: r loops replace na


    【解决方案1】:

    我们可以从zoo使用na.approx

    library(zoo)
    na.approx(trades)
    

    【讨论】:

    • 非常感谢您抽出宝贵时间。我知道如何做到这一点,但这是学校的作业,其中指定我们必须使用循环来解决它(就像我的解决方案,你可以在下面找到)。
    【解决方案2】:

    这是另一个使用循环的解决方案。我使用来自dplyrleadlag 做了一些代码的快捷方式。首先,我们使用 2 个递归函数来计算超前和滞后和。然后我们使用条件语句来确定是否有任何缺失数据。最后,我们使用递归的输出或前后 4 的总和(去掉 NA)来填充缺失的数据。我会注意到这不是我解决这个问题的方式,但我按照要求使用循环进行了尝试。

    library(dplyr)
    
    r.lag <- function(x, n){
      if (n == 1) return(lag(x = x, n = 1))
      else return( lag(x = x, n = n) +  r.lag(x = x, n = n-1))
    }
    
    r.lead <- function(x, n){
      if (n == 1) return(lead(x = x, n = 1))
      else return( lead(x = x, n = n) +  r.lead(x = x, n = n-1))
    }
    
    lead.vec <- r.lead(trades, 2)
    lag.vec <- r.lag(trades, 2)
    
    output <- vector(length = length(trades))
    for(i in 1:length(trades)){
      if(!is.na(trades[[i]])){
        output[[i]] <- trades[[i]]
      }
      else if(is.na(trades[[i]]) & !is.na(lead.vec[[i]]) & !is.na(lag.vec[[i]])){
        output[[i]] <- (lead.vec[[i]] + lag.vec[[i]])/4
      }
      else
        output[[i]] <- mean(
          c(trades[[i-4]], trades[[i-3]], trades[[i-2]], trades[[i-1]], 
            trades[[i+4]], trades[[i+3]], trades[[i+2]], trades[[i+1]]),
          na.rm = T
          )
    }
    
    tibble(
      original = trades,
      filled = output
    )
    #> # A tibble: 150 x 2
    #>    original filled
    #>       <int>  <dbl>
    #>  1        7      7
    #>  2        7      7
    #>  3       12     12
    #>  4       18     18
    #>  5       30     30
    #>  6       31     31
    #>  7       36     36
    #>  8       NA     40
    #>  9       43     43
    #> 10       50     50
    #> # … with 140 more rows
    

    【讨论】:

      【解决方案3】:

      看来,发帖到 StackOverflow 帮助我解决了问题。

      trades<-sample(1:500,25,T)
      trades<-trades[order(trades)]
      trades[sample(1:25,5)]<-NA
      

      这给了我们:

      [1]  NA  20  24  30  NA  77 188 217 238 252 264 273 296  NA 326 346 362 368  NA  NA 432 451 465 465 490
      

      如果你运行这个循环:

      for (i in 1:length(trades)) {
        if (is.na(trades[i])== T) {
          test1 <- c(trades[c(i+1:2)])
             if (any(is.na(test1))==T) {
              test2 <- c(trades[abs(c(i-1:4))], trades[c(i+1:4)])
              trades[i] <- round(mean(test2, na.rm = T),0)
            }else {
              test3 <- c(trades[abs(c(i-1:2))], trades[c(i+1:2)])
              trades[i] <- round(mean(test3, na.rm = T),0)
            }
          }
        }
      

      它将 NA 更改为:

      [1]  22  20  24  30  80  77 188 217 238 252 264 273 296 310 326 346 362 368 387 410 432 451 465 465 490
      

      所以它的工作原理和预期的差不多。

      感谢您的所有帮助。

      【讨论】:

      • 逻辑似乎与问题描述不符。如果i+1 是na,则代码将使用前4 个和后4 个结果。但是,如果i + 2 不是 na,则代码将仅更新为前 2 和下 2。您需要一个 ``break``` 或使用 any(is.na(test1)) 而不是第二个循环。
      • 谢谢,没有意识到错误。更正了代码。希望现在它是正确的。
      • 好的,下一个改进是无需查看前面的行进行测试。我们知道 ``i-1``` 在找到第一个非 NA 值后总会有一个值。我们知道,因为在前面的循环中,我们给它赋值了。
      • 是的,既然你指出了这一点,那是有道理的......我想我对这个作业感到困惑,它提到了上一个和下一个 2 :D。我已经更改了代码。非常感谢您的宝贵时间。
      • 我最后要打扰你的是子集。 c() 在很大程度上是不需要的。只是trades[i + 1:2] 和你的另一个trades[abs(i + c(-(1:2), 1:2))]。您可能会作弊并使用i + -2:2,因为 0 索引将被删除,但这会有些草率
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-26
      • 2017-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-17
      相关资源
      最近更新 更多