Игнорировать выбросы в бокс-графике ggplot2

132

Как мне игнорировать выбросы в диаграмме ggplot2? Я не хочу, чтобы они просто исчезли (т.е. outlier.size = 0), но я хочу, чтобы они игнорировались, чтобы ось y масштабировалась для отображения 1-го / 3-го процентиля. Мои выбросы заставляют «коробку» сжиматься настолько мало, что это практически линия. Есть ли какие-то способы справиться с этим?

Изменить Вот пример:

y = c(.01, .02, .03, .04, .05, .06, .07, .08, .09, .5, -.6)
qplot(1, y, geom="boxplot")

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

SFun28
источник
Некоторые образцы данных и воспроизводимый пример упростят вам задачу.
Андри
3
у меня файл 200 мег! Просто возьмите любой набор данных, в котором есть много точек данных между 1-м и 3-м квантилями и несколько выбросов (вам нужен только 1). Если выброс далеко от 1-го / 3-го, тогда коробки обязательно уменьшатся, чтобы вместить выброс
SFun28
Да, это то, что я имел в виду. Составьте такой набор данных и используйте dput (), чтобы опубликовать его здесь вместе с оператором ggplot (), который вы используете. Помогите нам помочь вам.
Андри
Разве вы не можете просто изменить пределы оси Y, чтобы "увеличить" интересующую вас часть оси Y?
Гэвин Симпсон
2
дай мне посмотреть .... Ах да, извини. Просто сделайте fivenum()с данными, чтобы извлечь то, что, IIRC, используется для верхних и нижних петель на коробчатых диаграммах, и используйте этот вывод в scale_y_continuous()вызове, который показал @Ritchie. Это можно очень легко автоматизировать с помощью инструментов, предоставляемых R и ggplot. Если вам нужно включить усы, подумайте об использовании, boxplot.stats()чтобы получить верхний и нижний пределы для усов, и используйте их в scale_y_continuous().
Гэвин Симпсон

Ответы:

141

Вот решение с использованием boxplot.stats

# create a dummy data frame with outliers
df = data.frame(y = c(-100, rnorm(100), 100))

# create boxplot that includes outliers
p0 = ggplot(df, aes(y = y)) + geom_boxplot(aes(x = factor(1)))


# compute lower and upper whiskers
ylim1 = boxplot.stats(df$y)$stats[c(1, 5)]

# scale y limits based on ylim1
p1 = p0 + coord_cartesian(ylim = ylim1*1.05)
Ramnath
источник
15
+1 для автоматического вычисления, +1 для использования кортежа_картезианского для масштабирования, а не исключения данных
Бен Болкер
2
@Ben - у вас два аккаунта? =) @Ramnath - это действительно элегантное решение
SFun28
7
Используя вышеупомянутый метод, пределы могут смещаться из-за небольшого предела с одной стороны и большого предела с другой, например, ylim <- c(-0.1, 1000) * 1.05дает [1] 0.105 1050. Чтобы получить равные пределы вокруг среднего, вы можете использовать ylim + c(-0.05, 0.05) * diff(ylim) / 2. На мой взгляд красивее.
Брэм Виссер,
2
@Ramnath, что делает $ stats [c (1,5)]?
Люкег
3
Не работает, если вы используете facet_grid(). Тогда у вас будет несколько коробчатых диаграмм вместо одного. Таким образом, вы не получаете правильных ограничений.
WitheShadow
204

использование geom_boxplot(outlier.shape = NA) чтобы не отображать выбросы и scale_y_continuous(limits = c(lower, upper))изменить пределы оси.

Пример.

n <- 1e4L
dfr <- data.frame(
  y = exp(rlnorm(n)),  #really right-skewed variable
  f = gl(2, n / 2)
)

p <- ggplot(dfr, aes(f, y)) + 
  geom_boxplot()
p   # big outlier causes quartiles to look too slim

p2 <- ggplot(dfr, aes(f, y)) + 
  geom_boxplot(outlier.shape = NA) +
  scale_y_continuous(limits = quantile(dfr$y, c(0.1, 0.9)))
p2  # no outliers plotted, range shifted

На самом деле, как показал Рамнат в своем ответе (и Андри тоже в комментариях), имеет смысл обрезать шкалы после расчета статистики с помощью coord_cartesian .

coord_cartesian(ylim = quantile(dfr$y, c(0.1, 0.9)))

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

