Is there way to expand rows in a data frame by conditioning on two columns?

53 Views Asked by At

My data structure is as follows:

rad_1 division_num interval
1 2 4
1 3 2
2 3 3

I want to expand the rows by division and interval. If the interval is 4 and the division is 2 then expand the row eight times as 4 x 2 is 8. Similarly, if the interval is 2 and the division is 3 then expand the row 6 times as 2 x 3 is 6.

Code I tried:

dt1[, row_index := 1:.N]

dt1 <- dt1[rep(seq_len(.N), dt1$division), ]

dt1[, new_row := seq_len(division) - 1 + interval * (row_index - 1), by = row_index]

Expected output:

rad_1 division_num interval
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 2 4
1 3 2
1 3 2
1 3 2
1 3 2
1 3 2
1 3 2
2 3 3
2 3 3
2 3 3
2 3 3
2 3 3
2 3 3
2 3 3
2 3 3
2 3 3
3

There are 3 best solutions below

0
Onyambu On BEST ANSWER

You could use tidyr::uncount

 tidyr::uncount(df, division_num * interval)

   rad_1 division_num interval
1      1            2        4
2      1            2        4
3      1            2        4
4      1            2        4
5      1            2        4
6      1            2        4
7      1            2        4
8      1            2        4
9      1            3        2
10     1            3        2
11     1            3        2
12     1            3        2
13     1            3        2
14     1            3        2
15     2            3        3
16     2            3        3
17     2            3        3
18     2            3        3
19     2            3        3
20     2            3        3
21     2            3        3
22     2            3        3
23     2            3        3
0
r2evans On

We can use rep(., times=) for this:

dt1[rep(seq(.N), times = division_num * interval),]
#     rad_1 division_num interval
#     <int>        <int>    <int>
#  1:     1            2        4
#  2:     1            2        4
#  3:     1            2        4
#  4:     1            2        4
#  5:     1            2        4
#  6:     1            2        4
#  7:     1            2        4
#  8:     1            2        4
#  9:     1            3        2
# 10:     1            3        2
# ---                            
# 14:     1            3        2
# 15:     2            3        3
# 16:     2            3        3
# 17:     2            3        3
# 18:     2            3        3
# 19:     2            3        3
# 20:     2            3        3
# 21:     2            3        3
# 22:     2            3        3
# 23:     2            3        3

Data

dt1 <- data.table::as.data.table(structure(list(rad_1 = c(1L, 1L, 2L), division_num = c(2L, 3L, 3L), interval = c(4L, 2L, 3L)), class = c("data.table", "data.frame"), row.names = c(NA, -3L)))
0
Berna Oruç On

An alternative solution is to set the value to expand by creating an object expand:

dt1<- data.table(rad_1= c(1,1,2),
       division_num= c(2,3,3),
       interval= c(4,2,3))
expand <- dt1$division_num * dt1$interval
dt.expanded <- dt1[rep(1:nrow(dt1), expand)]
dt.expanded
    rad_1 division_num interval
 1:     1            2        4
 2:     1            2        4
 3:     1            2        4
 4:     1            2        4
 5:     1            2        4
 6:     1            2        4
 7:     1            2        4
 8:     1            2        4
 9:     1            3        2
10:     1            3        2
11:     1            3        2
12:     1            3        2
13:     1            3        2
14:     1            3        2
15:     2            3        3
16:     2            3        3
17:     2            3        3
18:     2            3        3
19:     2            3        3
20:     2            3        3
21:     2            3        3
22:     2            3        3
23:     2            3        3