【问题标题】:R delete Dataframe columns with specific rows conditionsR删除具有特定行条件的Dataframe列
【发布时间】:2021-08-17 18:58:34
【问题描述】:

我有一个空值和 NA 值的数据框,如下所示:

> DF_datos
 
   V1  V2  V3  V4  V5 V6 
3 aaa aaa             NA
4  bb  bb  70  80     NA
5  cc  cc  80  80     NA
6 ddd ddd             NA  

我想删除第二行或第三行包含空值或 NA 值的所有列,而不在数据帧上循环。使用子集函数或类似的东西...... 我想要的结果是:

> DF_datos
 
   V1  V2  V3  V4 
3 aaa aaa           
4  bb  bb  70  80   
5  cc  cc  80  80    
6 ddd ddd     

     
                                         

【问题讨论】:

    标签: r dataframe rows na is-empty


    【解决方案1】:

    我们可以将tidyverse 与来自dplyrselect 一起使用。在select中,指定where中的逻辑表达式,检查待选列中是否有any非NA(!is.na(.))和any非空(nzchar)元素

    library(dplyr)
    DF_datos %>%
          select(where(~ any(!is.na(.))&any(nzchar(.))))
    

    -输出

    #   V1  V2 V3 V4
    #3 aaa aaa      
    #4  bb  bb 70 80
    #5  cc  cc 80 80
    #6 ddd ddd      
    

    如果我们只需要检查第 2 行或第 3 行

    DF_datos %>%
      slice(2:3) %>% 
      select(where(~ any(!is.na(.))&any(nzchar(.)))) %>% 
      names %>% 
      select(DF_datos, .)
    

    或者使用相同的逻辑从base R (R 4.1.0) 使用Filter

    Filter(\(x) any(!is.na(x)) & any(nzchar(x)), DF_datos)
    

    -输出

    #   V1  V2 V3 V4
    #3 aaa aaa      
    #4  bb  bb 70 80
    #5  cc  cc 80 80
    #6 ddd ddd      
    

    或者对于第 2 行和第 3 行

    Filter(\(x) any(!is.na(x)) & any(nzchar(x)), DF_datos[2:3,]) |>
          names() |>
          {\(x) subset(DF_datos, select = x)}()
    

    或者通过检查复合逻辑表达式的sum是否大于0来使用sum而不是any

    Filter(\(x) sum(!is.na(x) & nzchar(x)) > 0, DF_datos)
    

    在早期的R 版本中使用

    Filter(function(x) any(!is.na(x)) & any(nzchar(x)), DF_datos)
    

    注意:上述所有选项都很有效,因为它会在列上循环,并且内存效率很高,因为它不会将表达式应用于整个数据集

    更新

    根据 cmets,如果第 2 行或第 3 行中有任何 NA 或空白,则 OP 想要删除列。

    DF_datos$V6 <- c(NA, NA, 80, NA)
    
    DF_datos %>%
      slice(2:3) %>% 
      select(where(~ all(!is.na(.)) & all(nzchar(.)))) %>% names %>% 
      select(DF_datos, .)
    

    -输出

      V1  V2 V3 V4
    3 aaa aaa      
    4  bb  bb 70 80
    5  cc  cc 80 80
    6 ddd ddd      
    

    或使用Filter

    Filter(\(x) all(!is.na(x)) & all(nzchar(x)), DF_datos[2:3,]) |>
           names() |>
           {\(x) subset(DF_datos, select = x)}()
    #   V1  V2 V3 V4
    #3 aaa aaa      
    #4  bb  bb 70 80
    #5  cc  cc 80 80
    #6 ddd ddd      
    

    数据

    DF_datos <- structure(list(V1 = c("aaa", "bb", "cc", "ddd"), V2 = c("aaa", 
    "bb", "cc", "ddd"), V3 = c("", "70", "80", ""), V4 = c("", "80", 
    "80", ""), V5 = c("", "", "", ""), V6 = c(NA, NA, NA, NA)), row.names = c("3", 
    "4", "5", "6"), class = "data.frame")
    

    【讨论】:

    • 谢谢,它适用于我的具体示例,但不是我正在寻找的。我尝试使用不同的数据框但不起作用。如果第二或第三行有任何 NA 或空值,则删除该位置的列。
    • @Mantanamm 你的逻辑应该符合DF_datos %&gt;% slice(2:3) %&gt;% select(where(~ any(!is.na(.))&amp;any(nzchar(.)))) %&gt;% names %&gt;% select(DF_datos, .)
    • 是的,完全同意。也许我最初的例子不够清楚
    • @Mantanamm 我更新了帖子,它适用于第 2 行和第 3 行的示例。请检查我的更新
    • 我测试了不同的情况,它可以工作,谢谢!!
    【解决方案2】:

    使用colSums -

    DF_datos[colSums(is.na(DF_datos) | DF_datos == '') != nrow(DF_datos)]
    
    #   V1  V2 V3 V4
    #3 aaa aaa      
    #4  bb  bb 70 80
    #5  cc  cc 80 80
    #6 ddd ddd      
    

    另一种写法是-

    DF_datos[colSums(!is.na(DF_datos) & DF_datos != '') != 0]
    

    【讨论】:

      猜你喜欢
      • 2016-10-04
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2020-12-19
      • 1970-01-01
      • 1970-01-01
      • 2022-06-15
      相关资源
      最近更新 更多