【问题标题】:How can I remove outliers (numbers 3 standard deviations away from the mean) in each column of a data frame如何在数据框的每一列中删除异常值(距离平均值 3 个标准差)
【发布时间】:2019-03-25 11:38:31
【问题描述】:

我有一个数据集,其中包含参与者 IDS 和每个参与者的 17 种不同测量值。

我需要删除离均值 3 个标准差的异常值。这需要针对每一列单独进行。

到目前为止,通过使用下面的代码,我已经设法将 NA 添加到每列的异常列中,但这对我没有多大帮助,因为我需要能够将 NA 与其余列一起添加到列中的数字或简单地删除异常值

理想情况下,我希望获得如下所示的文件:

ID measure1 measure2 ....measure17
1  10897                  64436
2  184658    1739473
3            75758
4  746483    4327349      3612638
5  6444      36363        46447

到目前为止我使用过的代码:

phenotypes <- colnames(imaging_data_kept[,2:ncol(imaging_data_kept)])

 for (i in phenotypes){
  Min <- mean(imaging_data_kept[[i]]) - (3*sd(imaging_data_kept[[i]]))
  Max <- mean(imaging_data_kept[[i]]) + (3*sd(imaging_data_kept[[i]]))  
  imaging_data_kept[[paste0(i,"_outliers")]] <- imaging_data_kept[[i]] < 
  Min | imaging_data_kept[[i]] > Max
 }

样本数据:

SubjID M1 M2 M3 M4 M5 
1000496 14898.1 9172 4902 5921.9 1428.2 
1001121 5420.7 2855.5 4144 732.1 4960.2 
1001468 7478.8 3401.4 5143.6 1106.5 4355.5 
1004960 11316.4 8460.1 3953.4 5682.2 1717 
1005040 15052.7 6362.8 3145.2 4593 1214.5  
1005677 17883.3 6705.1 3943.5 4993.1 1373.1 
1006128 6260.8 4274.6 5865 2002.3 4727.1 
1006694 9292.8 3389.9 5141.6 1246.6 4135.7 
1009080 10391.3 8372.1 2921.8 4008.6 860.4 
1010482 9381.5 2743.4 4526.5 1160.4 3655.1 
1011508 15598.5 7365.7 4279.4 6274.1 1757.1 

【问题讨论】:

  • 你有一些我们可以使用的示例数据吗?
  • SubjID M1 M2 M3 M4 M5 1000496 14898.1 9172 4902 5921.9 1428.2 1001121 5420.7 2855.5 4144 732.1 4960.2 1001468 7478.8 3401.4 5143.6 1106.5 4355.5 1004960 11316.4 8460.1 3953.4 5682.2 1717 1005040 15052.7 6362.8 3145.2 4593 1214.5 1005677 17883.3 6705.1 3943.5 4993.1 1373.1 10061271 5141.6 1246.6 4008.6 860.4 10143721/1914436521/40013721921/30137281,411193659998981/303655991/3015598/3436553990×42798年4月4日,6276.1111236598,472.3 4008.6,6276,62.3,4008.4,62.3。

标签: r


【解决方案1】:

这将用 NA 替换与平均值相差超过 3 SD 的值:

dd[,-1] <- lapply(dd[,-1],
      function(x) replace(x,abs(scale(x))>3,NA))

scale() 函数计算 (x-mean(x))/sd(x)abs(scale(x))&gt;3 应该是不言自明的;replace() 用指示的值替换一组指定的索引。)

如果要删除任何列中包含异常值的所有行,则可以使用 na.omit(dd)

您提供给我们的样本数据似乎没有任何异常值(根据您的定义)——我添加了一些。


