Unnest data frame list columns
unnest_cross.RdLike tidyr::unnest() but always produces a cartesian product and does not
requires that list columns be "parallel entries ... of compatible sizes".
Arguments
- data
 A data.frame.
- cols
 <
tidy-select> Columns to unnest.- ...
 Arguments passed on to
tidyr::unchop,tidyr::unpackerror_callThe execution environment of a currently running function, e.g.
caller_env(). The function will be mentioned in error messages as the source of the error. See thecallargument ofabort()for more information.keep_emptyBy default, you get one row of output for each element of the list that you are unchopping/unnesting. This means that if there's a size-0 element (like
NULLor an empty data frame or vector), then that entire row will be dropped from the output. If you want to preserve all rows, usekeep_empty = TRUEto replace size-0 elements with a single row of missing values.ptypeOptionally, a named list of column name-prototype pairs to coerce
colsto, overriding the default that will be guessed from combining the individual values. Alternatively, a single empty ptype can be supplied, which will be applied to allcols.names_repairUsed to check that output data frame has valid names. Must be one of the following options:
"minimal": no name repair or checks, beyond basic existence,"unique": make sure names are unique and not empty,"check_unique": (the default), no name repair, but check they are unique,"universal": make the names unique and syntactica function: apply custom name repair.
tidyr_legacy: use the name repair from tidyr 0.8.
a formula: a purrr-style anonymous function (see
rlang::as_function())
See
vctrs::vec_as_names()for more details on these terms and the strategies used to enforce them.
Examples
df <- tibble::tibble(
    n = 1:2,
    interjection = list(c("oh", "wow"), "zap"),
    letter = list(c("a", "b", "c"), "d"),
    keep_list = list("please", c("don't", "unnest"))
)
df
#> # A tibble: 2 × 4
#>       n interjection letter    keep_list
#>   <int> <list>       <list>    <list>   
#> 1     1 <chr [2]>    <chr [3]> <chr [1]>
#> 2     2 <chr [1]>    <chr [1]> <chr [2]>
# Uses tidyselect semantics, like tidyr::unnest()
unnest_cross(df, cols = tidyselect::starts_with("inter"))
#> # A tibble: 3 × 4
#>       n interjection letter    keep_list
#>   <int> <chr>        <list>    <list>   
#> 1     1 oh           <chr [3]> <chr [1]>
#> 2     1 wow          <chr [3]> <chr [1]>
#> 3     2 zap          <chr [1]> <chr [2]>
# Works when list column sizes differ, unlike tidyr::unnest()
tryCatch(
    tidyr::unnest(df, cols = c(interjection, letter)),
    error = function(e) message(e)
)
#> Error in tidyr::unnest(df, cols = c(interjection, letter)): In row 1, can't recycle input of size 2 to size 3.
unnest_cross(df, cols = c(interjection, letter))
#> # A tibble: 7 × 4
#>       n interjection letter keep_list
#>   <int> <chr>        <chr>  <list>   
#> 1     1 oh           a      <chr [1]>
#> 2     1 oh           b      <chr [1]>
#> 3     1 oh           c      <chr [1]>
#> 4     1 wow          a      <chr [1]>
#> 5     1 wow          b      <chr [1]>
#> 6     1 wow          c      <chr [1]>
#> 7     2 zap          d      <chr [2]>
# Always produces a cartesian product, unlike tidyr::unnest()
df2 <- tibble::tibble(
    n = list(1:2, 3L),
    letter = list(c("a", "b"), "c"),
)
df2
#> # A tibble: 2 × 2
#>   n         letter   
#>   <list>    <list>   
#> 1 <int [2]> <chr [2]>
#> 2 <int [1]> <chr [1]>
tidyr::unnest(df2, cols = tidyselect::everything())
#> # A tibble: 3 × 2
#>       n letter
#>   <int> <chr> 
#> 1     1 a     
#> 2     2 b     
#> 3     3 c     
unnest_cross(df2, cols = tidyselect::everything())
#> # A tibble: 5 × 2
#>       n letter
#>   <int> <chr> 
#> 1     1 a     
#> 2     1 b     
#> 3     2 a     
#> 4     2 b     
#> 5     3 c