Remove columns that have one zero value

Viewed 97

I have data frame like this

       class     col2    col3   col4   col5  col6
A      AA         0        5      4      2    15
B      AA         4       10     14     12    25
C      AA         19       2      8      5     3  
D      SS         17       5      5     32    12
E      AA         14       2      12    14    55
F      II         12      17       1     9     0 
G      SS         10      37       8     2    17
H      II         17       7       5     7   14

I want to remove all columns that have zero values

       class         col3    col4   col5     
A      AA              5       4      2   
B      AA               10     14     12    
C      AA                2      8      5      
D      SS                5      5     32    
E      AA                2     12    14    
F      II               17       1     9      
G      SS               37       8     2    
H      II                7       5     7    

So the result I want is just want those columns which do not contain any zeros

Thank you

5 Answers

Based on your description I assume you want to remove rows with zero values, not columns. Here's how you can do it with dplyr:

library(dplyr)

filter(df, across(everything(), ~.!=0))

#> # A tibble: 4 x 6
#>   class  col2  col3  col4  col5  col6
#>   <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 AA        4    10    14    12    25
#> 2 AA       19     2     8     5     3
#> 3 AA       14     2    12    14    55
#> 4 SS       10    37     8     2    17

With the new dataset: base R: In base R we can use Filter and negate any:

Filter(function(x) !any(x %in% 0), df) 
  class col3 col4 col5
A    AA    5    4    2
B    AA   10   14   12
C    AA    2    8    5
D    SS    5    5   32
E    AA    2   12   14
F    II   17    1    9
G    SS   37    8    2
H    II    7    5    7

A possible solution:

df[apply(df == 0, 2, sum) == 0]

#>   class col3 col4 col5
#> A    AA    5    4    2
#> B    AA   10   14   12
#> C    AA    2    8    5
#> D    SS    5    5   32
#> E    AA    2   12   14
#> F    II   17    1    9
#> G    SS   37    8    2
#> H    II    7    5    7

One base R option could be:

df_so[,!sapply(df_so, function(x) any(x == 0))]

#  class col3 col4 col5
#A    AA    5    4    2
#B    AA   10   14   12
#C    AA    2    8    5
#D    SS    5    5   32
#E    AA    2   12   14
#F    II   17    1    9
#G    SS   37    8    2
#H    II    7    5    7

Not my answer, but @user2974951 provided a very fast and straightforward answer as a comment in the Original Post:

df[,colSums(df==0)==0]

Here is another option using a combination of select and where:

library(tidyverse)

df %>%
  select(where(~!any(. == 0)))

Output

  class col3 col4 col5
A    AA    5    4    2
B    AA   10   14   12
C    AA    2    8    5
D    SS    5    5   32
E    AA    2   12   14
F    II   17    1    9
G    SS   37    8    2
H    II    7    5    7

Before select_if was deprecated, we could have written it like:

df %>%
  select_if( ~ !any(. == 0))

Data Table

Here is a possible data.table solution:

library(data.table)

dt <- as.data.table(df)

dt[, .SD,  .SDcols = !names(dt)[(colSums(dt == 0) > 0)]]

Data

df <- structure(list(class = c("AA", "AA", "AA", "SS", "AA", "II", 
"SS", "II"), col2 = c(0L, 4L, 19L, 17L, 14L, 12L, 10L, 17L), 
    col3 = c(5L, 10L, 2L, 5L, 2L, 17L, 37L, 7L), col4 = c(4L, 
    14L, 8L, 5L, 12L, 1L, 8L, 5L), col5 = c(2L, 12L, 5L, 32L, 
    14L, 9L, 2L, 7L), col6 = c(15L, 25L, 3L, 12L, 55L, 0L, 17L, 
    14L)), class = "data.frame", row.names = c("A", "B", "C", 
"D", "E", "F", "G", "H"))
Related