【问题标题】:Expand number range to the individual numbers [duplicate]将数字范围扩展到单个数字[重复]
【发布时间】:2020-08-05 17:29:17
【问题描述】:

不知道如何命名这个问题,所以如果有更好的建议,请编辑


假设我们有这个数据框:

数据集

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 展开。

【问题讨论】:

    标签: r dataframe expand


    【解决方案1】:

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

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

    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)。如果您的数据框很大,这可能会带来巨大的性能提升(在这个小例子中不会)

    【讨论】:

    • 谢谢,另一个答案很快,但我的完整数据集太慢了。请参阅我对另一个答案的评论,当我想包含除 label 之外的多个列时,这是如何工作的(顺便说一句,我的 label 列不是唯一的,所以我生成了行号)
    • 你想要的是by = c('rn','label','x','y')吗?如果你想真正加速你的程序,试试data.table::setkeyv(df, 'rn')。在进行扩展之前
    • 这很棒。谢谢!
    猜你喜欢
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    • 2012-05-30
    • 1970-01-01
    相关资源
    最近更新 更多