如何在R中用第5个和第95个百分位数值替换异常值

9

我希望能替换掉在我的相对较大的 R 数据集中取值在第95个和第5个百分位之上或之下的所有数值,使它们分别等于这些百分位的数值。 我的目标是避免完全删去数据中的离群值。

如有建议,十分感谢。我在其他地方找不到如何做到这一点的信息。


2
除了回答这个问题需要更多的细节之外,你真的确定想要这样做吗?如果没有异常值,一个相对较大的数据集(比如100个数字)将有5个值低于第5百分位数和5个值高于第95百分位数。 - John
在采取这些措施时要非常小心,因为您正在大幅改变数据集的统计数据。如果这是有效的,取决于您尝试从数据中获取什么以及数据的分布(例如正态分布)。 - Paul Hiemstra
@RobS 注意使用=作为赋值运算符。<-可以复合,但=不行。 - Ricardo Saporta
1
我几乎总是使用=,很少遇到问题。只有在像system.time(bla <- spam())这样的调用中,<-是必需的。 - Paul Hiemstra
Bobbo,缺失的细节包括模型是什么以及如何定义百分位数;您是否想要从数据中推导出经验性截止点或从模型中推导出截止点以及该模型是什么;以及具体如何替换数据点...使用模型参数替换为随机值?...还是其他形式的插补?附加到末尾?此外,您所做的并不能单独测试鲁棒性。它需要添加其他内容。 - John
4个回答

21
这样就可以了。
fun <- function(x){
    quantiles <- quantile( x, c(.05, .95 ) )
    x[ x < quantiles[1] ] <- quantiles[1]
    x[ x > quantiles[2] ] <- quantiles[2]
    x
}
fun( yourdata )

谢谢,非常好用。我是这个网站的新手,有没有什么方式可以为您的答案点赞或者其他的评价呢? - Bobbo
你可以提高答案并接受它(你已经接受了它)。请参阅http://stackoverflow.com/faq,如果您全部阅读将获得一个徽章。 - Romain Francois
以上代码片段还将用分位数值替换缺失值(如果有的话)! - Bolaka
请查看pandas中的.clip函数 https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.quantile.html - Jason Goal

12
你可以使用squish()一行代码完成它:
d2 <- squish(d, quantile(d, c(.05, .95)))



在 Scales 库中,查看 ?squish?discard

#--------------------------------
library(scales)

pr <- .95
q  <- quantile(d, c(1-pr, pr))
d2 <- squish(d, q)
#---------------------------------

# Note: depending on your needs, you may want to round off the quantile, ie:
q <- round(quantile(d, c(1-pr, pr)))

例子:

d <- 1:20
d
# [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20


d2 <- squish(d, round(quantile(d, c(.05, .95))))
d2
# [1]  2  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 19

不错。或者你可以将squish函数合并到自己的函数中。cap <- function(x, low, high) pmin(high, pmax(low, x)) - Ben

3
我使用了这段代码来获取您需要的内容:
qn = quantile(df$value, c(0.05, 0.95), na.rm = TRUE)
df = within(df, { value = ifelse(value < qn[1], qn[1], value)
                  value = ifelse(value > qn[2], qn[2], value)})

其中df是您的数据框,value是包含您的数据的列。


谢谢您的回答,您和上面的回答都完美地解决了问题。 - Bobbo

2
有一种更好的方法来解决这个问题。异常值不是指在95分位数以上或5分位数以下的任何点。相反,只有当它低于第一四分位数-1.5·IQR或高于第三四分位数+1.5·IQR时,才被视为异常值。
此网站将更详细地解释

要了解更多有关异常值处理的信息,请参见此处

capOutlier <- function(x){
   qnt <- quantile(x, probs=c(.25, .75), na.rm = T)
   caps <- quantile(x, probs=c(.05, .95), na.rm = T)
   H <- 1.5 * IQR(x, na.rm = T)
   x[x < (qnt[1] - H)] <- caps[1]
   x[x > (qnt[2] + H)] <- caps[2]
   return(x)
}
df$colName=capOutlier(df$colName)
Do the above line over and over for all of the columns in your data frame

这是一个异常值的严格定义。无论您将异常值定义为低于20%/高于80%+(如您所定义)还是低于5%/高于95%+(如OP所述),都是任意的;适用的定义取决于您的问题和数据。 - ctbrown
我没有将其定义为低于20%或高于80%。我使用了一个常见的异常值定义,这可能会在统计学课程介绍中使用。任何小于第一四分位数-1.5 *四分位距或大于第三四分位数+1.5 *四分位距的值都被视为异常值。四分位距(IQR)是第一四分位数和第三四分位数之间的范围(数据的中间50%)。 - Kyle Peters
这不是“常见”的异常值定义,而是任意的定义。 - ctbrown
如果你在大学学习101统计课程,他们会给你这个离群值的定义。请查看我回答中的网站。有其他关于离群值的定义,但这是最基本和最常用的定义。而且,我发布的定义比问题中给出的更准确。如果你有数据(.99998,1,1,1,1,1,1,1,1.0001),那么如果你使用问题中描述的离群值分类方法,则.99998和1.0001将被错误地分类为离群值。 - Kyle Peters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接