Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove empty lists from a tibble in R

I am trying to remove any list from my tibble that has "<chr [0]>"

library(tidyverse)

df <- tibble(x = 1:3, y = list(as.character()), 
             z=list(as.character("ATC"),as.character("TAC"), as.character()))
df
#> # A tibble: 3 × 3
#>       x y         z        
#>   <int> <list>    <list>   
#> 1     1 <chr [0]> <chr [1]>
#> 2     2 <chr [0]> <chr [1]>
#> 3     3 <chr [0]> <chr [0]>

Created on 2022-02-15 by the reprex package (v2.0.1)

I want my tibble to look like this

#> # A tibble: 3 × 3
#>       x  z        
#>    <int> <list>   
#> 1     1 <chr [1]>
#> 2     2 <chr [1]>
#> 3     3    NA

any help is appreciated

like image 372
LDT Avatar asked Oct 22 '25 15:10

LDT


2 Answers

You can do:

df %>%
  select(where(~!all(lengths(.) == 0))) %>%
  mutate(z = lapply(z, function(x) ifelse(length(x) == 0, NA, x)))

# A tibble: 3 x 2
      x z        
  <int> <list>   
1     1 <chr [1]>
2     2 <chr [1]>
3     3 <lgl [1]>

Note, in your z column you can‘t have list elemtents for row 1 and 2 and a direct logical value NA. The whole column needs to be a list.

If all elements of z have only one element, you can add another line of code with mutate(z = unlist(z)).


TO asked for a more dynamic solution to pass several columns.

Here is an example where I simply created another z2 variable. Generally, you can repeat the recoding for several columns using across.

library(tidyverse)

df <- tibble(x = 1:3, y = list(as.character()), 
             z=list(as.character("ATC"),as.character("TAC"), as.character()),
z2 = z)

df %>%
  select(where(~!all(lengths(.) == 0))) %>%
  mutate(across(starts_with('z'), ~ lapply(., function(x) ifelse(length(x) == 0, NA, x))))

Which gives:

# A tibble: 3 x 3
      x z         z2       
  <int> <list>    <list>   
1     1 <chr [1]> <chr [1]>
2     2 <chr [1]> <chr [1]>
3     3 <lgl [1]> <lgl [1]>
like image 76
deschen Avatar answered Oct 25 '25 04:10

deschen


A two-step way using base R:

df <- tibble(x = 1:3, y = list(as.character()), 
             z=list(as.character("ATC"),as.character("TAC"), as.character()))


df <- df[apply(df, 2, function(x) any(lapply(x, length) > 0))] #Remove empty columns
df[apply(df, 2, function(x) lapply(x, length) == 0)] <- NA #Replace empty lists with NA

df
# A tibble: 3 x 2
      x z        
  <int> <list>   
1     1 <chr [1]>
2     2 <chr [1]>
3     3 <NULL> 
like image 42
Maël Avatar answered Oct 25 '25 05:10

Maël



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!