Apply unnest to multiplt columns in tibble

I've dataset with about 2000 rows and 110 Columns. After Pivoting (pivot_wider it returns lists of varying lengths in Columns - which is correct behavior.
Now I'm trying to unnest the columns and if I do it per-Column then it works correctly:

medlist %>% unnest(Med.Immunsupressivum, keep_empty=TRUE)

If I try this on multiple columns I can't get it working:

medlist %>% mutate(across(.cols= contains("Med."), unnest)

  • no applicable method for 'unnest' applied to an Object of class "list"
  • However if I use unlist it returns "dplyr internal error"

medlist %>% unnest(.cols = select(starts_with("Med."))))

  • requires a "selecting function" for .cols

This seems illogical to me but maybe I just don't get what I'm missing.

Unfortuonatly I cannot share the dataset.

Thanks in advance
nielsson

Welcome, @nielsson! Can you try medlist %>% unnest(contains("Med."), keep_empty = TRUE)? If not, can you create a dummy dataset that is similar to your dataset?

library(tidyr)
library(dplyr)
library(tibble)

medlist <- tibble(
  patient_id = 1:5,
  age = c(45, 52, 38, 61, 29),

  Med.Immunsupressivum = list(
    c("Tacrolimus", "Prednisone"),
    c("Cyclosporine"),
    character(0), 
    c("Azathioprine", "Mycophenolate", "Prednisone"),
    NULL 
  ),

  Med.Antibiotic = list(
    c("Amoxicillin"),
    character(0),
    c("Azithromycin", "Doxycycline"),
    NULL,
    c("Ciprofloxacin")
  ),

  Med.Antihypertensive = list(
    c("Lisinopril", "Amlodipine"),
    c("Metoprolol"),
    c("Losartan"),
    character(0),
    c("Hydrochlorothiazide")
  )
)

print(medlist)
#> # A tibble: 5 × 5
#>   patient_id   age Med.Immunsupressivum Med.Antibiotic Med.Antihypertensive
#>        <int> <dbl> <list>               <list>         <list>              
#> 1          1    45 <chr [2]>            <chr [1]>      <chr [2]>           
#> 2          2    52 <chr [1]>            <chr [0]>      <chr [1]>           
#> 3          3    38 <chr [0]>            <chr [2]>      <chr [1]>           
#> 4          4    61 <chr [3]>            <NULL>         <chr [0]>           
#> 5          5    29 <NULL>               <chr [1]>      <chr [1]>

result <- medlist %>%
  unnest(Med.Immunsupressivum, keep_empty = TRUE)

print(result)
#> # A tibble: 8 × 5
#>   patient_id   age Med.Immunsupressivum Med.Antibiotic Med.Antihypertensive
#>        <int> <dbl> <chr>                <list>         <list>              
#> 1          1    45 Tacrolimus           <chr [1]>      <chr [2]>           
#> 2          1    45 Prednisone           <chr [1]>      <chr [2]>           
#> 3          2    52 Cyclosporine         <chr [0]>      <chr [1]>           
#> 4          3    38 <NA>                 <chr [2]>      <chr [1]>           
#> 5          4    61 Azathioprine         <NULL>         <chr [0]>           
#> 6          4    61 Mycophenolate        <NULL>         <chr [0]>           
#> 7          4    61 Prednisone           <NULL>         <chr [0]>           
#> 8          5    29 <NA>                 <chr [1]>      <chr [1]>

result_all <- medlist %>%
  unnest(contains("Med."), keep_empty = TRUE)

print(result_all)
#> # A tibble: 9 × 5
#>   patient_id   age Med.Immunsupressivum Med.Antibiotic Med.Antihypertensive
#>        <int> <dbl> <chr>                <chr>          <chr>               
#> 1          1    45 Tacrolimus           Amoxicillin    Lisinopril          
#> 2          1    45 Prednisone           Amoxicillin    Amlodipine          
#> 3          2    52 Cyclosporine         <NA>           Metoprolol          
#> 4          3    38 <NA>                 Azithromycin   Losartan            
#> 5          3    38 <NA>                 Doxycycline    Losartan            
#> 6          4    61 Azathioprine         <NA>           <NA>                
#> 7          4    61 Mycophenolate        <NA>           <NA>                
#> 8          4    61 Prednisone           <NA>           <NA>                
#> 9          5    29 <NA>                 Ciprofloxacin  Hydrochlorothiazide