Ричи Коттон
источник
1
Итак, мне пришлось бы вычислить нижнее / верхнее - возможно, вычислив 1-й / 3-й процентиль? Это означает, что нет автоматического магического способа указать gg-plot2 игнорировать выбросы и разумно масштабироваться?
SFun28,
38
Будьте осторожны с scale_y_continuous (limits = ...). Это удалит данные, выходящие за пределы, а затем выполнит статистические вычисления. Другими словами, это повлияет на среднее значение и другие итоги. Если это то, чего вы хотите, тогда отлично. Альтернативой является использование декартовой координаты (limits = ...) - это «увеличение» без удаления данных или влияния на итоги.
Андри
@Andrie - спасибо! Я не хочу, чтобы это повлияло на скупые и прочие резюме.
SFun28,
1
coord_cartesian()не очень хорошо сочетается с coord_flip(), по моему опыту, поэтому я предпочитаю scale_y_continuous().
PatrickT
1
Это лучшее решение. Причина, по которой я хочу скрыть выбросы, заключается в том, что я также рисую точки с колебаниями с помощью geom_jitter. В этом случае выбросы просто мешают и создают впечатление, что точек больше, чем должно быть.
williamsurles
14

У меня была та же проблема, и я предварительно вычислил значения для Q1, Q2, median, ymin, ymax, используя boxplot.stats:

# Load package and generate data
library(ggplot2)
data <- rnorm(100)

# Compute boxplot statistics
stats <- boxplot.stats(data)$stats
df <- data.frame(x="label1", ymin=stats[1], lower=stats[2], middle=stats[3], 
                 upper=stats[4], ymax=stats[5])

# Create plot
p <- ggplot(df, aes(x=x, lower=lower, upper=upper, middle=middle, ymin=ymin, 
                    ymax=ymax)) + 
    geom_boxplot(stat="identity")
p

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

Маттиас Мунц
источник
9

Одна из идей заключалась бы в том, чтобы выиграть данные в двухпроходной процедуре:

  1. запустите первый проход, узнайте, каковы границы, например, отсечение по заданному процентилю, или стандартное отклонение N выше среднего, или ...

  2. во втором проходе установите значения за заданной границей на значение этой границы

Я должен подчеркнуть, что это старомодный метод, в котором должны преобладать более современные надежные методы, но вы все равно часто с ним сталкиваетесь.

Дирк Эддельбюттель
источник
1
Кто только downvoted молча : Оставить комментарий , чтобы объяснить , почему .
Дирк Эддельбюттель
Не я. Просто хотел добавить, что наличие усов, которые ограничиваются процентилями (обычно 10-м и 90-м), кажется, очень распространено в данных об окружающей среде.
Ричи Коттон
Я был молчаливым +1 и хотел бы предложить еще один. Winsorizing почти всегда делается в econ + financial. Если у SFun есть выбросы, которые портят визуализацию данных, мне интересно, как они влияют на анализ данных.
Ричард Херрон,
перечитывал этот пост, вы упомянули, что виндзоризация - более старая техника ... какие методы можно было бы сделать более современными?
SFun28
1
В общем, надежные методы как разработка последних 30+ лет.
Дирк Эддельбюттель
2

Параметр "coef" функции geom_boxplot позволяет изменять отсечение выбросов в терминах межквартильных диапазонов. Эта опция задокументирована для функции stat_boxplot. Чтобы деактивировать выбросы (другими словами, они обрабатываются как обычные данные), можно вместо использования значения по умолчанию 1,5 указать очень высокое значение отсечки:

library(ggplot2)
# generate data with outliers:
df = data.frame(x=1, y = c(-10, rnorm(100), 10)) 
# generate plot with increased cutoff for outliers:
ggplot(df, aes(x, y)) + geom_boxplot(coef=1e30)
Эккарт
источник
3
Он просто удлиняет усы, он не
изменяет
2

Если вы хотите заставить усы увеличиваться до максимального и минимального значений, вы можете настроить coefаргумент. Значение по умолчанию coef- 1,5 (т.е. длина усов по умолчанию в 1,5 раза превышает IQR).

# Load package and create a dummy data frame with outliers 
#(using example from Ramnath's answer above)
library(ggplot2)
df = data.frame(y = c(-100, rnorm(100), 100))

# create boxplot that includes outliers
p0 = ggplot(df, aes(y = y)) + geom_boxplot(aes(x = factor(1)))

# create boxplot where whiskers extend to max and min values
p1 = ggplot(df, aes(y = y)) + geom_boxplot(aes(x = factor(1)), coef = 500)

изображение p0

изображение p1

IggyM
источник
2

Ipaper :: geom_boxplot2 - это именно то, что вам нужно.

# devtools::install_github('kongdd/Ipaper')
library(Ipaper)
library(ggplot2)
p <- ggplot(mpg, aes(class, hwy))
p + geom_boxplot2(width = 0.8, width.errorbar = 0.5)

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

Dongdong Kong
источник
Спасибо!! Протестировано с моими данными, работает отлично! Я бы рекомендовал это решение, хотя я не уверен в стабильности / длительной поддержке вещей github.
Гильдас