检测宽数据帧上的异常值

时间:2012-10-15 01:30:44

标签: r

X

Team Date       Score
A    1-1-2012   80
A    1-2-2012   90
A    1-3-2012   50
A    1-4-2012   40   
B    1-1-2012   100
B    1-2-2012   60
B    1-3-2012   30
B    1-4-2012   70
etc

我需要并且可以将此数据框转换为每个团队的一行宽数据框,并将所有观察和日期作为标题:

XX

Team 1-1-2012 1-2-2012  1-3-2012 1-4-2012
A    80       90        50        40
B    100     60         30        70  

我需要计算每行的均值和sd,我可以这样做:

XX

Team 1-1-2012 1-2-2012  1-3-2012 1-4-2012  mean   sd
A    80       90        50        40       75    20
B    100     60         30        70       55    10 

考虑到我在数据帧xx中有数千行。我想对每个单元格进行计算:

如果abs(xx-Mean)> 3 * SD,创建计数器列名称并递增值。想法是将每个观察值与平均值和sd进行比较,如果给定团队的每个观察结果与此匹配 - abs(xx-Mean)> 3 * SD,递增计数器。在检查每个单元格之后,我想查看每个团队的每个计数器,并获得具有最高计数器值的前十名高级团队。基本上我试图检测最多的异常值。一旦我获得前十名团队名称,我想在数据框x上绘制他们的时间序列数据。

我希望我不会让它变得比它应该更复杂。不确定,R已经具有对每个单元格进行计算的功能。任何想法如何实现这一点是值得赞赏的?

2 个答案:

答案 0 :(得分:6)

我会以长格式保留您的数据,并使用plyrdata.table或任何其他拆分应用合并工具来计算您的统计信息。以下是我使用plyr执行任务的方法:

#Your data
dat <- read.table(text = "Team Date       Score
A    1-1-2012   80
A    1-2-2012   90
A    1-3-2012   50
A    1-4-2012   40   
B    1-1-2012   100
B    1-2-2012   60
B    1-3-2012   30
B    1-4-2012   70", header = TRUE)

library(plyr)

#Compute mean and sd by team
dat <- ddply(dat, .(Team), transform, mean = mean(Score), sd = sd(Score))
#Your outlier threshold
dat <- transform(dat, outlier = abs(Score - mean) > 3*sd)
#Cumulative sum by team
dat <- ddply(dat, .(Team), transform, cumsumOutlier = cumsum(outlier))

将此作为输出(与您的示例不符,但可能是您的真实数据):

 Team     Date Score mean       sd outlier cumsumOutlier
1    A 1-1-2012    80   65 23.80476   FALSE             0
2    A 1-2-2012    90   65 23.80476   FALSE             0
3    A 1-3-2012    50   65 23.80476   FALSE             0
4    A 1-4-2012    40   65 23.80476   FALSE             0
5    B 1-1-2012   100   65 28.86751   FALSE             0
6    B 1-2-2012    60   65 28.86751   FALSE             0
7    B 1-3-2012    30   65 28.86751   FALSE             0
8    B 1-4-2012    70   65 28.86751   FALSE             0

答案 1 :(得分:5)

long-formatdata.table方法

DT <- read.table( 'clipboard', header = T)
library(data.table)
DT <- as.data.table(DT)
DT[, mean.score := mean(Score), by = Team]
##    Team     Date Score mean.score
## 1:    A 1-1-2012    80         65
## 2:    A 1-2-2012    90         65
## 3:    A 1-3-2012    50         65
## 4:    A 1-4-2012    40         65
## 5:    B 1-1-2012   100         65
## 6:    B 1-2-2012    60         65
## 7:    B 1-3-2012    30         65
## 8:    B 1-4-2012    70         65
DT[, sd.score := sd(Score), by = Team]
##    Team     Date Score mean.score sd.score
## 1:    A 1-1-2012    80         65 23.80476
## 2:    A 1-2-2012    90         65 23.80476
## 3:    A 1-3-2012    50         65 23.80476
## 4:    A 1-4-2012    40         65 23.80476
## 5:    B 1-1-2012   100         65 28.86751
## 6:    B 1-2-2012    60         65 28.86751
## 7:    B 1-3-2012    30         65 28.86751
## 8:    B 1-4-2012    70         65 28.86751
DT[, outlier := abs(Score-mean.score) > 3 * sd.score, by = Team]
##    Team     Date Score mean.score sd.score outlier
## 1:    A 1-1-2012    80         65 23.80476   FALSE
## 2:    A 1-2-2012    90         65 23.80476   FALSE
## 3:    A 1-3-2012    50         65 23.80476   FALSE
## 4:    A 1-4-2012    40         65 23.80476   FALSE
## 5:    B 1-1-2012   100         65 28.86751   FALSE
## 6:    B 1-2-2012    60         65 28.86751   FALSE
## 7:    B 1-3-2012    30         65 28.86751   FALSE
## 8:    B 1-4-2012    70         65 28.86751   FALSE

或者,只需一步

DT[, outlier := abs(Score-mean(Score)) > 3 *  sd(Score), by = Team]

添加异常值的数量(逻辑变量的总和将强制为0,1)

DT[, sum.outlier := sum(outlier), by = Team]