在特定值的连续运行中创建计数器

时间:2011-02-16 04:22:53

标签: r

我有一个小时的价值。我想计算自上一次非零以来该值连续多少小时。对于电子表格或循环来说,这是一项简单的工作,但我希望有一个快速的矢量化单行程来完成任务。

x <- c(1, 0, 1, 0, 0, 0, 1, 1, 0, 0)
df <- data.frame(x, zcount = NA)

df$zcount[1] <- ifelse(df$x[1] == 0, 1, 0)
for(i in 2:nrow(df)) 
  df$zcount[i] <- ifelse(df$x[i] == 0, df$zcount[i - 1] + 1, 0)

期望的输出:

R> df
   x zcount
1  1      0
2  0      1
3  1      0
4  0      1
5  0      2
6  0      3
7  1      0
8  1      0
9  0      1
10 0      2

6 个答案:

答案 0 :(得分:22)

William Dunlap关于R-help的帖子是寻找与跑步长度相关的所有事情的地方。他来自this post的f7是

f7 <- function(x){ tmp<-cumsum(x);tmp-cummax((!x)*tmp)}

并且在当前情况f7(!x)。在性能方面有

> x <- sample(0:1, 1000000, TRUE)
> system.time(res7 <- f7(!x))
   user  system elapsed 
  0.076   0.000   0.077 
> system.time(res0 <- cumul_zeros(x))
   user  system elapsed 
  0.345   0.003   0.349 
> identical(res7, res0)
[1] TRUE

答案 1 :(得分:21)

这是一种基于约书亚的rle方法的方法:(按照马雷克的建议编辑使用seq_lenlapply

> (!x) * unlist(lapply(rle(x)$lengths, seq_len))
 [1] 0 1 0 1 2 3 0 0 1 2

<强>更新即可。只是为了踢,这是另一种方法,大约快5倍:

cumul_zeros <- function(x)  {
  x <- !x
  rl <- rle(x)
  len <- rl$lengths
  v <- rl$values
  cumLen <- cumsum(len)
  z <- x
  # replace the 0 at the end of each zero-block in z by the 
  # negative of the length of the preceding 1-block....
  iDrops <- c(0, diff(v)) < 0
  z[ cumLen[ iDrops ] ] <- -len[ c(iDrops[-1],FALSE) ]
  # ... to ensure that the cumsum below does the right thing.
  # We zap the cumsum with x so only the cumsums for the 1-blocks survive:
  x*cumsum(z)
}

试一个例子:

> cumul_zeros(c(1,1,1,0,0,0,0,0,1,1,1,0,0,1,1))
 [1] 0 0 0 1 2 3 4 5 0 0 0 1 2 0 0

现在比较百万长度矢量的时间:

> x <- sample(0:1, 1000000,T)
> system.time( z <- cumul_zeros(x))
   user  system elapsed 
   0.15    0.00    0.14 
> system.time( z <- (!x) * unlist( lapply( rle(x)$lengths, seq_len)))
   user  system elapsed 
   0.75    0.00    0.75 

故事的道德:单行更好,更容易理解,但并不总是最快!

答案 2 :(得分:6)

rle将“计算自上次不为零以来该值连续多少小时”,但不是“所需输出”的格式。

请注意相应值为零的元素的长度:

rle(x)
# Run Length Encoding
#   lengths: int [1:6] 1 1 1 3 2 2
#   values : num [1:6] 1 0 1 0 1 0

答案 3 :(得分:3)

单行,不是超级优雅:

x <- c(1, 0, 1, 0, 0, 0, 1, 1, 0, 0) 

 unlist(lapply(split(x, c(0, cumsum(abs(diff(!x == 0))))), function(x) (x[1] == 0) * seq(length(x))))

答案 4 :(得分:1)

一种简单的import GameplayKit import SpriteKit class AgentNode : SKNode, GKAgentDelegate { var agent = GKAgent2D() var triangleShape = SKShapeNode() override init(){ super.init() } init(scene:SKScene, radius:Float, position:CGPoint) { super.init() self.position = position self.zPosition = 10; scene.addChild(self) agent.radius = radius agent.position = vector_float2(Float(position.x), Float(position.y)) agent.delegate = self agent.maxSpeed = 100 * 4 agent.maxAcceleration = 50 * 4 let ship = SKSpriteNode(imageNamed:"Spaceship") ship.setScale(1.0 / 8.0) ship.zRotation = CGFloat(-Double.pi / 2.0) self.addChild(ship) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func agentWillUpdate(agent: GKAgent) { } private func agentDidUpdate(agent: GKAgent) { guard let agent2D = agent as? GKAgent2D else { return } self.position = CGPoint(x: CGFloat(agent2D.position.x), y: CGFloat(agent2D.position.y)) self.zRotation = CGFloat(agent2D.rotation) } } R方法:

base

答案 5 :(得分:0)

使用 purr::accumulate() 非常简单,因此这个 tidyverse 解决方案可能会增加一些价值。我必须承认它绝对不是最快的,因为它调用了 length(x) 次相同的函数。

library(purrr)

accumulate(x==0, ~ifelse(.y!=0, .x+1, 0))

 [1] 0 1 0 1 2 3 0 0 1 2