dd <- read.table(header=TRUE,
                 colClasses=c("character",rep("numeric",5)),
                 text="
SubjID M1 M2 M3 M4 M5 
1000496 14898.1 9172 4902 5921.9 1428.2 
1001121 5420.7 2855.5 4144 732.1 100000
1001468 7478.8 3401.4 5143.6 1106.5 4355.5 
1004960 11316.4 8460.1 3953.4 5682.2 1717 
1005040 15052.7 6362.8 3145.2 4593 1214.5  
1005677 17883.3 6705.1 100000 4993.1 1373.1 
1006128 6260.8 4274.6 5865 2002.3 4727.1 
1006694 9292.8 3389.9 5141.6 1246.6 4135.7 
1009080 10391.3 8372.1 2921.8 4008.6 860.4 
1010482 9381.5 2743.4 4526.5 1000000 3655.1 
1011508 15598.5 7365.7 4279.4 6274.1 1757.1
")

【讨论】:

    【解决方案2】:

    我建议使用计算异常值的boxplot()- 函数。您可以通过boxplot$out 在您的boxplot 对象中访问它们或通过boxplot$stats 获取分位数。我接下来要做什么。

    但请注意,boxplot 不会根据 3 个标准差计算异常值,而是分别使用 Q1 - 1.5*IQRQ3 + 1.5*IQR

    
    library(dplyr) # for the pipe operators
    
    #creating sample data 
    df <- data.frame("var1" = c(-20.32, -15.29, rnorm(5,1,1), 11.23, 20.45),
                     "var2" = c(-12.43, -3.12, rnorm(5, 1,1), 10.75, 18.11))
    
    #looks like that
    > df
             var1        var2
    1 -20.3200000 -12.4300000
    2 -15.2900000  -3.1200000
    3   0.9950276   1.2645415
    4   1.7022687   0.8313770
    5   1.8828154  -0.7459769
    6   1.2299670   0.5053378
    7   0.2749259   2.0239793
    8  11.2300000  10.7500000
    9  20.4500000  18.1100000
    
    #remove outliers
    nooutliers <- lapply(df, function(x) boxplot(df, plot = FALSE)) %>%
                    lapply(`[`, "stats") %>% 
                      lapply(range) %>%
                        mapply(function (x,y) !between(x, y[1], y[2]), df, .) %>%
                          as.data.frame %>%
                            mapply(function(x,y) {y[x] <- NA; y},  
                                   y = df, x = .)
    
    #looks like this now
    > nooutliers
               var1       var2
     [1,]        NA         NA
     [2,]        NA -3.1200000
     [3,] 0.9950276  1.2645415
     [4,] 1.7022687  0.8313770
     [5,] 1.8828154 -0.7459769
     [6,] 1.2299670  0.5053378
     [7,] 0.2749259  2.0239793
     [8,]        NA         NA
     [9,]        NA         NA
    
    

    此代码计算每列的须线内的范围,将NA 分配给此范围外的所有值并返回一个矩阵。

    我想这就是你要找的。​​p>

    更新:有 3 个标准差:

    df <- data.frame("var1" = c(-210.32, rnorm(20,1,1), 234.45),
                     "var2" = c(-230.43, rnorm(20, 1,1), 213.11))
    
    
    phenotypes <- colnames(df)
    
    for (i in phenotypes){
      Min <- mean(df[[i]]) - (3*sd(df[[i]]))
      Max <- mean(df[[i]]) + (3*sd(df[[i]]))  
      df[[i]][df[[i]] < Min | df[[i]] > Max] <- NA}
    
    

    这采用了您的异常值定义。

    【讨论】:

    • 但是boxplot 并没有将异常值识别为 OP 给出的“距离平均值 3 个标准差”。它有自己的异常值定义,所以这个解决方案不起作用。
    • 你是绝对正确的。我错过了那部分。我更新了。
    • 非常感谢!有用!但是你能解释一下你是如何将它设置为 3 个标准差的吗?如果我想要 2、1.5 等,我将如何改变它?
    • 事实上,正如弗利克先生所说,我没有。 boxplot 有自己的异常值定义,无法更改。我错过了你关于三个标准差的问题。
    • 我看到了@Humpelstielzchen。我认为它已经更新了,因为我的代码和 excel 过滤结果相同(我真的不想长期这样做)。任何进一步的帮助都会很棒,谢谢
    猜你喜欢
    • 2018-01-21
    • 2020-10-19
    • 2022-07-05
    • 2018-10-27
    • 2021-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    相关资源
    最近更新 更多