【问题标题】:Using results of aggregate to subset data in R在 R 中使用聚合结果来子集数据
【发布时间】:2014-05-03 08:29:44
【问题描述】:

我正在使用Rstats 包中的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))))

这给出了:

+---------------------------------------+
|  Group.1 Group.2       x.1       x.2  |
+---------------------------------------+
| 1       a       a  2.875560 -2.809068 |
| 2       b       a  2.867109 -2.843691 |
| 3       a       b  3.137889 -2.960135 |
| 4       b       b  3.091169 -3.134296 |
+---------------------------------------+

x.1 是上限,x.2 是下限。我想对df 进行子集化,以便为每个因子水平组合删除异常值 - 例如在 aa 中,我不希望任何高于 2.88 或低于 -2.80 的值,但对于 ab,我希望上限为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)))),])

非常感谢任何指导。

【问题讨论】:

  • “x.2”是否也代表下限?
  • 是的,对不起!我会在问题中澄清。

标签: r aggregate outliers


【解决方案1】:

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

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

聚合您的原始数据框,结果列“y”是满足过滤条件的向量列表

df1 <- aggregate(y ~ x1 + x2, df, filt, simplify=FALSE)

然后复制指标变量,并取消列出向量列表,以达到最终表示

len <- sapply(df1$y, length)
result <- data.frame(x1=rep(df1$x1, len), x2=rep(df1$x2, len),
                     y=unlist(df1$y, use.names=FALSE))

【讨论】:

    【解决方案2】:

    这是使用plyr 的解决方案。它使用 split-apply-combine 范例。我们首先使用x1x2 列将数据框拆分为多个部分。对于每一块d(它是一个数据框),我们计算超出的限制,将y 视为异常值,然后使用逻辑索引仅返回那些不是异常值的d 行。最后,ddply 负责将所有子集片段组合到一个数据帧中。

    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,]
    })
    

    【讨论】:

    • 我最初尝试使用ddply,但没有成功。感谢您的解释,我现在了解如何更好地使用plyr
    【解决方案3】:

    我想你可以使用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
    

    【讨论】:

    • R 在我尝试最初创建boundaries 时报告Error in '[.default'(xj, i) : invalid subscript type 'closure'。知道会发生什么吗?
    • @luser,您的实际data.frame 是否称为“df”?您发布的这个示例数据集是否存在同样的问题?
    • 我的实际 data.frame 不称为 df 或任何其他系统保留名称。当我清除工作区并复制粘贴我放在这里的代码时,我遇到了同样的问题。
    • @luser,你使用的是什么版本的 R?
    • sessionInfo() 报告 3.0.2
    猜你喜欢
    • 1970-01-01
    • 2014-11-10
    • 2018-06-25
    • 2015-05-26
    • 1970-01-01
    • 2014-01-21
    • 2018-08-02
    • 1970-01-01
    • 2022-01-01
    相关资源
    最近更新 更多