R删除具有特定行条件的Dataframe列

R delete Dataframe columns with specific rows conditions

我有一个包含空值和 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     

     
                                         

我们可以将 tidyversedplyr 中的 select 一起使用。在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)

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

更新

根据评论,OP 希望删除第 2 行或第 3 行中有任何 NA 或空白的列。

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")

使用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]