我有一个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
说,如果&#39;速度&#39;十字架限制&#39;将其计为1.只有当速度低于并超过“限制”时,您才会再次计算。
我想要数据。
id | Speed Viol.
----------
1 | 2
---------
2 | 2
---------
3 | 1
---------
这里是id(count)。
id1 (1) 40 (2) 50,40
id2 (1) 45,50 (2) 55
id3 (1) 50,50,60
如何不使用if()
。
答案 0 :(得分: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
代替d.b建议:
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
答案 1 :(得分:2)
这是一个dplyr
解决方案。我按id
进行分组,然后检查速度是否高于每行的限制,但不在上一个条目中。 (我使用lag
获取上一行)。如果是这种情况,则会生成TRUE
。或者,如果它是id
的第一行(即row_number()==1
)且超出限制,则也会给出TRUE
。然后,我使用TRUE
对每个id
的所有summarise
值求和。
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
答案 2 :(得分: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
答案 3 :(得分: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)$values
为TRUE
时)。