Как удалить выбросы из набора данных

98

У меня есть многомерные данные о красоте и возрастах. Возраст варьируется от 20 до 40 с интервалом 2 (20, 22, 24 .... 40), и для каждой записи данных им дается возраст и оценка красоты от 1 до 5. Когда я строю прямоугольные диаграммы этих данных (возраст по оси X, оценки красоты по оси Y), за пределами усов каждого прямоугольника отображаются некоторые выбросы.

Я хочу удалить эти выбросы из самого фрейма данных, но я не уверен, как R вычисляет выбросы для своих ящичных диаграмм. Ниже приведен пример того, как могут выглядеть мои данные. введите описание изображения здесь

Дэн Кью
источник
2
boxplotФункция возвращает выбросы (среди других статистических данных) невидимо. Попробуйте foo <- boxplot(...); fooпрочитать, ?boxplotчтобы понять вывод.
Джошуа Ульрих
Вы должны отредактировать свой вопрос в соответствии с комментарием, который вы дали на ответ @Prasad!
aL3xa
@ aL3xa: это первое предложение второго абзаца.
Джошуа Ульрих
24
Релевантно: davidmlane.com/ben/outlier.gif
eyjo
Можете ссылку на данные прислать?
wordsforward 02

Ответы:

120

Хорошо, вы должны применить что-то подобное к своему набору данных. Не заменяйте и не сохраняйте, иначе вы уничтожите свои данные! И, кстати, вы (почти) никогда не должны удалять выбросы из своих данных:

remove_outliers <- function(x, na.rm = TRUE, ...) {
  qnt <- quantile(x, probs=c(.25, .75), na.rm = na.rm, ...)
  H <- 1.5 * IQR(x, na.rm = na.rm)
  y <- x
  y[x < (qnt[1] - H)] <- NA
  y[x > (qnt[2] + H)] <- NA
  y
}

Чтобы увидеть это в действии:

set.seed(1)
x <- rnorm(100)
x <- c(-10, x, 10)
y <- remove_outliers(x)
## png()
par(mfrow = c(1, 2))
boxplot(x)
boxplot(y)
## dev.off()

И еще раз: вы никогда не должны делать это в одиночку, выбросы просто должны быть! знак равно

РЕДАКТИРОВАТЬ: я добавил na.rm = TRUEпо умолчанию.

РЕДАКТИРОВАТЬ2: Удалена quantileфункция, добавлены индексы, следовательно, функция стала быстрее! знак равно

введите описание изображения здесь

aL3xa
источник
Спасибо за помощь! Я бы подумал, что если R способен выводить выбросы в коробчатой ​​диаграмме, мне не нужно делать эти промежуточные вычисления. Что касается удаления выбросов, это просто задание.
Dan Q
3
Хорошо, я кое-что упустил. Вы хотите удалить выбросы из данных, чтобы их можно было построить с помощью boxplot. Это выполнимо, и тогда вы должны отметить ответ @Prasad, поскольку он ответил на ваш вопрос. Если вы хотите исключить выбросы с помощью «правила выбросов»q +/- (1.5 * H) , следовательно, провести некоторый анализ, используйте эту функцию. Кстати, я сделал это с нуля, без поиска в Google, так что есть шанс, что я заново изобрел колесо с этой моей функцией ...
aL3xa
10
Вы не должны задавать вопросы о назначении в stackoverflow!
Хэдли
7
Значит ли это, что нам тоже не стоит отвечать? =)
aL3xa
5
"выбросы просто должны быть"? Не обязательно. Они могут возникать из-за ошибок измерения и должны быть тщательно проверены. Когда выброс слишком велик, это может означать что-то или не очень. Вот почему (по крайней мере, в биологии) медиана обычно говорит больше о популяции, чем среднее значение.
Родриго
133

Никто не опубликовал простейшего ответа:

x[!x %in% boxplot.stats(x)$out]

Также см. Это: http://www.r-statistics.com/2011/01/how-to-label-all-the-outliers-in-a-boxplot/

