【问题标题】:Drop Multiple Columns in R在 R 中删除多列
【发布时间】:2021-06-10 16:57:35
【问题描述】:

我有 80k 行和 874 列的数据。其中一些列是空的。我在 for 循环中使用 sum(is.na) 来确定空列的索引。由于第一列不为空,如果 sum(is.na) 等于第一列的行数,则表示该列为空。

for (i in 1:ncol(loans)){
  if (sum(is.na(loans[i])) == nrow(loans[1])){
      print(i)
  }
}

现在我知道空列的索引,我想从数据中删除它们。我曾考虑将这些索引存储在一个数组中并将它们放入一个循环中,但我认为它不会起作用,因为带有数据的列将替换空列。我怎样才能放下它们?

【问题讨论】:

    标签: r


    【解决方案1】:

    您应该尝试为您的问题提供一个玩具数据集。

    loans <- data.frame(
      a = c(NA, NA, NA),
      b = c(1,2,3),
      c = c(1,2,3),
      d = c(1,2,3),
      e = c(NA, NA, NA)
    )
    
    
    loans[!sapply(loans, function(col) all(is.na(col)))]
    

    sapply 循环遍历loans 的列,并应用匿名函数检查所有元素是否为 NA。然后它将输出强制转换为一个向量,在这种情况下是逻辑的。

    tidyverse 选项:

    loans[!purrr::map_lgl(loans, ~all(is.na(.x)))]
    
    

    【讨论】:

      【解决方案2】:

      这行得通吗:

      df <- data.frame(col1 = rep(NA, 5),
                       col2 = 1:5,
                       col3 = rep(NA,5),
                       col4 = 6:10)
      df
        col1 col2 col3 col4
      1   NA    1   NA    6
      2   NA    2   NA    7
      3   NA    3   NA    8
      4   NA    4   NA    9
      5   NA    5   NA   10
      df[,which(colSums(df, na.rm = TRUE) == 0)] <- NULL
      df
        col2 col4
      1    1    6
      2    2    7
      3    3    8
      4    4    9
      5    5   10
      

      另一种方法:

      df[!apply(df, 2, function(x) all(is.na(x)))]
        col2 col4
      1    1    6
      2    2    7
      3    3    8
      4    4    9
      5    5   10
      

      【讨论】:

      • 如果列中的所有内容都为 0,colSums(df, na.rm = TRUE) 不会计算为 0?
      • @zerz,它会,但考虑到 OP 的数据帧有 874 列和 80k 行,发生这种情况的可能性非常小。添加了另一种方法来解决这个问题。
      • 还有:df[-which(colSums(df, na.rm = TRUE) == 0)]
      【解决方案3】:

      dplyr 解决方案:

      df %>%
        select_if(!colSums(., na.rm = TRUE) == 0)
      

      【讨论】:

        【解决方案4】:

        您可以尝试使用if elsefor loops 之类的基本技能来解决几乎所有问题,但缺点是速度较慢。

        # evaluate each column, if a column meets your condition, remove it, then next
        for (i in 1:length(loans)){
          if (sum(is.na(loans[,i])) == nrow(loans)){
            loans[,i] <- NULL
          }
        }
        

        【讨论】:

        • 这里的问题是,如果一个空列被删除,下一个有数据的列正在替换它。因此,我想,在每次迭代中,您都有可能删除包含数据的列。
        • @VolkanDemir 好吧,我明白你的担忧。但是“if”语句决定了何时应该删除列,因此无论如何,包含数据的列都不会受到影响。
        • @VolkanDemir 因为您担心下一列数据正在替换已删除的数据。其实我以前从来没有想过这个。如果您使用小样本数据来测试我的方法,您就会知道它确实有效。但是你提出了一个很好的观点,我可能会就此提出一个问题。谢谢!
        猜你喜欢
        • 1970-01-01
        • 2016-06-20
        • 1970-01-01
        • 2014-08-26
        • 2020-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多