【问题标题】:Remove constant columns with or without NAs删除带或不带 NA 的常量列
【发布时间】:2018-01-14 20:12:13
【问题描述】:

我试图让许多 lm 模型在一个函数中工作,我需要自动从我的 data.table 中删除常量列。因此,我只想保留具有两个或多个唯一值的列,不包括 NA

我尝试了在 SO 上找到的几种方法,但我仍然无法删除具有两个值的列:常量和 NA。

我的可重现代码:

library(data.table)
df <- data.table(x=c(1,2,3,NA,5), y=c(1,1,NA,NA,NA),z=c(NA,NA,NA,NA,NA), 
d=c(2,2,2,2,2))

> df
    x  y  z d
1:  1  1 NA 2
2:  2  1 NA 2
3:  3 NA NA 2
4: NA NA NA 2
5:  5 NA NA 2

我的意图是删除 y、z 和 d 列,因为它们是常量,包括在省略 NAs 时只有一个唯一值的 y。

我试过了:

same <- sapply(df, function(.col){ all(is.na(.col))  || all(.col[1L] == .col)})
df1 <- df[ , !same, with = FALSE]


> df1
    x  y
1:  1  1
2:  2  1
3:  3 NA
4: NA NA
5:  5 NA

正如所见,'y' 仍然存在...... 有什么帮助吗?

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    因为你有一个data.table,你可以使用uniqueN 和它的na.rm 参数:

    df[ , lapply(.SD, function(v) if(uniqueN(v, na.rm = TRUE) > 1) v)]
    #     x
    # 1:  1
    # 2:  2
    # 3:  3
    # 4: NA
    # 5:  5
    

    base 的替代方案可能是 Filter(function(x) length(unique(x[!is.na(x)])) &gt; 1, df)

    【讨论】:

    • 完美运行,谢谢。我喜欢这个解决方案,因为它也适用于字符 cols(其他基于方差的解决方案,不要)并且是完整的 data.table。谢谢!顺便问一下,unique 和 uniqueN ... 有什么区别?
    • 感谢您的反馈。关于您的问题,我认为您需要更具体一些,否则我可能只会反刍帮助文本;)
    【解决方案2】:

    在基础r 中有函数Filter 的简单解决方案。会有帮助的。

    library(data.table)
    df <- data.table(x=c(1,2,3,NA,5), y=c(1,1,NA,NA,NA),z=c(NA,NA,NA,NA,NA), 
                     d=c(2,2,2,2,2))
    # Select only columns for which SD is not 0
    > Filter(function(x) sd(x, na.rm = TRUE) != 0, df)
        x
    1:  1
    2:  2
    3:  3
    4: NA
    5:  5
    

    注意:不要忘记使用na.rm = TRUE

    【讨论】:

    • 这是一个很好的答案,但需要一些解释。 Filter 遍历一个列表(在这种情况下,包括一个数据框),返回那些在传递给提供的函数时返回 TRUE (或对其强制执行的东西)的元素。在这种情况下,sd(如其他一些答案中的var)对于不需要的列(Filter 强制为FALSE)将为 0,并且所需的列将是非零数(其中Filter 强制转换为 TRUE)。
    • @alistaire 您的解释非常正确。修改调用以显式返回TRUE 可能会很好(只是为了更好地理解)。
    【解决方案3】:

    检查方差是否为零:

    df[, sapply(df, var, na.rm = TRUE) != 0, with = FALSE]
    #     x
    # 1:  1
    # 2:  2
    # 3:  3
    # 4: NA
    # 5:  5
    

    【讨论】:

      【解决方案4】:

      这是一个选项:

      df[,which(df[,
             unlist(
              sapply(.SD,function(x) length(unique(x[!is.na(x)])) >1))]),
         with=FALSE]
      
          x
      1:  1
      2:  2
      3:  3
      4: NA
      5:  5
      

      对于 data.table 的每一列,我们计算不同 NA 的唯一值的数量。我们只保留具有多个值的列。

      【讨论】:

        【解决方案5】:

        如果你真的要删除这些列,这里有一个解决方案:

        library(data.table)
        dt <- data.table(x=c(1,2,3,NA,5), 
                         y=c(1,1,NA,NA,NA),
                         z=c(NA,NA,NA,NA,NA), 
                         d=c(2,2,2,2,2))
        
        for (col in names(copy(dt))){
            v = var(dt[[col]], na.rm = TRUE)
            if (v == 0 | is.na(v)) dt[, (col) := NULL]
        }
        

        【讨论】:

        • 这与我的解决方案有何不同?
        • @zx8754 区别很明显。在您的方法中,您复制原始数据表,然后构建一个新数据表。我正在通过引用更新原始的data.table,这是一种更data.table 的方式。顺便说一句,当我研究我的解决方案时,我没有看到你的解决方案。
        • 问题不是“如何删除列”而是“如何应用规则删除列”,我使用了 var,而你使用了 var。从问题中您可以看到 OP 已经在对新变量进行子集处理:df1 &lt;- df[ , !same, with = FALSE]
        • @zx8754 再次提醒您,当我在研究我的解决方案时,您没有发布您的解决方案。我确实认为使用var 函数的两个答案都是一个问题。使用sd 函数的第三个答案,本质上是var 函数。两个答案使用了某种unique 函数,您认为它们也有问题吗?我真的不明白你为什么对var函数如此关注?这是很多人能想到的一个很常见的功能。除了这个功能,我的解决方案和你的根本不同。
        【解决方案6】:

        改变一下

        all(is.na(.col)) || all(.col[1L] == .col)

        all(is.na(.col) | .col[1L] == .col)

        最终代码:

        same <- sapply( df, function(.col){ all( is.na(.col) | .col[1L] == .col ) } )
        df1 <- df[,!same, with=F]
        

        结果:

            x
        1:  1
        2:  2
        3:  3
        4: NA
        5:  5
        

        【讨论】:

          【解决方案7】:

          对于删除constant 列,

          1. 数字列:-

            constant_col = [const for const in df.columns if df[const].std() == 0]
            print (len(constant_col))
            print (constant_col)
            
          2. 分类列:-

            constant_col = [const for const in df.columns if len(df[const].unique()) == 1]
            print (len(constant_col))
            print (constant_col)
            

          然后你使用 drop 方法删除列

          【讨论】:

            【解决方案8】:
            library(janitor)
            df %>%
              remove_constant(na.rm = TRUE)
            
                x
            1:  1
            2:  2
            3:  3
            4: NA
            5:  5
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-05-07
              • 2011-08-17
              • 2017-05-04
              • 2021-04-17
              • 2022-12-20
              • 2017-06-12
              • 2013-11-25
              相关资源
              最近更新 更多