Устранение точек выброса данных в R

#r #dataframe #data-cleaning #outliers

#r #фрейм данных #очистка данных #выбросы

Вопрос:

У меня есть фрейм данных, который немного похож на этот воспроизводимый код, и я хочу удалить выбросы (в нашем случае точки данных ниже или выше 2,5 стандартных отклонений от среднего значения) для каждого столбца, не удаляя весь объект / строку целиком.

 Subj <- c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J")
Var1 <- c("1", "5", "100", "0.1", "3", "5", "2", "3", "2.5", "4")
Var2 <- sample(1:10, 10, replace=TRUE)
Var3 <- runif(10, min=0, max=700)
Var4 <- c("0.5", "0.1", "23", "0.2", "0.4", "0.6", "0.12", "0.3", "0.25", "-75")

df <- as.data.frame(cbind(Subj, Var1, Var2, Var3, Var4))

df$Var1_scale <- scale(as.numeric(df$Var1), scale = TRUE)
df$Var2_scale <- scale(as.numeric(df$Var2))
df$Var3_scale <- scale(as.numeric(df$Var3))
df$Var4_scale <- scale(as.numeric(df$Var4))
  

Я бы хотел исключить две точки данных — 100 для Var1 и -75 для Var4 на основе масштабированных переменных. Каков наилучший способ сделать это? Я всегда рассматриваю это как устранение строк, но это не цель здесь.

Вывод будет выглядеть примерно так (т. е. пустое пространство вместо выброса)

    Subj Var1 Var2             Var3 Var4 Var1_scale Var2_scale Var3_scale Var4_scale
1     A    1    9 82.5652090134099  0.5 -0.3757658  0.8660254 -1.2116275  0.2128018
2     B    5    2 606.970524415374  0.1 -0.2457431 -1.1547005  1.2318109  0.1971919
3     C         9 422.833283618093   23  2.8422981  0.8660254  0.3738333  1.0908581
4     D  0.1   10 100.154890632257  0.2 -0.4050210  1.1547005 -1.1296693  0.2010944
5     E    3    4 144.251625519246  0.4 -0.3107545 -0.5773503 -0.9242029  0.2088993
6     F    5    2 310.489796195179  0.6 -0.2457431 -1.1547005 -0.1496251  0.2167043
7     G    2    8 624.485966027714 0.12 -0.3432602  0.5773503  1.3134231  0.1979724
8     H    3    3 617.240970185958  0.3 -0.3107545 -0.8660254  1.2796654  0.2049969
9     I  2.5   10 293.290452379733 0.25 -0.3270073  1.1547005 -0.2297645  0.2030456
10    J    4    3 223.737383470871      -0.2782488 -0.8660254 -0.5538433 -2.7335648
  

Ответ №1:

Вместо замены их на пустые, замените их на NA , чтобы классы поддерживались.

 cols <- paste0('Var', 1:4)
mat <- sapply(df[cols], function(x) {
  mn <- mean(x, na.rm = TRUE)
  sd <- sd(x, na.rm = TRUE)
  (x > mn   sd * 2.5) | (x < mn - sd * 2.5)
})
df[cols][mat] <- NA

df
#   Subj Var1 Var2      Var3  Var4
#1     A  1.0    2 383.35261  0.50
#2     B  5.0    8 498.22071  0.10
#3     C   NA    6 272.23357 23.00
#4     D  0.1    1  70.61119  0.20
#5     E  3.0    2 649.11146  0.40
#6     F  5.0    7 198.26275  0.60
#7     G  2.0    7 413.40121  0.12
#8     H  3.0    4  77.25242  0.30
#9     I  2.5    9 588.35492  0.25
#10    J  4.0    8 222.57458    NA
  

данные

Вы создали dataset таким образом, что числа преобразуются в символы, что затрудняет выполнение над ними каких-либо математических вычислений. Я использую type.convert для изменения их на исходные классы.

 df <- type.convert(df)
  

Комментарии:

1. Не уверен, почему, но у меня это не работает. Не работает ни для моих данных, ни для воспроизводимого примера. «mat» для меня — это просто NA для всего.

2. Если вы используете R < 4.0.0, выполните 1) df <- data.frame(Subj, Var1, Var2, Var3, Var4, stringsAsFactors = FALSE) и 2) df <- type.convert(df) и повторите попытку ответа.

3. Я не знаю, как определить выбросы, хотя в базе R есть функция выбросов для вас. т.е., x<- boxplot(scale(df[-1)); x$out; x$group где x$out — выбросы, а x$group — столбцы, из которых произошли выбросы. База R использует fivenum метод.

4. @RonakShah Что бы вы сделали, если бы фрейм данных был из csv-файла, вы бы просто сделали df <- data.frame(df, stringsAsFactors = FALSE)? Кроме того, этот бит «cols <- paste0(‘Var’, 1: 4)» автоматически определяет, к какому фрейму данных вы обращаетесь? Что следует делать, если столбцы имеют разные имена? будет ли работать paste0(select(name:название))?

5. Достаточно @CatM, если вы считываете данные из csv-файла df <- read.csv('csv_file_name.csv', stringsAsFactors = FALSE) . cols должны быть имена столбцов, к которым вы хотите обратиться NA . Здесь у вас есть Var1 , Var2`, поэтому я использовал ярлык для его генерации с помощью paste0 . Если ваши фактические имена столбцов «abc», «efg», вы должны написать cols <- c("abc", "efg")