使用聚合结果对R中的数据子集

使用聚合结果对R中的数据子集,r,aggregate,outliers,R,Aggregate,Outliers,我正在使用R的stats包中的mad函数来识别异常值。使用aggregate,我可以找到每个因子水平的唯一组合的边界值,如下所示: require(stats) set.seed(492) y <- rnorm(2000) x1 <- sample(letters[1:2], 2000,T) x2 <- sample(letters[1:2], 2000,T) df <- data.frame(y,x1,x2) boundaries <- aggregate(df

我正在使用
R
stats
包中的
mad
函数来识别异常值。使用
aggregate
,我可以找到每个因子水平的唯一组合的边界值,如下所示:

require(stats)
set.seed(492)
y <- rnorm(2000)
x1 <- sample(letters[1:2], 2000,T)
x2 <- sample(letters[1:2], 2000,T)
df <- data.frame(y,x1,x2)

boundaries <- aggregate(df$y, list(df$x1, df$x2), function(x) cbind(median(x) 
+ (3*mad(x)), median(x) - (3*mad(x))))
x.1
是上限,
x.2
是下限。我想对df进行子集
df
,以便去除每个因子水平组合的异常值-例如,在a.a中,我不希望任何值高于2.88或低于-2.80,但对于a.b,我希望上限值为3.14,下限值为-2.96

到目前为止,我已尝试使用
by
,但它返回长度为0行的数据帧:

by(df$y, list(df$x1, df$x2), function(x) df[which(df$y>(median(x) + (3*mad(x))) &     df$y<(median(x) - (3*mad(x)))),])

by(df$y,list(df$x1,df$x2),function(x)df[which(df$y>(中位数(x)+(3*mad(x))&df$y我想你可以使用
merge
然后使用一些标准的子集。在下面,我修改了你的
aggregate
语句,得到更好的名称,使
merge
更简单。我还使用了
do.call(data.frame,…)
将矩阵列展平为聚合的
data.frame中的列

boundaries <- aggregate(y ~ x1 + x2, df, function(x)
  cbind(median(x) + (3*mad(x)), median(x) - (3*mad(x))))
boundaries <- do.call(data.frame, boundaries)

out <- merge(df, boundaries)
head(out)
#   x1 x2          y     y.1       y.2
# 1  a  a -0.4003471 2.87556 -2.809068
# 2  a  a -0.5652717 2.87556 -2.809068
# 3  a  a  0.1185306 2.87556 -2.809068
# 4  a  a  1.2634333 2.87556 -2.809068
# 5  a  a  0.3585731 2.87556 -2.809068
# 6  a  a -0.1436202 2.87556 -2.809068

out2 <- out[with(out, y.2 < y & y < y.1), c("y", "x1", "x2")]
head(out2)
#            y x1 x2
# 1 -0.4003471  a  a
# 2 -0.5652717  a  a
# 3  0.1185306  a  a
# 4  1.2634333  a  a
# 5  0.3585731  a  a
# 6 -0.1436202  a  a

dim(out2)
# [1] 1993    3

bounders我想你可以使用
merge
然后使用一些标准的子集。在下面,我修改了你的
aggregate
语句,使
merge
更简单。我还使用了
do.call(data.frame,…)
将矩阵列展平为聚合的
data.frame中的列

boundaries <- aggregate(y ~ x1 + x2, df, function(x)
  cbind(median(x) + (3*mad(x)), median(x) - (3*mad(x))))
boundaries <- do.call(data.frame, boundaries)

out <- merge(df, boundaries)
head(out)
#   x1 x2          y     y.1       y.2
# 1  a  a -0.4003471 2.87556 -2.809068
# 2  a  a -0.5652717 2.87556 -2.809068
# 3  a  a  0.1185306 2.87556 -2.809068
# 4  a  a  1.2634333 2.87556 -2.809068
# 5  a  a  0.3585731 2.87556 -2.809068
# 6  a  a -0.1436202 2.87556 -2.809068

out2 <- out[with(out, y.2 < y & y < y.1), c("y", "x1", "x2")]
head(out2)
#            y x1 x2
# 1 -0.4003471  a  a
# 2 -0.5652717  a  a
# 3  0.1185306  a  a
# 4  1.2634333  a  a
# 5  0.3585731  a  a
# 6 -0.1436202  a  a

dim(out2)
# [1] 1993    3

bounders这里是一个使用
plyr
的解决方案。它使用split-apply-combine范式。我们首先使用列
x1
x2
将数据框拆分为若干部分。对于每个部分
d
(这是一个数据框)我们计算出的外部限制,我们将考虑<代码> y>代码>离群值,然后使用逻辑索引只返回不属于异常值的<代码> d>代码>行。
library(plyr)
df2 = ddply(df, .(x1, x2), function(d){
  limits = median(d$y) + 3*c(-1, 1)*mad(d$y)
  d[(d$y - limits[1])*(limits[2] - d$y) > 0,]
})

这里是一个使用
plyr
的解决方案。它使用拆分应用组合范例。我们首先使用列
x1
x2
将数据帧拆分为多个片段。对于每个片段
d
(这是一个数据帧)我们计算出的外部限制,我们将考虑<代码> y>代码>离群值,然后使用逻辑索引只返回不属于异常值的<代码> d>代码>行。
library(plyr)
df2 = ddply(df, .(x1, x2), function(d){
  limits = median(d$y) + 3*c(-1, 1)*mad(d$y)
  d[(d$y - limits[1])*(limits[2] - d$y) > 0,]
})

此函数过滤值以满足您的条件,其结构可避免不必要的中位数和mad重新计算

filt <- function (x) {
    b <- median(x) + mad(x) * c(-3, 3)
    x[x > b[1] & x < b[2]]
}

filt此函数过滤值以满足您的条件,其结构可避免不必要的中位数和mad重新计算

filt <- function (x) {
    b <- median(x) + mad(x) * c(-3, 3)
    x[x > b[1] & x < b[2]]
}

filt“x.2”是否也代表下限?是的,对不起!我会在问题中澄清。“x.2”是否也代表下限?是的,对不起!我会在问题中澄清。
R
报告“[.default”(xj,I)中的
错误:当我尝试最初创建
边界时,下标类型“closure”无效。
知道可能发生了什么吗?@luser,是您的实际
数据。frame
称为“df”?您发布的这个示例数据集是否存在相同的问题?我的实际
数据。frame
未调用
df
或任何其他系统保留名称。当我清除我的工作区并复制粘贴我放在这里的代码时,我也有相同的问题。@luser,您使用的是什么版本的R?
sessionInfo()
reports 3.0.2
R
reports
Error in'[.default'(xj,i):当我尝试最初创建
边界时,无效的下标类型“closure”
。知道会发生什么吗?@luser,是您实际的
数据。frame
称为“df”?您发布的这个示例数据集是否存在相同的问题?我的实际
数据。frame
未调用
df
或任何其他系统保留名称。当我清除我的工作区并复制粘贴我放在这里的代码时,我也有相同的问题。@luser,您使用的是什么版本的R?
sessionInfo()
reports 3.0.2我最初尝试使用
ddply
,但没有结果。感谢您的解释,我现在对如何使用
plyr
有了一点了解。我最初尝试使用
ddply
,但没有结果。感谢您的解释,我现在对如何使用
plyr
有了一点了解。