R:计算单个列中连续出现的值

时间:2013-11-15 10:25:28

标签: r count find-occurrences

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

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

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

3 个答案:

答案 0 :(得分:33)

您需要使用sequencerle

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

答案 1 :(得分:17)

现在,data.table包中提供了一个高效且更直接的函数版本,名为rleid。使用它,它只是:

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

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


rle绝对是最便捷的方式(+1 @ Ananda's)。但是对于更大的数据,人们可以做得更好(就速度而言)。您可以使用duplist中的vecseqdata.table函数(未导出),如下所示:

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

答案 2 :(得分:0)

软件包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