Reputation: 437
I would like to unnest this dataframe.
df <- tibble(
bears = c(1,2,3),
eagles = tibble(
talons = c(2,3,4),
beaks = c("x","y","z")
)
)
So that it looks like
tibble(
bears = c(1,2,3),
talons = c(2,3,4),
beaks = c("x","y","z")
)
I have tried using unnest
and unnest_wider
, flatten
and unlist
but to no avail.
If I run, for example,
test <- df %>%
unnest_wider(eagles, names_sep = "_")
The error is
Error: Assigned data `map(data[[col]], vec_to_wide, col = col, names_sep = names_sep)` must be compatible with existing data.
x Existing data has 3 rows.
x Assigned data has 2 rows.
ℹ Only vectors of size 1 are recycled.
I'm not sure how to resolve this error. Thanks!
Upvotes: 9
Views: 3202
Reputation: 285
Using unpack
from tidyr
does the job I think:
df <- tibble(
bears = c(1,2,3),
eagles = tibble(
talons = c(2,3,4),
beaks = c("x","y","z")
)
)
tidyr::unpack(df, cols=c(eagles))
Output:
# A tibble: 3 x 3
bears talons beaks
<dbl> <dbl> <chr>
1 1 2 x
2 2 3 y
3 3 4 z
If you want to keep "eagles", do
unpack(df, cols=c(eagles), names_sep = "_")
Upvotes: 5
Reputation: 440
An alternative solution that might help people who want to figure out why unnesting does not work: unnest()
works on list
-columns of data frames. So if the original df
is changed to contain a list column, everything works as intended by the OP.
df <- tibble(
bears = c(1,2,3),
eagles = list(tibble(
talons = c(2,3,4),
beaks = c("x","y","z")
))
)
unnest(df, eagles)
Upvotes: 3
Reputation: 887501
We can use reduce
with tibble
library(purrr)
df1 <- bind_cols(df[1], reduce(df[-1], tibble))
str(df1)
#tibble [3 × 3] (S3: tbl_df/tbl/data.frame)
# $ bears : num [1:3] 1 2 3
# $ talons: num [1:3] 2 3 4
# $ beaks : chr [1:3] "x" "y" "z"
Or if we need to rename
library(dplyr)
library(stringr)
df %>%
select(where(is.tibble)) %>%
imap_dfc(~ set_names(.x, str_c(.y, '_', names(.x)))) %>%
bind_cols(df %>%
select(where(negate(is.tibble))), .)
# A tibble: 3 x 3
# bears eagles_talons eagles_beaks
# <dbl> <dbl> <chr>
#1 1 2 x
#2 2 3 y
#3 3 4 z
Or using
df %>%
reduce(data.frame)
Or an easier option is do.call
in base R
df1 <- do.call(data.frame, df)
str(df1)
#'data.frame': 3 obs. of 3 variables:
# $ bears : num 1 2 3
# $ eagles.talons: num 2 3 4
# $ eagles.beaks : chr "x" "y" "z"
Upvotes: 8