我有一个非常大的数据框,大约有1000行和10000列,每列都是一个ID,每一行代表一个日期。 并且数据框中的每个单元格都可以作为截至该ID的特定问题的累计出现次数。
简化数据如下:
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不算,因为id2从8增加到9没有异常); 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 :(得分: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
元素为真,请将结果用apply()
和paste()
包裹在另一个which()
中:
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" ""