将号码范围扩展到单个号码

Expand number range to the individual numbers

不确定如何给这个问题起标题所以如果有更好的建议请编辑


假设我们有这个数据框:

数据集

df <- data.frame(start = c(10, 20), end = c(15,33), label = c('ex1','ex2'))

看起来像这样:

  start end label
1    10  15   ex1
2    20  33   ex2


我想得到什么
我想从 start --> end 展开,像这样:

  pos label
1   10   ex1
2   11   ex1
3   12   ex1
4   13   ex1
5   14   ex1
6   15   ex1
7   20   ex2
8   21   ex2
9   22   ex2
10  23   ex2
11  24   ex2
12  25   ex2
13  26   ex2
14  27   ex2
15  28   ex2
16  29   ex2
17  30   ex2
18  31   ex2
19  32   ex2
20  33   ex2

我现在拥有的

f <- function(x) {data.frame(pos = x$start:x$end, label = x$label)}
df %>% rowwise() %>% do(f(.))

虽然我的解决方案有效,但我的原始数据集要大得多,我怀疑这是否有效。此外,我想包含比 label 更多的列,所以我想重新训练所有列并展开 startend

我有一个 data.table 的解决方案。

我假设你的 label var 通过观察是独一无二的。否则,您应该使用行号对数据进行分组。

library(data.table)
df <- data.frame(start = c(10, 20), end = c(15,33), label = c('ex1','ex2'))
setDT(df)

df[, seq(.SD[['start']], .SD[['end']]), by = label]
label V1
 1:   ex1 10
 2:   ex1 11
 3:   ex1 12
 4:   ex1 13
 5:   ex1 14
 6:   ex1 15
 7:   ex2 20
 8:   ex2 21
 9:   ex2 22
10:   ex2 23
11:   ex2 24
12:   ex2 25
13:   ex2 26
14:   ex2 27
15:   ex2 28
16:   ex2 29
17:   ex2 30
18:   ex2 31
19:   ex2 32
20:   ex2 33

就效率而言,可能很难找到比专为此目的而设计的 data.table 更快的解决方案。

如果您不能使用 label 作为唯一标识符,您可以使用

df[,'rn' := seq(.N)]

df[, seq(.SD[['start']], .SD[['end']]), by = c('rn','label')]
    rn label V1
 1:  1   ex1 10
 2:  1   ex1 11
 3:  1   ex1 12
 4:  1   ex1 13
 5:  1   ex1 14
 6:  1   ex1 15
 7:  2   ex2 20
 8:  2   ex2 21
 9:  2   ex2 22
10:  2   ex2 23
11:  2   ex2 24
12:  2   ex2 25
13:  2   ex2 26
14:  2   ex2 27
15:  2   ex2 28
16:  2   ex2 29
17:  2   ex2 30
18:  2   ex2 31
19:  2   ex2 32
20:  2   ex2 33

您可以使用 df[,'rn' := NULL]

删除中间行号

效率

data.table带来了很好的加速(在这个例子中,如果你使用一列或两列来分组并不重要)

Unit: microseconds
                                                           expr      min       lq     mean   median       uq
                                  df %>% rowwise() %>% do(f(.)) 1549.408 1808.669 2309.332 2292.525 2555.888
          df[, seq(.SD[["start"]], .SD[["end"]]), by = "label"] 1011.608 1302.249 1555.808 1490.542 1779.543
 df[, seq(.SD[["start"]], .SD[["end"]]), by = c("label", "rn")]  968.124 1095.703 1387.556 1253.023 1592.483
      max neval cld
 7141.964   100   b
 3061.487   100  a 
 2953.598   100  a 

如果你想走得更快,可以设置一个键(?setkeyv)。如果您的数据框很大,这可能会带来巨大的性能提升(在这个小例子中不会)