2012-10-12 125 views
6

异常值我有这样一个数据帧:计算中的R

X

Team 01/01/2012 01/02/2012 01/03/2012 01/01/2012 01/04/2012 SD Mean 
A  100   50   40  NA   30  60 80 

我喜欢在每个单元上的均值和SD来计算异常值进行计算。例如,

abs(x-Mean) > 3*SD 

x$count<-c(1)(如果满足上述条件,则增加此值)。

我这样做来检查我的数据集中的异常。如果我知道列名称,则计算会更容易,但列数会有所不同。有些细胞可能有NA。

我想从副轨道每个单元的意思是,我想这

x$diff<-sweep(x, 1, x$Mean, FUN='-') 

似乎并不奏效,任何想法?

+1

如果您为我们提供了一个小样本数据用'dput(head(x))',那么我们可以将它剪切并粘贴到我们的浏览器中,并测试我们的解决方案。 – nograpes

回答

30

获取您的IQR(四分位数间距)和下/上四分位使用:

lowerq = quantile(data)[2] 
upperq = quantile(data)[4] 
iqr = upperq - lowerq #Or use IQR(data) 

计算的界限为温和的离群值:

mild.threshold.upper = (iqr * 1.5) + upperq 
mild.threshold.lower = lowerq - (iqr * 1.5) 

的任何数据点外(> mild.threshold。上限或< mild.threshold.lower)这些值是一个温和的异常值

要检测极端异常值做同样的事情,但乘以3代替:

extreme.threshold.upper = (iqr * 3) + upperq 
extreme.threshold.lower = lowerq - (iqr * 3) 

的任何数据点外(> extreme.threshold.upper或< extreme.threshold.lower)这些值是一个极端的异常值

希望这有助于

编辑的:访问50%,不是75%

+3

应该是'upperq = quantile(data)[4]' – Ben

+0

这将会是一个非常糟糕的算法。例如,当一个相当大的向量可以说80%的数据点在短距离范围内(例如10-100 ),其余的20%非常稀疏,那么这种算法将识别大量的异常值,这可能并不能真实地反映人口中的异常值。 – Bg1850

+2

这里给出的答案是由于Tukey而众所周知的方法。见:https://en.wikipedia.org/wiki/Outlier#Tukey.27s_test – stackoverflowuser2010

3

我已经看到你问了一些关于按行操作的问题。你应该避免这种情况。 R遵循以下概念:列表示变量,行表示观察值。许多功能都根据这个概念进行了优化。如果您需要将宽输出或转置输出转换为文件,则可以在写入文件之前重新排列数据。

我假设你的数据实际上看起来如问题所示,但是你有多行。

df <- read.table(text="Team 01/01/2012 01/02/2012 01/03/2012 01/01/2012 01/04/2012 SD 

Mean 
A  100   50   40  NA   30  60 80 
B  200   40   5   8   NA  NA NA",check.names = FALSE,header=TRUE) 

#needed because one date appears twice 
df <- df[,] 

#reshape the data 
library(reshape2) 
df <- melt(df,id="Team") 
names(df)[2] <- "Date" 

#remove the SD and Mean 
df <- df[!df$Date %in% c("SD","Mean"),] 

#function to detect outliers 
outfun <- function(x) { 
    abs(x-mean(x,na.rm=TRUE)) > 3*sd(x,na.rm=TRUE) 
} 

#test if function works 
outfun(c(200,rnorm(10))) 

#use function over all data 
df3$outlier.all <- outfun(df3$value) 

#apply function for each team 
library(plyr) 
df3 <- ddply(df3,.(Team),transform,outlier.team=outfun(value)) 

结果:

  Date Team value outlier.all outlier.team 
1 01/01/2012 A 100  FALSE  FALSE 
2 01/02/2012 A 50  FALSE  FALSE 
3 01/03/2012 A 40  FALSE  FALSE 
4 01/01/2012.1 A NA   NA   NA 
5 01/04/2012 A 30  FALSE  FALSE 
6 01/01/2012 B 200  FALSE  FALSE 
7 01/02/2012 B 40  FALSE  FALSE 
8 01/03/2012 B  5  FALSE  FALSE 
9 01/01/2012.1 B  8  FALSE  FALSE 
10 01/04/2012 B NA   NA   NA 
+0

嗨@罗兰。感谢您的答复。这是一个特例,我有成千上万的观察(行),我想找出异常值,然后只绘制它们。我正在将日期转换为行,并尝试检查每个单元的平均值并计算它达到异常点的次数。然后,我将选择10或20个项目并绘制它们。基本上,我试图在我的数据集中捕捉anamolies。 – user1471980

+0

@ user1471980,好吧,我的答案是这样做的起点。在R中实际上并不难(如果数据是长格式的,我演示了如何实现这一点)。根据观察结果的数量(你写成千上万,也可能意味着成千上万)和数据组,考虑到计算时间,其他方法可能更可取。但是如果我的回答不够充分,你最好问一个新的问题,提供包括最终目标在内的所有信息。 – Roland

+0

感谢您的意见。根据你的建议,我确实创造了另一个问题,希望我已经提出了点 - http://stackoverflow.com/questions/12888212/detecting-outliers-on-wide-data-frame – user1471980

4

我用@ BY0的回答上面创建一个功能,可自动去除异常值。下面是函数和一些示例代码:

# generate 10 random numbers and 2 'outlier' numbers 
testData <- c(-42,rnorm(10),42) 

# show the numbers 
testData 

# define a function to remove outliers 
FindOutliers <- function(data) { 
    lowerq = quantile(data)[2] 
    upperq = quantile(data)[4] 
    iqr = upperq - lowerq #Or use IQR(data) 
    # we identify extreme outliers 
    extreme.threshold.upper = (iqr * 3) + upperq 
    extreme.threshold.lower = lowerq - (iqr * 3) 
    result <- which(data > extreme.threshold.upper | data < extreme.threshold.lower) 
} 

# use the function to identify outliers 
temp <- FindOutliers(testData) 

# remove the outliers 
testData <- testData[-temp] 

# show the data with the outliers removed 
testData 
0

下面的公式可用于确定哪些值是异常值:

upper.outlier.calc <- function(x.var, df){with(df, quantile(x.var, 0.75) + (1.5 * (quantile(x.var, 0.75) - quantile(x.var, 0.25))))}

lower.outlier.calc <- function(x.var, df){with(df, quantile(x.var, 0.25) - (1.5 * (quantile(x.var, 0.75) - quantile(x.var, 0.25))))}