【问题标题】:Create group number for contiguous runs of equal values为相等值的连续运行创建组号
【发布时间】:2015-07-30 15:14:31
【问题描述】:

有没有比使用循环更快的方法来创建计数器索引?对于每个连续运行的相等值,索引应该相同。我发现循环非常慢,尤其是当数据很大时。

为了说明,这里是输入和期望的输出

x <- c(2, 3, 9, 2, 4, 4, 3, 4, 4, 5, 5, 5, 1)

所需的结果计数器:

c(1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9)

请注意,连续运行具有不同索引。例如。查看值24 的所需索引

我的低效代码是这样的:

group[1]<-1
counter<-1
for (i in 2:n){
if (x[i]==x[i-1]){
    group[i]<-counter
}else{
    counter<-counter+1
    group[1]<-counter}
}

【问题讨论】:

    标签: r performance loops indexing counting


    【解决方案1】:

    使用data.table,具有rleid()的功能:

    require(data.table) # v1.9.5+
    rleid(x)
    #  [1] 1 2 3 4 5 5 6 7 7 8 8 8 9
    

    【讨论】:

      【解决方案2】:

      如果您有这样的数值,您可以使用diffcumsum 将值的变化相加

      x <- c(2,3,9,2,4,4,3,4,4,5,5,5,1)
      cumsum(c(1,diff(x)!=0))
      # [1] 1 2 3 4 5 5 6 7 7 8 8 8 9
      

      【讨论】:

      • 肯定比我的回答快。目前无法针对 Arun 的 data.table 答案进行评估。
      • 感谢弗兰克的评论。我现在将使用 MrFlick 的建议。 Arun的data.table建议似乎需要一些安装。
      • 是的,如果您想尝试 Arun 的解决方案,请参阅此链接以获取安装帮助:github.com/Rdatatable/data.table/wiki/Installation
      • @Frank,昨天推出了更快的rleid() 版本,它也可以节省内存。这里,diff(x)c(...)!=cumsum() 都分配了新的内存,这意味着它需要大约 4 倍于空间中的原始数据!!
      【解决方案3】:

      这将适用于数字字符值:

      rep(1:length(rle(x)$values), times = rle(x)$lengths)
      #[1] 1 2 3 4 5 5 6 7 7 8 8 8 9
      

      您也可以通过只调用一次rle 来提高效率(大约快 2 倍)并且使用rep.int 而不是rep 可以非常略微提高速度:

      y <- rle(x)
      rep.int(1:length(y$values), times = y$lengths)
      

      【讨论】:

        【解决方案4】:

        以上answer by Jota 可以进一步简化为,这样会更快

        with(rle(x), rep(1:length(lengths), lengths))
        
         [1] 1 2 3 4 5 5 6 7 7 8 8 8 9
        

        【讨论】:

          猜你喜欢
          • 2016-10-15
          • 2013-11-28
          • 2015-01-20
          • 2012-04-26
          • 1970-01-01
          • 2020-09-13
          • 2019-01-16
          • 1970-01-01
          相关资源
          最近更新 更多