rdataframedplyrtidyr

Pivot Wider without unique ID generating NA's


I wanted to restore the iris dataset to original format from longer but getting NA's. Any suggestions?

library(tidyverse)

# pivot_longer
iris_longer <- iris %>%
  pivot_longer(cols = -c(Species),
               names_to = "feature",
               values_to = "value")

# Restoring original structure
iris_longer %>% mutate(row = row_number()) %>% 
  pivot_wider(names_from = feature,
              values_from = value, 
              id_cols = c(row, Species)) %>%
  arrange(row) %>%           # Make sure rows are ordered
  select(-row)  
#> # A tibble: 600 × 5
#>    Species Sepal.Length Sepal.Width Petal.Length Petal.Width
#>    <fct>          <dbl>       <dbl>        <dbl>       <dbl>
#>  1 setosa           5.1        NA           NA          NA  
#>  2 setosa          NA           3.5         NA          NA  
#>  3 setosa          NA          NA            1.4        NA  
#>  4 setosa          NA          NA           NA           0.2
#>  5 setosa           4.9        NA           NA          NA  
#>  6 setosa          NA           3           NA          NA  
#>  7 setosa          NA          NA            1.4        NA  
#>  8 setosa          NA          NA           NA           0.2
#>  9 setosa           4.7        NA           NA          NA  
#> 10 setosa          NA           3.2         NA          NA  
#> # ℹ 590 more rows

Created on 2025-04-08 with reprex v2.1.1


Solution

  • Just create a id column grouped by feature, then pivot_wider.

    res <- iris_longer %>%
      mutate(id = row_number(), .by = feature) %>%
      pivot_wider(names_from = feature, values_from = value) %>%
      relocate(-Species)
    
    res
    # # A tibble: 150 × 6
    #       id Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #    <int>        <dbl>       <dbl>        <dbl>       <dbl> <fct>  
    #  1     1          5.1         3.5          1.4         0.2 setosa 
    #  2     2          4.9         3            1.4         0.2 setosa 
    #  3     3          4.7         3.2          1.3         0.2 setosa 
    #  4     4          4.6         3.1          1.5         0.2 setosa 
    #  5     5          5           3.6          1.4         0.2 setosa 
    #  6     6          5.4         3.9          1.7         0.4 setosa 
    #  7     7          4.6         3.4          1.4         0.3 setosa 
    #  8     8          5           3.4          1.5         0.2 setosa 
    #  9     9          4.4         2.9          1.4         0.2 setosa 
    # 10    10          4.9         3.1          1.5         0.1 setosa 
    # ℹ 140 more rows
    
    all.equal(res[-1], iris, check.attributes = FALSE)
    # [1] TRUE