【问题标题】:Remove outlier rows by column and factor in R在R中按列和因子删除异常值行
【发布时间】:2020-08-19 10:08:00
【问题描述】:

我正在使用 R 中的数据框。我有以下函数删除数据框 df 的所有行,其中,对于指定的列索引/属性,该行的值超出平均值(列)加或减 n*stdev(列)。

remove_outliers <- function(df,attr,n){
  outliersgone <- df[df[,attr]<=(mean(df[,attr],na.rm=TRUE)+n*sd(df[,attr],na.rm=TRUE)) & df[,attr]>=(mean(df[,attr],na.rm=TRUE)-n*sd(df[,attr],na.rm=TRUE)),]
  return(outliersgone)
}

我的问题分为两部分。

(1) 我的数据框df 也有一个“组”列,它指定了一个类标签。我希望能够根据列内组内的均值和标准差删除异常值,即按因子组织(在列内)。因此,如果在指定的列/属性中,该行的值超出平均值(该列中的 A 组行)加/减 n*stdev(组该列中的一行)。 B、C、D、E、F 等组也是如此。

我该怎么做? (最好只使用基本 R 和 dplyr。)我尝试使用 df %&gt;% group_by(Group) 后跟 mutate 但我不确定要传递什么来变异,因为我的函数 remove_outliers 似乎需要整个数据帧传递给它(因此它可以返回整个数据框,其中仅根据所选属性attr 删除行删除)。

我也愿意听取有关更改函数 remove_outliers 的建议,只要它们还按照说明返回整个数据帧。如果可能的话,我更喜欢避免循环的解决方案(除非不可避免且没有更有效的方法出现在基本 R / dplyr 中)。

(2) 有没有一种直接的方法可以跨多个列结合异常值考虑因素?例如从数据框df 中删除那些在指定的属性/列索引向量(长度≥N)中至少有 $N$ 个属性的异常值行。或更复杂的条件,例如,从数据框df 中删除属性 1 属性 2、4、6、8 中的至少 2 个异常值的行。

(理想情况下,异常值的定义将再次在列内的组内,如上面问题 1 中所述,但是在不考虑组的情况下仅在列内工作的解决方案对我也很有用。)

【问题讨论】:

    标签: r dataframe dplyr filtering outliers


    【解决方案1】:

    好的 - 第 1 部分(并尽可能避免循环):

    这是一些测试数据:

    test_data=data.frame(
        group=c(rep("a",100),rep("b",100)),
        value=rnorm(200)
    )
    

    我们会找到组:

    groups=levels(test_data[,1]) # or unique(test_data[,1]) if it isn't a factor
    

    我们将计算异常值限制(这里我只指定 1 sd)- 抱歉循环,但它只针对组,而不是数据:

    outlier_sds=1
    outlier_limits=sapply(groups,function(g) {
        m=mean(test_data[test_data[,1]==g,2])
        s=sd(test_data[test_data[,1]==g,2])
        return(c(m-outlier_sds*s,m+outlier_sds*s))
    })
    

    所以我们可以为test_data的每一行定义限制:

    test_data_limits=outlier_limits[,test_data[,1]]
    

    并使用它来确定异常值:

    outliers=test_data[,2]<test_data_limits[1,] | test_data[,2]>test_data_limits[2,]
    

    (或者,结合最后的步骤):

    outliers=test_data[,2]<outlier_limits[1,test_data[,1]] | test_data[,2]>outlier_limits[2,test_data[,1]]
    

    最后:

    test_data_without_outliers=test_data[!outliers,]
    

    编辑:现在是第 2 部分(应用第 1 部分,循环遍历数据中的所有列):

    一些包含多于一列值的测试数据:

    test_data2=data.frame(
        group=c(rep("a",100),rep("b",100)),
        value1=rnorm(200),
        value2=2*rnorm(200),
        value3=3*rnorm(200)
    )
    

    将第 1 部分的所有步骤组合成一个新函数 find_outliers,该函数返回一个逻辑向量,指示任何值是否是其各自列和组的异常值:

    find_outliers = function(values,n_sds,groups) {
        group_names=levels(groups)
        outlier_limits=sapply(group_names,function(g) {
            m=mean(values[groups==g])
            s=sd(values[groups==g])
            return(c(m-n_sds*s,m+n_sds*s))
        })
        return(values < outlier_limits[1,groups] | values > outlier_limits[2,groups])
    }
    

    然后将此函数应用于每个数据列:

    test_groups=test_data2[,1]
    test_data_outliers=apply(test_data2[,-1],2,function(d) find_outliers(values=d,n_sds=1,groups=test_groups))
    

    test_data_outliers 中的 rowSums 表示每一行在不同的列中被视为“异常值”的次数,相对于其自己的组:

    rowSums(test_data_outliers)
    

    【讨论】:

      猜你喜欢
      • 2020-11-17
      • 2017-11-28
      • 2018-10-03
      • 2019-09-30
      • 2022-01-22
      • 2012-08-11
      • 1970-01-01
      • 2018-10-08
      相关资源
      最近更新 更多