2017-09-01 32 views
1

我有一个带有ID和速度的数据集。计数超过阈值的变量的实例

id <- c(1,1,1,1,2,2,2,2,3,3,3) 

speed <- c(40,30,50,40,45,50,30,55,50,50,60) 

i <- cbind(id, speed) 

limit <- 35 

说,如果“速度”十字架“限价”将其视作1.如果速度低于来到和跨越“限制”,你将再次只算。

我希望数据能够像。

id | Speed Viol. 
---------- 
1 | 2 
--------- 
2 | 2 
--------- 
3 | 1 
--------- 

here id(count)。

id1 (1) 40 (2) 50,40 

id2 (1) 45,50 (2) 55 

id3 (1) 50,50,60 

如何做不使用if()

+0

你试过'tapply'吗? –

回答

5

这里有一个方法tapply正如评论和原始载体中所建议的。

tapply(speed, id, FUN=function(x) sum(c(x[1] > limit, diff(x > limit)) > 0)) 
1 2 3 
2 2 1 

tapply对每个组应用一个函数,这里是用ID。该函数检查ID的第一个元素是否超过35,然后将其连接到diff的输出,其参数是检查后续观察值是否大于35.因此diff检查ID是否在低于该值后返回到35以上水平。生成的向量中的负值用> 0转换为FALSE(0),并将这些结果相加。

tapply返回一个命名向量,它可以很好地处理。但是,如果你想有一个data.frame,那么你可以使用aggregate而不是通过数据库的建议:

aggregate(speed, list(id=id), FUN=function(x) sum(c(x[1] > limit, diff(x > limit)) > 0)) 
    id x 
1 1 2 
2 2 2 
3 3 1 
2

这是dplyr解决方案。我通过id进行分组,然后检查速度是否超过每行的限制,但不在之前的条目中。 (我使用lag得到前一行)。如果是这种情况,则产生TRUE。或者,如果它是id的第一行(即,row_number()==1)并且超出了限制,则也给出TRUE。然后,我使用summarise将每个id的所有TRUE值相加。

id <- c(1,1,1,1,2,2,2,2,3,3,3) 
speed <- c(40,30,50,40,45,50,30,55,50,50,60) 
i <- data.frame(id, speed) 
limit <- 35 

library(dplyr) 

i %>% 
    group_by(id) %>% 
    mutate(viol=(speed>limit&lag(speed)<limit)|(row_number()==1&speed>limit)) %>% 
    summarise(sum(viol)) 

# A tibble: 3 x 2 
    id `sum(viol)` 
    <dbl>  <int> 
1  1   2 
2  2   2 
3  3   1 
1

这里是data.table另一种选择,

library(data.table) 

setDT(i)[, id1 := rleid(speed > limit), by = id][ 
      speed > limit, .(violations = uniqueN(id1)), by = id][] 

赋予,

id violations 
1: 1   2 
2: 2   2 
3: 3   1 
0
aggregate(speed~id, data.frame(i), function(x) sum(rle(x>limit)$values)) 
# id speed 
#1 1  2 
#2 2  2 
#3 3  1 

主要想法是x > limit将检查违反速度限制的情况,并且rle(x)会将这些实例组合为连续违规或连续的非违规。然后,您需要做的就是统计连续违规组(当rle(x>limit)$valuesTRUE时)。