Ignoruj ​​wartości odstające w wykresie pudełkowym ggplot2

135

Jak mógłbym zignorować wartości odstające w wykresie pudełkowym ggplot2? Nie chcę, aby po prostu zniknęły (tj. Outlier.size = 0), ale chcę, aby były ignorowane w taki sposób, aby oś y skalowała się tak, aby pokazywała 1/3 percentyl. Moje wartości odstające powodują, że „pudełko” kurczy się tak małe, że jest praktycznie linią. Czy są jakieś techniki radzenia sobie z tym?

Edycja Oto przykład:

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

wprowadź opis obrazu tutaj

SFun28
źródło
Niektóre przykładowe dane i odtwarzalny przykład ułatwią Ci udzielenie pomocy.
Andrie
3
mój plik ma 200 MB! Po prostu weź dowolny zbiór danych, w którym istnieje wiele punktów danych między 1. a 3. kwantylem i kilka wartości odstających (potrzebujesz tylko 1). Jeśli wartość odstająca jest daleko od
1/3,
Tak, to właśnie miałem na myśli. Utwórz taki zbiór danych i użyj dput (), aby opublikować go tutaj razem z instrukcją ggplot (), której używasz. Pomóż nam, aby pomóc sobie.
Andrie
Czy nie możesz po prostu zmienić granic osi Y, aby „powiększyć” część osi Y, która Cię interesuje?
Gavin Simpson
2
pozwól mi spojrzeć ... O tak, przepraszam. Po prostu zrób fivenum()na danych, aby wyodrębnić to, co, IIRC, jest używane dla górnych i dolnych zawiasów na wykresach pudełkowych i użyj tego wyniku w scale_y_continuous()wywołaniu, które pokazał @Ritchie. Można to bardzo łatwo zautomatyzować za pomocą narzędzi dostarczanych przez R i ggplot. Jeśli musisz uwzględnić również wąsy, rozważ użycie, boxplot.stats()aby uzyskać górną i dolną granicę wąsów, a następnie użyj scale_y_continuous().
Gavin Simpson

Odpowiedzi:

143

Oto rozwiązanie wykorzystujące 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
źródło
17
+1 do obliczeń automatycznych, +1 za użycie kodu koordynacyjnego do powiększania zamiast wykluczania danych
Ben Bolker,
3
@Ben - masz dwa konta? =) @Ramnath - to jest naprawdę eleganckie rozwiązanie
SFun28
7
Stosując powyższą metodę, limity mogą zostać przesunięte przez małą skrajność z jednej strony i dużą skrajność z drugiej, np . ylim <- c(-0.1, 1000) * 1.05Daje [1] 0.105 1050. Aby uzyskać równe limity wokół średniej, której możesz użyć ylim + c(-0.05, 0.05) * diff(ylim) / 2. Moim zdaniem ładniejsze.
Bram Visser
2
@Ramnath co robi $ stats [c (1,5)]?
lukeg
3
Nie działa, jeśli używasz facet_grid(). Wtedy masz wiele wykresów pudełkowych zamiast jednego. W ten sposób nie masz odpowiednich ograniczeń.
WitheShadow
210

Służy geom_boxplot(outlier.shape = NA)do niewyświetlania wartości odstających i scale_y_continuous(limits = c(lower, upper))do zmiany granic osi.

Przykład.

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

W rzeczywistości, jak pokazał Ramnath w swojej odpowiedzi (a także Andrie w komentarzach), bardziej sensowne jest przycinanie skali po obliczeniu statystyki za pomocą coord_cartesian.

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

(Prawdopodobnie nadal będziesz musiał użyć, scale_y_continuousaby naprawić pęknięcia osi).

