将索引添加到相等值的连续运行

Ren*_*ens 9 indexing performance loops r counting

制作计数器索引比使用循环有更快的方法吗?在相等值的连续运行中,索引应该相同.我发现循环非常慢,特别是当数据如此之大时.

为了说明,这是输入和所需的输出

x <- c(2, 3, 9, 2, 4, 4, 3, 4, 4, 5, 5, 5, 1)
Run Code Online (Sandbox Code Playgroud)

期望的结果:

c(1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9)
Run Code Online (Sandbox Code Playgroud)

请注意,连续运行具有不同的索引.例如,查看值的所需索引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}
}
Run Code Online (Sandbox Code Playgroud)

Aru*_*run 10

使用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
Run Code Online (Sandbox Code Playgroud)


MrF*_*ick 8

如果您有这样的数值,则可以使用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
Run Code Online (Sandbox Code Playgroud)

  • @Frank,昨天推送了一个更快的 `rleid()` 版本,它也是内存高效的。在这里,`diff(x)`、`c(...)`、`!=` 和 `cumsum()` 都分配了新的内存,这意味着它需要大约 4 倍的空间原始数据!! (2认同)

Jot*_*ota 6

这将使用字符值的数字:

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

您也可以多一点有效的通过调用rle只需一次(大约快2倍)和非常轻微的速度提升可以用做rep.int替代rep:

y <- rle(x)
rep.int(1:length(y$values), times = y$lengths)
Run Code Online (Sandbox Code Playgroud)