Created on 2026-07-28 with reprex v2.1.1

Thank you @ivelasq3 for giving me a starter-mimimal working example(mwe).
With your example unnest works nicely with your mwe, however clinical datasets are different.

Here is a mwe which represents a typical anonymized clinical dataset when it's dumped from the hospital-information-system.
Patient_id is unique to the Patient and appeares per every admission in the dataset. Per admission to the hospital a Patient gets a case number (patient_case) which is unique to the case. The rest of the data - like medication - might change over time and contains duplicates.
Unnest seems unable to cope with several admissions (patient_case) of the same patient (patient_id) to the hospital, so unnest throws an error:

library(tidyr)
library(dplyr)
library(tibble)

patients <- c(1:100)
numbers <- c(1000:1999)
ages <- c(18:90)
sexes <- c("male", "female", "diverse")

patlist <- tibble(
  patient_id = patients,
  age = sample(ages, 100, replace = TRUE),
  sex = sample(sexes, 100, replace = TRUE),
  Med_ID = sample(5, 100, replace = TRUE)
)
caselist <- tibble(
  patient_case = sample(numbers, 300, replace = TRUE),
  patient_id = sample(patients, 300, replace=TRUE)
)
patlist <- left_join(patlist, caselist)

medlist <- tibble(
  Med_ID = 1:5,
  Med.Immunsupressive = list(
    c("Tacrolimus", "Prednisone"),
    c("Cyclosporine"),
    character(0),
    c("Azathioprine", "Mycophenolate", "Prednisone"),
    NULL
  ),
  Med.Antibiotic = list(
    c("Amoxicillin"),
    character(0),
    c("Azithromycin", "Doxycycline"),
    NULL,
    c("Ciprofloxacin")
  ),
  Med.Antihypertensive = list(
    c("Lisinopril", "Amlodipine"),
    c("Metoprolol"),
    c("Losartan"),
    character(0),
    c("Hydrochlorothiazide")
  )
)
patlist <- left_join(patlist, medlist) %>% select(-Med_ID) 

patlist %>% unnest()

I've tried several approaches but didn't figure out how to solve this. Is there a tidyverse-way to solve this problem?
Thanks
nielsson

Hi nielsson

I an not exactly clear on the exact output you want and I am not much of a {tidyr} user but would this code with {data.table} help?

# Load packages -----------------------------------------------------------
suppressMessages(library(data.table))
suppressMessages(library(tidyverse))

# Create sample data set ---------------------------------------------------
patients <- c(1:100)
numbers <- c(1000:1999)
ages <- c(18:90)
sexes <- c("male", "female", "diverse")

patlist <- tibble(
  patient_id = patients,
  age = sample(ages, 100, replace = TRUE),
  sex = sample(sexes, 100, replace = TRUE),
  Med_ID = sample(5, 100, replace = TRUE)
)
caselist <- tibble(
  patient_case = sample(numbers, 300, replace = TRUE),
  patient_id = sample(patients, 300, replace=TRUE)
)
patlist <- left_join(patlist, caselist)

medlist <- tibble(
  Med_ID = 1:5,
  Med.Immunsupressive = list(
    c("Tacrolimus", "Prednisone"),
    c("Cyclosporine"),
    character(0),
    c("Azathioprine", "Mycophenolate", "Prednisone"),
    NULL
  ),
  Med.Antibiotic = list(
    c("Amoxicillin"),
    character(0),
    c("Azithromycin", "Doxycycline"),
    NULL,
    c("Ciprofloxacin")
  ),
  Med.Antihypertensive = list(
    c("Lisinopril", "Amlodipine"),
    c("Metoprolol"),
    c("Losartan"),
    character(0),
    c("Hydrochlorothiazide")
  )
)
dat1 <- left_join(patlist, medlist) %>% select(-Med_ID)

# Convert tibble to data.table --------------------------------------------

DT <- as.data.table(dat1)

# Melt and unlist  --------------------------------------------------------

long_DT <- melt(DT, id.vars = "patient_id", 
                measure.vars = c( "Med.Immunsupressive",  "Med.Antibiotic", 
                                  "Med.Antihypertensive"))

result <- long_DT[, .(value = unlist(value)), by = .(patient_id, variable)]

result