2017-09-01 34 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時)。