【问题标题】:Create counter within consecutive runs of values在值的连续运行中创建计数器
【发布时间】:2013-11-28 17:07:51
【问题描述】:

我希望在每次运行相等值时创建一个序列号,例如出现计数器,一旦当前行中的值与前一行不同,它就会重新启动。

请在下面找到输入和预期输出的示例。

dataset <- data.frame(input = c("a","b","b","a","a","c","a","a","a","a","b","c"))
dataset$counter <- c(1,1,2,1,2,1,1,2,3,4,1,1)
dataset

#    input counter
# 1      a       1
# 2      b       1
# 3      b       2
# 4      a       1
# 5      a       2
# 6      c       1
# 7      a       1
# 8      a       2
# 9      a       3
# 10     a       4
# 11     b       1
# 12     c       1

我的问题与这个问题非常相似:Cumulative sequence of occurrences of values

【问题讨论】:

    标签: r count sequence find-occurrences run-length-encoding


    【解决方案1】:

    你需要使用sequencerle

    > sequence(rle(as.character(dataset$input))$lengths)
     [1] 1 1 2 1 2 1 1 2 3 4 1 1
    

    【讨论】:

    • 干杯,这就像一个魅力!你怎么知道 $lengths 部分?还有其他属性吗? (在 R Docs 中看不到它们)。
    • @Richard,请参阅 ?rle 文档的“价值”部分。返回的两个值(在class“rle”的list 中)是lengthsvalues
    【解决方案2】:

    从 v1.9.8(新闻第 16 条)开始,使用 rowidrleid

    dataset[, counter := rowid(rleid(input))]
    

    计时码:

    set.seed(1L)
    library(data.table)
    DT <- data.table(input=sample(letters, 1e6, TRUE))
    DT1 <- copy(DT)
    
    bench::mark(DT[, counter := seq_len(.N), by=rleid(input)], 
        DT1[, counter := rowid(rleid(input))])
    

    时间安排:

      expression                                              min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
      <bch:expr>                                          <bch:t> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
    1 DT[, `:=`(counter, seq_len(.N)), by = rleid(input)] 613.8ms 613.8ms      1.63    18.8MB     8.15     1     5      614ms
    2 DT1[, `:=`(counter, rowid(rleid(input)))]            60.5ms  71.4ms     12.7     26.4MB    14.5      7     8      553ms
    

    下面编写的函数的一个高效且更直接的版本现在可以在 data.table 包中获得,称为rleid。使用它,它只是:

    setDT(dataset)[, counter := seq_len(.N), by=rleid(input)]
    

    有关用法和示例的更多信息,请参阅?rleid。感谢@Henrik 提出更新这篇文章的建议。


    rle 绝对是最方便的方式(+1 @Ananda's)。但是在更大的数据上可以做得更好(在速度方面)。您可以使用data.table 中的duplistvecseq 函数(未导出),如下所示:

    require(data.table)
    arun <- function(y) {
        w = data.table:::duplist(list(y))
        w = c(diff(w), length(y)-tail(w,1L)+1L)
        data.table:::vecseq(rep(1L, length(w)), w, length(y))
    }
    
    x <- c("a","b","b","a","a","c","a","a","a","a","b","c")
    arun(x)
    # [1] 1 1 2 1 2 1 1 2 3 4 1 1
    

    大数据基准测试:

    set.seed(1)
    x <- sample(letters, 1e6, TRUE)
    # rle solution
    ananda <- function(y) {
        sequence(rle(y)$lengths)
    }
    
    require(microbenchmark)
    microbenchmark(a1 <- arun(x), a2<-ananda(x), times=100)
    Unit: milliseconds
                expr       min        lq    median       uq       max neval
       a1 <- arun(x)  123.2827  132.6777  163.3844  185.439  563.5825   100
     a2 <- ananda(x) 1382.1752 1899.2517 2066.4185 2247.233 3764.0040   100
    
    identical(a1, a2) # [1] TRUE
    

    【讨论】:

    • @Arun,谢谢这是我正在处理的一个较小的数据集,但它肯定会在未来派上用场!对不起,我只能接受一个答案! :(
    • 嗨@Arun - 我认为最新版本的“data.table”版本 1.9.2 中没有 duplist
    • 似乎此代码不再适用于最新版本的 data.table?谢谢!
    • 还有另一个 mtd:setDT(dataset)[, cnt := rowid(rleid(input))]
    • @chinsoon12 好多了!随意将其编辑为答案。
    【解决方案3】:

    runner 有专门的解决方案来计算所需的内容。 streak_run 是最快的解决方案,接受向量作为输入。

    library(microbenchmark)
    library(runner)
    
    x      <- sample(letters, 1e6, TRUE)
    ananda <- function(y) sequence(rle(y)$lengths)
    
    microbenchmark(
      a2 <- ananda(x), 
      runner <- streak_run(x), 
      times=100
    )
    
    #Unit: milliseconds
    #                expr     min      lq     mean  median       uq      max neval
    #     a2 <- ananda(x) 580.744 718.117 1059.676 944.073 1399.649 1699.293    10
    #run <- streak_run(x)  37.682  39.568   42.277  40.591   43.947   52.917    10
    
    identical(a2, run)
    #[1] TRUE
    

    【讨论】:

    • 这个包还在吗?好像下载不了
    • 是的。使用install.packages("runner")。你用什么系统?我刚刚检查了 Linux 和 MacOS,它可以工作
    • 我在 Windows 上安装了 R 3.4.1。当我尝试安装它说package ‘runner’ is not available (for R version 3.4.1)
    • 尝试更新到最新的R版本或从github安装devtools::install_github("gogonzo/runner")
    • 这一定是问题所在。这是一台工作计算机,我无法获得devtools。我正在等待我的 R 更新,然后希望我能拿到包
    猜你喜欢
    • 1970-01-01
    • 2015-01-20
    • 2016-01-12
    • 2021-09-07
    • 1970-01-01
    • 2015-07-30
    • 2014-05-03
    • 2015-03-29
    相关资源
    最近更新 更多