【问题标题】:Replace NA with group value in loop across multiple columns在多列的循环中将 NA 替换为组值
【发布时间】:2020-07-04 20:19:36
【问题描述】:

我想将 NA 替换为组值(不是平均值或中值,因为某些列是字符或因子),并且我想为所有使用相同组的列列表执行此操作。

样本数据:

ID <- c(1,1,1,2,2,2,3,3)
V1 <- c(NA,"HEJ",NA,"BOS","BOS",NA,"IB","IB")
V2 <- c(700,700,NA,3000,NA,NA,NA,1000)
V3 <- c(NA,NA,3,1,1,1,2,NA)
V4 <- c(NA,NA,NA,NA,NA,"LA",NA,"FE")
mydf <- data.frame(ID,V1,V2,V3,V4)

> mydf
  ID   V1   V2 V3   V4
1  1 <NA>  700 NA <NA>
2  1  HEJ  700 NA <NA>
3  1 <NA>   NA  3 <NA>
4  2  BOS 3000  1 <NA>
5  2  BOS   NA  1 <NA>
6  2 <NA>   NA  1   LA
7  3   IB   NA  2 <NA>
8  3   IB 1000 NA   FE

所以我知道如果我只想为一列这样做,我会:

setDT(mydf)[, V1:= 
                V1[!is.na(V1)][1L],
                by = ID]

然后得到:

> mydf
   ID  V1   V2 V3   V4
1:  1 HEJ  700 NA <NA>
2:  1 HEJ  700 NA <NA>
3:  1 HEJ   NA  3 <NA>
4:  2 BOS 3000  1 <NA>
5:  2 BOS   NA  1 <NA>
6:  2 BOS   NA  1   LA
7:  3  IB   NA  2 <NA>
8:  3  IB 1000 NA   FE

但是我有很多列,所以我需要把它放在某种循环中。

期望的输出:

> mydf
   ID  V1   V2 V3   V4
1:  1 HEJ  700  3 <NA>
2:  1 HEJ  700  3 <NA>
3:  1 HEJ  700  3 <NA>
4:  2 BOS 3000  1   LA
5:  2 BOS 3000  1   LA
6:  2 BOS 3000  1   LA
7:  3  IB 1000  2   FE
8:  3  IB 1000  2   FE

这是我没有运气的尝试:

names <- colnames(mydf[,-c(1)])

for(j in seq_along(nm1)){

   set(mydf,
       i = which(is.na(mydf[[names[j]]])),
       j = names[j],
       value = mydf[[names[j]]][is.na(mydf[[names[j]]])])
}

我也试过这个:

mydf[,-c(1] <- lapply(mydf, function(x) 
  replace(x, is.na(x), x[!is.na(x)]))

> mydf
  ID V1  V2   V3 V4
1  1  1 HEJ  700  3
2  1  1 HEJ  700  1
3  1  1 BOS  700  3
4  2  2 BOS 3000  1
5  2  2 BOS  700  1
6  2  2 BOS 3000  1
7  3  3  IB 1000  2
8  3  3  IB 1000  1

很抱歉,如果我问的问题已经存在但我无法找到它。我希望有人可以帮我清理我凌乱的数据:)

【问题讨论】:

    标签: r loops replace


    【解决方案1】:

    我们可以从zoo使用na.locf

    library(data.table)
    setDT(df1)[, na.locf(.SD), by = ID, .SDcols = V2:V4]
    

    【讨论】:

      【解决方案2】:

      我们可以使用.SDcols 将函数应用于多个列。

      library(data.table)
      
      cols <- names(mydf[-1])
      setDT(mydf)
      
      mydf[, (cols):= lapply(.SD, function(x) 
               replace(x, is.na(x), x[!is.na(x)][1])),.SDcols = cols, by = ID]
      mydf
      
      #   ID  V1   V2 V3   V4
      #1:  1 HEJ  700  3 <NA>
      #2:  1 HEJ  700  3 <NA>
      #3:  1 HEJ  700  3 <NA>
      #4:  2 BOS 3000  1   LA
      #5:  2 BOS 3000  1   LA
      #6:  2 BOS 3000  1   LA
      #7:  3  IB 1000  2   FE
      #8:  3  IB 1000  2   FE
      

      【讨论】:

      • 感谢它有效,但它会覆盖那些没有 NA 的列,我不希望这样,所以我认为对于我的情况,填充效果更好。不过谢谢。我一直在寻找这样的东西。
      • @LouiseSørensen 更新了答案以仅替换 NA 值。
      【解决方案3】:

      dplyrtidyr 可能是:

      mydf %>%
       group_by(ID) %>%
       fill(-ID, .direction = "downup")
      
           ID V1       V2    V3 V4   
        <dbl> <fct> <dbl> <dbl> <fct>
      1     1 HEJ     700     3 <NA> 
      2     1 HEJ     700     3 <NA> 
      3     1 HEJ     700     3 <NA> 
      4     2 BOS    3000     1 LA   
      5     2 BOS    3000     1 LA   
      6     2 BOS    3000     1 LA   
      7     3 IB     1000     2 FE   
      8     3 IB     1000     2 FE 
      

      【讨论】:

      • 编辑:询问如果底部值为 NA 是否有效,但我可以看到我的示例数据已经有这样的列大小写 (V3)
      • 你能详细说明这个问题吗?我不确定我是否理解:)
      • 它不适用于我的示例数据..我收到错误“match.arg(.direction) 中的错误:'arg' 应该是“down”、“up”之一”
      • 上下都试过了,都没有提供想要的输出
      • 这个参数比较新,尝试更新到最新版tidyr
      猜你喜欢
      • 2021-02-26
      • 2018-09-11
      • 2021-07-08
      • 2017-09-13
      • 1970-01-01
      • 2021-09-24
      • 2020-04-23
      • 2021-08-10
      • 2022-10-04
      相关资源
      最近更新 更多