Xion
Xion

Reputation: 389

How can I break a row to multiple rows based on interval

My data looks like this:

das <- data.frame(val=1:3,
                  beginning =c(10,20,40),
                  end=c(20,40,51))
  val beginning end
1   1        10  20
2   2        20  40
3   3        40  51

I want to break each row to 3 rows by dividing the beginning to end to equal parts. like this

Expected output

> das
  val beginning end
1   1        10  13
2   2        13  16
3   3        16  20
4   4        20  27
5   5        27  34
6   6        34  40
7   7        40  44
8   8        44  48
9   9        48  51

I came across similar questions here, but most of them are w.r.t to date range.

Upvotes: 2

Views: 188

Answers (2)

Aur&#232;le
Aur&#232;le

Reputation: 12819

n_intervals <- 3

rows <- split(das, seq_len(nrow(das)))

res <- do.call(rbind, lapply(rows, function(row) {
  timesplits <- seq(from = row$beginning, 
                    to = row$end, 
                    length.out = n_intervals + 1)
  data.frame(beginning = head(timesplits, -1),
             end = tail(timesplits, -1))
}))

res$val <- seq_len(nrow(res))

#>     beginning      end val
#> 1.1  10.00000 13.33333   1
#> 1.2  13.33333 16.66667   2
#> 1.3  16.66667 20.00000   3
#> 2.1  20.00000 26.66667   4
#> 2.2  26.66667 33.33333   5
#> 2.3  33.33333 40.00000   6
#> 3.1  40.00000 43.66667   7
#> 3.2  43.66667 47.33333   8
#> 3.3  47.33333 51.00000   9

Upvotes: 1

Darren Tsai
Darren Tsai

Reputation: 35554

You can use uncount() in tidyr and then calculate the increment of each val.

library(dplyr)
library(tidyr)

das %>%
  uncount(3) %>% 
  mutate(beginning = beginning + round((end - beginning)/3) * 0:2,
         end = lead(beginning, default = last(end)))

#   val beginning end
# 1   1        10  13
# 2   1        13  16
# 3   1        16  20
# 4   2        20  27
# 5   2        27  34
# 6   2        34  40
# 7   3        40  44
# 8   3        44  48
# 9   3        48  51

Upvotes: 3

Related Questions