90%对多个变量进行Winsorization

时间:2019-06-06 21:39:43

标签: r

在我的真实数据中,我对多个变量有多个异常值。我的数据看起来像下面的示例,但是数字是完全随机的。 我想使用winsorization提取大于或小于2 SD的所有数据点。

df<-read.table(header=T, text="id, group, test1, test2
1, 0, 57, 82
2, 0, 77, 80
3, 0, 67, 90
4, 0, 15, 70
5, 0, 58, 72
6, 1, 18, 44
7, 1, 44, 44
8, 1, 18, 46
9, 1, 20, 44
10, 1, 14, 38")

到目前为止,我已经使用以下代码为每个组的test1和test2变量确定了离群值:

outlier <- function(x, SD = 2){
  mu <- mean(x)
  sigma <- sd(x)
  out <- x < mu - SD*sigma | x > mu + SD*sigma
  out
}

# identify the outliers for each variable by each group
with(df, ave(test1, group, FUN = outlier))
with(df, ave(test2, group, FUN = outlier))

# add these new-found outliers to the data set
df$out1 <- with(df, ave(test1, group, FUN = outlier))
df$out2 <- with(df, ave(test2, group, FUN = outlier))

我知道'robustHD'软件包中的'winsorize'功能,但不确定: 1)。如何将命令调整为90%的winsorization(2 SD),2)。确保将Winsorization分为2个不同的组,3)。并在Winsorization中包含多个变量。

另外,但不是必须的.​​..是否有办法查看“ winsorize”功能将数字从更改为数字的情况了?

2 个答案:

答案 0 :(得分:1)

这是一个开始-希望有人为您提供更好的解决方案。

library(tidyverse)
df <- tibble::tribble(
  ~id, ~group, ~test1, ~test2,
  1,      0,     57,     82,
  2,      0,     77,     80,
  3,      0,     67,     90,
  4,      0,     15,     70,
  5,      0,     58,     72,
  6,      1,     18,     44,
  7,      1,     44,     44,
  8,      1,     18,     46,
  9,      1,     20,     44,
  10,      1,     14,     38
)
df
#> # A tibble: 10 x 4
#>       id group test1 test2
#>    <dbl> <dbl> <dbl> <dbl>
#>  1     1     0    57    82
#>  2     2     0    77    80
#>  3     3     0    67    90
#>  4     4     0    15    70
#>  5     5     0    58    72
#>  6     6     1    18    44
#>  7     7     1    44    44
#>  8     8     1    18    46
#>  9     9     1    20    44
#> 10    10     1    14    38

library(DescTools)
df %>%
  group_by(group) %>%
  mutate(
    test2_winsorized = DescTools::Winsorize(
      test2,
      maxval = quantile(df$test2, 0.90),
      minval = quantile(df$test2, 0.10)
    ),
    test1_winsorized = DescTools::Winsorize(
      test1,
      maxval = quantile(df$test1, 0.90),
      minval = quantile(df$test1, 0.10)
    )
  )
#> # A tibble: 10 x 6
#> # Groups:   group [2]
#>       id group test1 test2 test2_winsorized test1_winsorized
#>    <dbl> <dbl> <dbl> <dbl>            <dbl>            <dbl>
#>  1     1     0    57    82             82               57  
#>  2     2     0    77    80             80               68  
#>  3     3     0    67    90             82.8             67  
#>  4     4     0    15    70             70               15  
#>  5     5     0    58    72             72               58  
#>  6     6     1    18    44             44               18  
#>  7     7     1    44    44             44               44  
#>  8     8     1    18    46             46               18  
#>  9     9     1    20    44             44               20  
#> 10    10     1    14    38             43.4             14.9

reprex package(v0.2.1)于2019-06-06创建

答案 1 :(得分:1)

首先要弄清楚如何对数据进行存储。您有几种选择。

  1. 使用平均值+/- 2sd极限作为极值,并用这些极限值替换所有外部值
  2. 在平均+/- 2sd极限附近使用观测值
  3. 使用90%的分位数

在选项1和3中,您可能会将值引入Winsorized变量中,而未观察到这些值,在选项2中,您将仅观察到值。另请注意,如果您没有表现良好的正态分布数据,则(5%,95%)分位数不一定会接近2 * sd。

对于winsorization过程,您可以使用DescTools::Winsorize(),它接受​​极限的概率和值。

实施1)

x <- rnorm(100)
w1 <- Winsorize(x, 
                minval = mean(x) - 2*sd(x), 
                maxval = mean(x) + 2*sd(x))

对于2),您可以使用类似的

w2 <- Winsorize(x, 
                minval = max(Coalesce(x[x <= mean(x)-2*sd(x)], mean(x)-2*sd(x))), 
                maxval = min(Coalesce(x[x >= mean(x)+2*sd(x)], mean(x)+2*sd(x))))

为没有超出限制的值的情况提供一些递增的值。 Coalesce()返回第一个非空值,因此Winsorize()将始终获得有效限制。

选项3)是该功能的默认

w3 <- Winsorize(x, probs=c(0.05, 0.95))

为分组应用定义一个函数(此处为选项1):

df$w1 <- unsplit(
           tapply(df$test1, df$group,
                  function(x) Winsorize(x, 
                                        minval = mean(x) - 2*sd(x), 
                                        maxval = mean(x) + 2*sd(x)) )
         , f=df$group)

替换的值可以找到

cbind(x, w1)[x!=w1,]