2013-03-19 120 views
1

我有一個非常大的數據框,約1000行和10000列,每列是一個ID,每一行代表一個日期。 數據框中的每個單元格都可以作爲該日期到該ID的特定問題的累計發生次數。R中的事件檢測

簡化數據如下:

Date  id1 id2 id3 id4 id5 
2012-01-01 0 1 0 2 1 
2012-01-02 0 2 0 2 2 
2012-01-03 2 2 0 8 3 
2012-01-04 2 2 1 8 4 
2012-01-05 2 2 1 8 5 
2012-01-06 4 3 1 8 6 
2012-01-07 4 5 1 14 7 
2012-01-08 5 8 1 16 8 
2012-01-09 5 8 1 20 9 
2012-01-10 5 9 1 20 10 

所以,對於小區(「2012-01-05」,「ID5」),這可能意味着,從一開始到至今,5個項目的id5出售,或錯誤id5發生了5次,類似的東西。

我要寫信給檢測到的任何不尋常的事件的程序和記錄ID,開始日期和事件的結束日期。 例如,id2在2012-01-08有一個不尋常的事件(2012-01-10未被計數,因爲從8增加到9對id2沒有異常); ID4具有兩個不尋常的事件,一個是2012-01-03,另一個是從2012-01-07到2012-01-09

的輸出數據將是這樣的:

Event IDs Start_Date End_Date number_Unusual 
    1 id2 2012-01-08 2012-01-08    5 
    2 id4 2012-01-03 2012-01-03    6 
    2 id4 2012-01-07 2012-01-09    12 
    .... 

number_unusual:這是在不尋常的時間框架內發生的次數。

我使用以下方法:1。 計算累計百分比變化:

Date id1 id2 id3 id4 id5 
1/1/2012 0.00 0.11 0.00 0.10 0.10 
1/2/2012 0.00 0.22 0.00 0.10 0.20 
1/3/2012 0.40 0.22 0.00 0.40 0.30 
1/4/2012 0.40 0.22 1.00 0.40 0.40 
1/5/2012 0.40 0.22 1.00 0.40 0.50 
1/6/2012 0.80 0.33 1.00 0.40 0.60 
1/7/2012 0.80 0.56 1.00 0.70 0.70 
1/8/2012 1.00 0.89 1.00 0.80 0.80 
1/9/2012 1.00 0.89 1.00 1.00 0.90 
1/10/2012 1.00 1.00 1.00 1.00 1.00 

2.找到一個固定的時間框架的差異,比方說,3天的區別:

Date id1 id2 id3 id4 id5 
1/4/2012 0.40 0.11 1.00 0.30 0.30 
1/5/2012 0.40 0.00 1.00 0.30 0.30 
1/6/2012 0.40 0.11 1.00 0.00 0.30 
1/7/2012 0.40 0.33 0.00 0.30 0.30 
1/8/2012 0.60 0.67 0.00 0.40 0.30 
1/9/2012 0.20 0.56 0.00 0.60 0.30 
1/10/2012 0.20 0.44 0.00 0.30 0.30 

3.到目前爲止,我已經到了這裏,下一步我將找出任何不尋常的大值,以便有可能發生不尋常的事件。我知道我可以使用一些for循環做我的工作,說,爲ID2,我知道這是不是通常它有一個增量大於0.2,所以:

event <- c(0) 
ids <- c(0) 
start <- c("") 
end <- c("") 
for (id in c(id1:id5)) 
    for (date in 2012-01-04:2012-01-10) 
    if value[date, id] > 0.2 
     event <- event + 1 
     ids[event] <- id 
     start[event] <- date 
     end[event] <- 2012-01-10 
     for (date2 in date:2012-01-10) 
     if value[date2, id] <= 0.2 { 
      end[event] <- date2 
      skip 
     } 

很抱歉,如果上述僞代碼有任何錯誤,我只是想展示我的想法。

現在我的問題是不是用這種愚蠢的for循環,你可以提出任何智能算法,使我可以做同樣的任務,即找到在數據集中的所有不尋常的事件。

還有,我知道我在用累積百分比的方法是不是一個很好的方法,如果您有任何其他建議,我也願意傾聽和向你學習。 謝謝!

+0

我不明白你的一個不尋常的事件的定義,並在你的第一個示例數據集中不能挑選出不尋常的事件。換句話說,我不明白你的頂級數據集中的數字是什麼,或者他們爲什麼改變他們的做法。也許澄清一點。 – 2013-03-19 06:16:28

+0

@MarkMiller 感謝您的評論。對於不常見的情況,我的意思是累積數量突然增加。對於id5說,它沒有任何不尋常的,因爲那裏的數字每天增加一個。但在id2和id4中,我說這很不尋常,因爲在某些日期,這個數字增加了很多。例如對於id2,2012-01-08突然增加了一倍。 它有助於解釋這一點嗎? – 2013-03-19 06:30:00

+0

也許上面的例子不夠有意義,但考慮到有1000行,這足以讓我爲每個id生成一個「通常」的情況,並且因爲我可以發現「異常」的情況 – 2013-03-19 06:37:50

回答

2

您可以將數據轉換爲matrix,然後使用apply()獲得運行的部分和diff()計算差異簡化代碼。

重建數據:

x <- read.table(tex=' 
Date  id1 id2 id3 id4 id5 
2012-01-01 0 1 0 2 1 
2012-01-02 0 2 0 2 2 
2012-01-03 2 2 0 8 3 
2012-01-04 2 2 1 8 4 
2012-01-05 2 2 1 8 5 
2012-01-06 4 3 1 8 6 
2012-01-07 4 5 1 14 7 
2012-01-08 5 8 1 16 8 
2012-01-09 5 8 1 20 9 
2012-01-10 5 9 1 20 10 
', header=TRUE) 

然後建立一個函數來做到的差異:

foo <- function(x, periods=3, exception=0.1){ 
    xm <- as.matrix(x) 
    xp <- apply(xm, 2, function(z)z/tail(z, 1)) 
    diff2 <- diff(diff(xp, periods), 1) 
    NAs <- matrix(NA, ncol=ncol(x), nrow=3) 
    rbind(NAs, abs(diff2) > exception) 
} 

,你會得到:

foo(x[, -1], periods=3, exception=0.2) 

     id1 id2 id3 id4 id5 
[1,] NA NA NA NA NA 
[2,] NA NA NA NA NA 
[3,] NA NA NA NA NA 
[4,] FALSE FALSE FALSE FALSE FALSE 
[5,] FALSE FALSE FALSE TRUE FALSE 
[6,] FALSE TRUE TRUE TRUE FALSE 
[7,] FALSE TRUE FALSE FALSE FALSE 
[8,] TRUE FALSE FALSE FALSE FALSE 
[9,] FALSE FALSE FALSE TRUE FALSE 

編輯

要找出which內容是真實的,與paste()which()包裹在另一個apply()結果:

z <- foo(x[, -1], periods=3, exception=0.2) 
apply(z, 2, function(x)paste(which(x), collapse="_")) 

    id1  id2  id3  id4  id5 
    "8" "6_7"  "6" "5_6_9"  "" 
+0

謝謝你的回答。但我可能不清楚我的問題。我已經從foo函數中得到了結果。這裏我的問題是我如何總結它,即[6:7,id2]有一個不尋常的事件,所以輸出數據應該有這樣一行: ** event#id start_date end_date相關事件**; ** 1 id2 6 7 6 **; – 2013-03-19 07:35:39

+0

@KloserCheung好的,我編輯了我的答案。 – Andrie 2013-03-19 09:35:04