Search code examples
rdataframetidyr

Pivot wider in R return list instead of data frame


i have a data frmae in R called df :

 df
# A tibble: 20 × 2
# Groups:   Professional_Assistance_Diet, How_successful_diet [9]
   var           val            
   <fct>         <fct>          
 1 No            Successful     
 2 I do not know Neutral        
 3 I do not know Very Successful
 4 No            Successful     
 5 No            Successful     
 6 I do not know Very Successful
 7 No            Neutral        
 8 I do not know Successful     
 9 I do not know Neutral        
10 Yes           Very Successful
11 Yes           Successful     
12 No            Not Successful 
13 I do not know Very Successful
14 I do not know Not Successful 
15 No            Not Successful 
16 I do not know Neutral        
17 I do not know Successful     
18 I do not know Neutral        
19 No            Neutral        
20 Yes           Very Successful

when i try to pivot wider it i receive :

> df %>%
+   pivot_wider(
+     names_from = var,
+     values_from = val
+   )
# A tibble: 1 × 3
  No        `I do not know` Yes      
  <list>    <list>          <list>   
1 <fct [7]> <fct [10]>      <fct [3]>
Warning message:
Values from `val` are not uniquely identified; output will contain list-cols.
• Use `values_fn = list` to suppress this warning.
• Use `values_fn = {summary_fun}` to summarise duplicates.
• Use the following dplyr code to identify duplicates.
  {data} |>
  dplyr::summarise(n = dplyr::n(), .by = c(var)) |>
  dplyr::filter(n > 1L) 

why ?

data

df = structure(list(var = structure(c(3L, 2L, 2L, 3L, 3L, 2L, 3L, 
2L, 2L, 4L, 4L, 3L, 2L, 2L, 3L, 2L, 2L, 2L, 3L, 4L), levels = c("", 
"I do not know", "No", "Yes"), class = "factor"), val = structure(c(4L, 
3L, 5L, 4L, 4L, 5L, 3L, 4L, 3L, 5L, 4L, 2L, 5L, 2L, 2L, 3L, 4L, 
3L, 3L, 5L), levels = c("Not at all Successful", "Not Successful", 
"Neutral", "Successful", "Very Successful"), class = "factor")), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -20L), groups = structure(list(
    Professional_Assistance_Diet = structure(c(2L, 2L, 2L, 2L, 
    3L, 3L, 3L, 4L, 4L), levels = c("", "i do not know", "No", 
    "Yes"), class = "factor"), How_successful_diet = structure(c(2L, 
    3L, 4L, 5L, 2L, 3L, 4L, 4L, 5L), levels = c("Not at all Successful", 
    "Not Successful", "Neutral", "Successful", "Very Successful"
    ), class = "factor"), .rows = structure(list(14L, c(2L, 9L, 
    16L, 18L), c(8L, 17L), c(3L, 6L, 13L), c(12L, 15L), c(7L, 
    19L), c(1L, 4L, 5L), 11L, c(10L, 20L)), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -9L), .drop = TRUE))

Solution

  • If you just want to avoid warnings, you can simply specify values_fn, e.g., values_fn = list

    df %>%
      pivot_wider(
        names_from = var,
        values_from = val,
        values_fn = list
      )
    

    which gives

    # A tibble: 1 × 3
      No        `I do not know` Yes
      <list>    <list>          <list>   
    1 <fct [7]> <fct [10]>      <fct [3]>
    

    Otherwise, you can use table instead, rather than pivot_wider

    df %>%
      {
        t(table(.))
      }
    

    which shows

                           var
    val                       I do not know No Yes
      Not at all Successful 0             0  0   0
      Not Successful        0             1  2   0
      Neutral               0             4  2   0
      Successful            0             2  3   1
      Very Successful       0             3  0   2