J. Win.
источник
4
Действительно элегантно. Спасибо. Но нужно быть осторожным, если распределение имеет более одного режима, а выбросы действительно немногочисленны и разбросаны.
KarthikS
Было бы здорово, если бы вы смогли получить их индекс в наборе данных. То, как вы это сделаете, будет фильтровать на основе значения данных. Если коробчатая диаграмма также выполняет группировку, не обязательно одно и то же значение данных будет выпадать в каждой группе
Адам
2
Также важно отметить, что это не меняет набор данных. Это всего лишь метод фильтрации. Поэтому, если вы собираетесь использовать набор данных без выбросов, присвойте его переменной. напримерresult = x[!x %in% boxplot.stats(x)$out]
Виктор Аугусто
Наличие всего одной строчки кода не обязательно означает, что это просто! Не всегда легко разобраться в однострочном коде, особенно для начинающих, и без комментариев.
PeyM87
29

Используйте outline = FALSEкак вариант при построении коробчатой ​​диаграммы (прочтите справку!).

> m <- c(rnorm(10),5,10)
> bp <- boxplot(m, outline = FALSE)

введите описание изображения здесь

Прасад Чаласани
источник
4
действительно, это удалит выбросы из самой диаграммы, но я хочу удалить выбросы из кадра данных.
Dan Q
2
Я вижу, то , как @Joshua сказал , что вы должны смотреть на данные , возвращаемые boxplot функции (в частности, outи groupпункты в списке).
Prasad Chalasani
16

Функция boxplot возвращает значения, используемые для построения графика (что на самом деле выполняется с помощью bxp ():

bstats <- boxplot(count ~ spray, data = InsectSprays, col = "lightgray") 
#need to "waste" this plot
bstats$out <- NULL
bstats$group <- NULL
bxp(bstats)  # this will plot without any outlier points

Я намеренно не ответил на конкретный вопрос, потому что считаю статистической халатностью удаление «выбросов». Я считаю приемлемой практикой не наносить их на коробчатую диаграмму, а удаление их только потому, что они превышают некоторое количество стандартных отклонений или некоторое количество межквартильных ширин, является систематическим и ненаучным искажением данных наблюдений.

IRTFM
источник
4
Что ж, уходить от вопроса, не зная, почему был задан вопрос, тоже не лучшая практика. Да, нецелесообразно удалять «выбросы» из данных, но иногда вам нужны данные без выбросов для конкретных задач. В недавно полученном мной задании по статистике нам нужно было визуализировать набор без выбросов, чтобы определить лучшую регрессионную модель для использования для данных. Так что!
Alex Essilfie
4
Я не считаю совет, который вы, возможно, получили по этому поводу, «определить лучшую регрессионную модель», особенно убедительным. Вместо этого, если вам нужно было удалить выбросы для этой расплывчато заявленной цели, то я думаю, что это плохо отразится на людях, которые это посоветовали, а не свидетельствует о недействительности моей позиции.
IRTFM
Я думаю, это законно, когда ты знаешь, что удаляешь "шум". особенно в физиологических данных.
roscoe1895
Да. Если у вас есть веские основания полагать, что отдельный процесс создает сигнал, это оправдание для удаления из данных.
IRTFM
9

Я искал пакеты, связанные с удалением выбросов, и нашел этот пакет (неожиданно названный «выбросами»!): Https://cran.r-project.org/web/packages/outliers/outliers.pdf,
если вы пройдете через него, вы см. различные способы удаления выбросов, и среди них я нашел rm.outlierнаиболее удобный для использования, и, как сказано в приведенной выше ссылке: «Если выброс обнаружен и подтвержден статистическими тестами, эта функция может удалить его или заменить на выборочное среднее или медианное значение» а также часть использования из того же источника:
" Использование

rm.outlier(x, fill = FALSE, median = FALSE, opposite = FALSE)

Аргументы
x набор данных, чаще всего вектор. Если аргументом является фрейм данных, то sapply удаляет выброс из каждого столбца. То же поведение применяется с помощью apply, когда задана матрица.
fill Если установлено значение TRUE, вместо выброса помещается медиана или среднее значение. В противном случае выбросы просто удаляются.
median Если установлено значение TRUE, при замене выбросов вместо среднего используется медиана. напротив, если установлено значение ИСТИНА, дает противоположное значение (если наибольшее значение имеет максимальное отличие от среднего, дает наименьшее и наоборот) "

Пейман
источник
Это кажется отличным, но если у вас есть столбец временного ряда во фрейме данных, он меняет временной ряд.
PeyM87
7
x<-quantile(retentiondata$sum_dec_incr,c(0.01,0.99))
data_clean <- data[data$attribute >=x[1] & data$attribute<=x[2],]

Я считаю, что это очень легко удалить выбросы. В приведенном выше примере я просто извлекаю от 2 до 98 процентилей значений атрибутов.

Гаурав Харе
источник
5

Не будет:

z <- df[df$x > quantile(df$x, .25) - 1.5*IQR(df$x) & 
        df$x < quantile(df$x, .75) + 1.5*IQR(df$x), ] #rows

справиться с этой задачей довольно легко?

d8aninja
источник
4

Добавив к предложению @sefarkas и используя квантиль в качестве отсечки, можно было бы изучить следующий вариант:

newdata <- subset(mydata,!(mydata$var > quantile(mydata$var, probs=c(.01, .99))[2] | mydata$var < quantile(mydata$var, probs=c(.01, .99))[1]) ) 

Это удалит точки за пределами 99-го квантиля. Следует проявлять осторожность, как то, что aL3Xa говорил о сохранении выбросов. Его следует удалять только для получения альтернативного консервативного представления данных.

KarthikS
источник
это 0.91или 0.99? как в mydata$var < quantile(mydata$var, probs=c(.01, .91))[1])илиmydata$var < quantile(mydata$var, probs=c(.01, .99))[1])
Комал Rathi
Если у вас есть конкретная причина использовать 91-й процентиль вместо 99-го процентиля, вы можете его использовать. Это всего лишь эвристика
KarthikS
1