Richie Cotton
źródło
1
Musiałbym więc obliczyć dolny / górny - być może obliczając 1/3 percentyl? Oznacza to, że nie ma automatycznej magii sposobu, aby powiedzieć gg-plot2, aby ignorował wartości odstające i inteligentnie skalował?
SFun28
39
Uważaj na scale_y_continuous (limits = ...) Spowoduje to usunięcie danych wykraczających poza limity, a następnie wykonanie obliczeń statystycznych. Innymi słowy, wpłynie to na średnią i inne podsumowania. Jeśli tego chcesz, to świetnie. Alternatywą jest użycie koordyn_kartesian (limity = ...) - to „powiększa się” bez usuwania danych lub wpływania na podsumowania.
Andrie
@Andrie - dzięki! Nie chcę, aby miało to wpływ na złośliwe i inne podsumowania.
SFun28
1
coord_cartesian()z coord_flip()mojego doświadczenia nie współgra, więc wolę scale_y_continuous().
PatrickT
1
To najlepsze rozwiązanie. Powodem, dla którego chcę ukryć wartości odstające, jest to, że wykreślam również niestabilne punkty za pomocą geom_jitter. W tym przypadku wartości odstające po prostu przeszkadzają i sprawiają, że wygląda na to, że punktów jest więcej niż powinno.
williamsurles
14

Miałem ten sam problem i wstępnie obliczyłem wartości dla Q1, Q2, mediana, ymin, ymax używając 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

W rezultacie otrzymujemy wykres pudełkowy bez wartości odstających. wprowadź opis obrazu tutaj

Matthias Munz
źródło
9

Jednym z pomysłów byłoby wygranie danych w procedurze dwuprzebiegowej:

  1. wykonaj pierwszy przebieg, dowiedz się, jakie są granice, np. obcięcie o dany percentyl lub odchylenie standardowe N powyżej średniej, lub ...

  2. w drugim przebiegu ustaw wartości poza podanym ograniczeniem na wartość tego ograniczenia

Powinienem podkreślić, że jest to staroświecka metoda, która powinna być zdominowana przez bardziej nowoczesne, solidne techniki, ale wciąż często się z nią spotykasz.

Dirk Eddelbuettel
źródło
1
Kto po cichu zagłosował przeciw : zostaw komentarz, aby wyjaśnić, dlaczego .
Dirk Eddelbuettel
To nie ja. Chciałem tylko dodać, że posiadanie wąsów, które kończą się na percentylach (zwykle 10 i 90), wydaje się być bardzo powszechne w przypadku danych środowiskowych.
Richie Cotton
Byłem cichym +1 i żałuję, że nie mam innego do zaoferowania. W przypadku econ + finance prawie zawsze wygrywa się. Jeśli SFun ma wartości odstające, które psują wizualizację danych, zastanawiam się, jaki jest ich wpływ na analizę danych.
Richard Herron
czytałeś ponownie ten post, wspomniałeś, że windsorizing to starsza technika… jakie byłyby bardziej nowoczesne techniki?
SFun28
1
Ogólnie rzecz biorąc, solidne metody jako rozwój ostatnich ponad 30 lat.
Dirk Eddelbuettel
2

Opcja „coef” funkcji geom_boxplot umożliwia zmianę wartości granicznej wartości odstającej w zakresie przedziałów międzykwartylowych. Ta opcja jest udokumentowana dla funkcji stat_boxplot. Aby dezaktywować wartości odstające (innymi słowy, są one traktowane jak zwykłe dane), można zamiast używać domyślnej wartości 1,5, określić bardzo wysoką wartość odcięcia:

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)
eckart
źródło
3
To tylko wydłuża wąsy, nie przeskalowuje w ogóle wykresu
Moody_Mudskipper
2

Jeśli chcesz zmusić wąsy, aby rozciągały się do wartości max i min, możesz zmodyfikować coefargument. Wartość domyślna coefto 1,5 (tj. Domyślna długość wąsów jest 1,5 razy większa od 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)

obraz p0

obraz p1

IggyM
źródło
2

Ipaper :: geom_boxplot2 jest właśnie tym, czego chcesz.

# 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)

wprowadź opis obrazu tutaj

Dongdong Kong
źródło
Dzięki!! Przetestowane na moich danych, działa idealnie! Poleciłbym to rozwiązanie, chociaż nie jestem pewien co do stabilności / długotrwałego wsparcia rzeczy na githubie.
Gildas