Home > Net >  Pivot data from wide to long with table containing `from` and `to` columns representing a sequence o
Pivot data from wide to long with table containing `from` and `to` columns representing a sequence o

Time:12-06

Below is a reprex of the problem including the solution I've come up with. However, I feel like there is a more efficient way of doing this.

Specifically check out the have and want tibbles to see what I am going for. The former has columns from and to that should translate to the year column in the latter.

library(tidyverse)

have <- tribble(
  ~V1, ~V2, ~from, ~to,
  "a", "b", 2010, 2013,
  "c", "d", 2010, 2010,
  "c", "e", 2011, 2013
)

have
#> # A tibble: 3 × 4
#>   V1    V2     from    to
#>   <chr> <chr> <dbl> <dbl>
#> 1 a     b      2010  2013
#> 2 c     d      2010  2010
#> 3 c     e      2011  2013

want <- list()

for(i in 1:nrow(have)){
  slice_i <- have %>% slice(i) 
  
  seqtab_i <- tibble(year = seq(slice_i$from, slice_i$to))
  
  want[[i]] <- slice_i %>% 
    select(-from, -to) %>% 
    bind_cols(seqtab_i)
}

want <- bind_rows(want)
want
#> # A tibble: 8 × 3
#>   V1    V2     year
#>   <chr> <chr> <int>
#> 1 a     b      2010
#> 2 a     b      2011
#> 3 a     b      2012
#> 4 a     b      2013
#> 5 c     d      2010
#> 6 c     e      2011
#> 7 c     e      2012
#> 8 c     e      2013

Created on 2022-12-06 with reprex v2.0.2

CodePudding user response:

library(tidyverse)

df  %>% 
  group_by(V1, V2) %>% 
  group_modify(~ add_row(from = first(.$to), .x)) %>%  
  select(-to, year = from) %>%  
  complete(year = first(year):max(year)) %>% 
  distinct_all()

# A tibble: 8 × 3
# Groups:   V1, V2 [3]
  V1    V2     year
  <chr> <chr> <dbl>
1 a     b      2010
2 a     b      2011
3 a     b      2012
4 a     b      2013
5 c     d      2010
6 c     e      2011
7 c     e      2012
8 c     e      2013

CodePudding user response:

You can use map to sequence the years between each row. This will provide you with a list of the years for each applicable row, you can then use unnest() to flatten this.

see code below:

have <- tribble(
  ~V1, ~V2, ~from, ~to,
  "a", "b", 2010, 2013,
  "c", "d", 2010, 2010,
  "c", "e", 2011, 2013
)

df <- have %>%
  mutate(years = map2(from, to, seq)) %>%
  unnest(years) %>%
  select(V1, V2, years)

CodePudding user response:

another solution

library(tidyverse)

have |> 
  rowwise() |> 
  mutate(year = list(seq(from, to))) |> 
  unnest(year) |> 
  select(-c(from, to))
#> # A tibble: 8 × 3
#>   V1    V2     year
#>   <chr> <chr> <int>
#> 1 a     b      2010
#> 2 a     b      2011
#> 3 a     b      2012
#> 4 a     b      2013
#> 5 c     d      2010
#> 6 c     e      2011
#> 7 c     e      2012
#> 8 c     e      2013
  • Related