1 способ сделать это

my.NEW.data.frame <- my.data.frame[-boxplot.stats(my.data.frame$my.column)$out, ]

или

my.high.value <- which(my.data.frame$age > 200 | my.data.frame$age < 0) 
my.NEW.data.frame <- my.data.frame[-my.high.value, ]
Сейма Калай
источник
0

Выбросы очень похожи на пики, поэтому детектор пиков может быть полезен для выявления выбросов. Описанный здесь метод имеет неплохую производительность с использованием z-значений. Анимация частично вниз по странице иллюстрирует метод, сигнализирующий о выбросах или пиках.

Пики не всегда совпадают с выбросами, но часто они похожи.

Здесь показан пример: Этот набор данных считывается с датчика по последовательной связи. Случайные ошибки последовательной связи, ошибка датчика или и то, и другое приводят к повторяющимся, явно ошибочным точкам данных. В этом пункте нет статистической ценности. Возможно, это не выбросы, а ошибки. Детектор пиков z-значений смог сигнализировать о ложных точках данных и сгенерировал чистый результирующий набор данных:введите описание изображения здесь

Марк Компере
источник
-1

Попробуй это. Подайте свою переменную в функцию и сохраните o / p в переменной, которая будет содержать удаленные выбросы

outliers<-function(variable){
    iqr<-IQR(variable)
    q1<-as.numeric(quantile(variable,0.25))
    q3<-as.numeric(quantile(variable,0.75))
    mild_low<-q1-(1.5*iqr)
    mild_high<-q3+(1.5*iqr)
    new_variable<-variable[variable>mild_low & variable<mild_high]
    return(new_variable)
}
Адипта Бивас
источник
Пожалуйста, добавьте пояснение к своему ответу. См. Как ответить .
ejderuby