首页 > 解决方案 > 使用 mutate_at 将 R 中的缺失值替换为从列名中获得的值(如果不缺失)

问题描述

这是一个我一直觉得应该很简单的问题,但让我很难过。我需要替换缺失值,但我需要从不同的相关列标题中查找替换值。

样本数据:

s <- data.frame(Finch=c(1, 5, NA, 2), 
            Station_1_Finch=c(NA, NA, NA, NA), 
            Station_2_Finch=c(NA, NA, 60, NA), 
            Station_3_Finch=c(NA, NA, NA, NA),
            Pigeon=c(NA, 3, 7, NA),
            Station_1_Pigeon=c(25, NA, NA, NA), 
            Station_2_Pigeon=c(NA, NA, 64, NA), 
            Station_3_Pigeon=c(NA, NA, NA, 50))
birds <- c("Finch", "Pigeon")

我需要做的是查找每只鸟的缺失值(我的实际数据中有超过 40 个)并将每个缺失值替换为该鸟的站号,来自列名 - 而不是列中的相应值. 幸运的是,Station 列名称遵循相同的模式并且易于解析。这是我想要的数据:

  Finch Station_1_Finch Station_2_Finch Station_3_Finch Pigeon Station_1_Pigeon Station_2_Pigeon Station_3_Pigeon
1     1              NA              NA              NA      1               25               NA               NA
2     5              NA              NA              NA      3               NA               NA               NA
3     2              NA              60              NA      7               NA               64               NA
4     2              NA              NA              NA      3               NA               NA               50

我认为带有自定义函数的 mutate_at 是最简单的方法,但我无法让它工作。(这是在尝试 lapply 和一个简单的 for 循环之后。)这就是我所拥有的:

birdcleanup <- function(b) {
  rs <- colnames(s)[grepl(pattern = deparse(names(b)[1]), colnames(s)) & 
                         grepl("^Station", colnames(s))]
  for(i in seq_along(rs)) {
    if(!is.na(s[rs[i]])) {
      v <- as.numeric(str_sub(rs[i], start = 9, end = 9))
      print(v)
    }
  }
  return(v)
}

surveytrim %>%
  mutate_at(birds, ~ if_else(is.na(.), birdcleanup(.), .))

我认为 purrr 中的 map 系列函数可能会有所帮助,但是在阅读了这里的文档、小插曲和类似问题之后,我仍然感到困惑。我究竟做错了什么?

标签: rdplyrpurrr

解决方案


这是解决此问题的一种基本 R 方法:

我们可以split.default根据鸟名来分割数据。我们从列名中删除不需要的“Station_number”,只保留鸟名。使用max.col我们找到行中第一个非 NA 值的索引,并用NA该值替换 in bird 列。

s[] <- do.call(cbind, lapply(split.default(s, 
              sub('Station_\\d+_', '', names(s))), function(x) {
          inds <- is.na(x[[1]])
          x[inds, 1] <- max.col(!is.na(x[inds, -1]), 'first')
          x
}))

s
#  Finch Station_1_Finch Station_2_Finch Station_3_Finch Pigeon
#1     1              NA              NA              NA      1
#2     5              NA              NA              NA      3
#3     2              NA              60              NA      7
#4     2              NA              NA              NA      3

#  Station_1_Pigeon Station_2_Pigeon Station_3_Pigeon
#1               25               NA               NA
#2               NA               NA               NA
#3               NA               64               NA
#4               NA               NA               50

推荐阅读