Ignora gli outlier nel boxplot ggplot2


132

Come ignorerei gli outlier nel boxplot ggplot2? Non voglio semplicemente che scompaiano (cioè outlier.size = 0), ma voglio che vengano ignorati in modo tale che l'asse y si riduca per mostrare il 1 ° / 3 ° percentile. I miei valori anomali stanno facendo restringere la "scatola" così piccola che praticamente è una linea. Ci sono alcune tecniche per affrontare questo?

Modifica Ecco un esempio:

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

inserisci qui la descrizione dell'immagine


Alcuni dati di esempio e un esempio riproducibile ti aiuteranno più facilmente.
Andrie,

3
il mio file è di 200 meg! Basta prendere qualsiasi set di dati in cui vi sono molti punti dati tra il 1o e il 3o quantile e alcuni valori anomali (ne occorre solo 1). Se il valore erratico è lontano dal 1 ° / 3 °, le caselle si restringono necessariamente per
adattarsi al valore erratico

Sì, è quello che avevo in mente. Crea un set di dati di questo tipo e usa dput () per pubblicarlo qui insieme all'istruzione ggplot () che usi. Aiutaci ad aiutarti.
Andrie,

Non puoi semplicemente modificare i limiti dell'asse y per "ingrandire" la parte dell'asse y che ti interessa?
Gavin Simpson,

2
fammi guardare .... Oh sì, scusa. Basta fare fivenum()i dati per estrarre ciò che, IIRC, viene utilizzato per le cerniere superiore e inferiore sui grafici a scatole e usare quell'output nella scale_y_continuous()chiamata mostrata da @Ritchie. Questo può essere automatizzato molto facilmente usando gli strumenti R e ggplot. Se è necessario includere anche i baffi, prendere in considerazione l'utilizzo boxplot.stats()per ottenere i limiti superiore e inferiore per i baffi e utilizzare quindi scale_y_continuous().
Gavin Simpson,

Risposte:


141

Ecco una soluzione che utilizza 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)

15
+1 per il calcolo automatico, +1 per l'utilizzo di coord_cartesian per lo zoom anziché l'esclusione dei dati
Ben Bolker,

2
@Ben - hai due account? =) @Ramnath - questa è una soluzione davvero elegante
SFun28

7
Utilizzando il metodo di cui sopra, limiti potrebbe avere spinto elasticamente da una piccola estremo su un lato e grande e estremo dall'altro, ad esempio ylim <- c(-0.1, 1000) * 1.05[1] 0.105 1050. Per ottenere limiti uguali intorno alla media che potresti usare ylim + c(-0.05, 0.05) * diff(ylim) / 2. Più carino secondo me.
Bram Visser,

2
@Ramnath cosa fanno le $ stats [c (1,5)]?
lukeg,

3
Non funziona se si utilizza facet_grid(). Quindi hai più boxplot invece di uno. Quindi non ottieni i limiti giusti.
WitheShadow

204

Utilizzare geom_boxplot(outlier.shape = NA)per non visualizzare i valori anomali e scale_y_continuous(limits = c(lower, upper))per modificare i limiti degli assi.

Un esempio.

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

In realtà, come ha mostrato Ramnath nella sua risposta (e anche Andrie nei commenti), ha più senso ritagliare le scale dopo aver calcolato la statistica, tramite coord_cartesian.

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

(Probabilmente dovrai ancora usare scale_y_continuousper correggere le interruzioni degli assi.)


1
Quindi dovrei calcolare il valore inferiore / superiore, forse calcolando il 1 ° / 3 ° percentile? Significa che non esiste un modo auto-magico per dire a gg-plot2 di ignorare i valori anomali e ridimensionare in modo intelligente?
SFun28,

38
Prestare attenzione con scale_y_continuous (limits = ...) Questo rimuoverà i dati che non rientrano nei limiti e quindi eseguirà i calcoli statistici. In altre parole, la media e altri riassunti saranno interessati. Se questo è quello che vuoi, fantastico. L'alternativa è usare coord_cartesian (limits = ...) - questo 'ingrandisce' senza rimuovere i dati o influenzare i riepiloghi.
Andrie,

@Andrie - grazie! Non voglio che la media e altri riassunti siano interessati.
SFun28,

1
coord_cartesian()non gioca bene con coord_flip(), nella mia esperienza, quindi preferisco scale_y_continuous().
Patrick

1
Questa è la soluzione migliore Il motivo per cui voglio nascondere i valori anomali è perché sto anche pianificando punti jitter con geom_jitter. In questo caso gli outlier si mettono in mezzo e fanno sembrare che ci siano più punti di quanti dovrebbero esserci.
williamsurles,

14

Ho avuto lo stesso problema e ho pre-calcolato i valori per Q1, Q2, mediana, ymin, ymax usando 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

Il risultato è un diagramma a scatole senza valori anomali. inserisci qui la descrizione dell'immagine


9

Un'idea sarebbe quella di vincolare i dati in una procedura a due passaggi:

  1. eseguire un primo passaggio, apprendere quali sono i limiti, ad es. taglio del dato percentile o N deviazione standard sopra la media o ...

  2. in un secondo passaggio, imposta i valori oltre il limite dato al valore di quel limite

Dovrei sottolineare che si tratta di un metodo vecchio stile che dovrebbe essere dominato da tecniche più moderne e robuste, ma ci si imbatte ancora molto.


1
Chi ha appena effettuato il downgrade in silenzio : lascia un commento per spiegare il perché .
Dirk Eddelbuettel,

Non sono stato io Volevo solo aggiungere che avere baffi che si fermano ai percentili (di solito 10 ° e 90 °) sembra essere molto comune con i dati ambientali.
Richie Cotton,

Ero un +1 silenzioso e vorrei averne un altro da offrire. Il winsorizing è quasi sempre fatto in econ + finance. Se SFun ha degli outlier che rovinano la visualizzazione dei dati, mi chiedo quale sia il loro effetto sull'analisi dei dati.
Richard Herron,

rileggendo questo post, hai detto che il windsurf è una tecnica più antica ... quali sarebbero alcune tecniche più moderne?
SFun28,

1
In generale, metodi robusti come sviluppo degli ultimi 30+ anni.
Dirk Eddelbuettel,

2

L'opzione "coef" della funzione geom_boxplot consente di modificare il valore soglia anomalo in termini di intervalli interquartili. Questa opzione è documentata per la funzione stat_boxplot. Per disattivare i valori anomali (in altre parole vengono trattati come dati regolari), invece di utilizzare il valore predefinito di 1,5 è possibile specificare un valore di cutoff molto elevato:

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
Estende solo i baffi, non ridimensiona il grafico di sorta
Moody_Mudskipper,

2

Se vuoi forzare i baffi a estendersi ai valori massimo e minimo, puoi modificare l' coefargomento. Il valore predefinito per coefè 1,5 (ovvero la lunghezza predefinita dei baffi è 1,5 volte l'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)

immagine di p0

immagine di p1


2

Ipaper :: geom_boxplot2 è proprio quello che vuoi.

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

inserisci qui la descrizione dell'immagine


Grazie!! Testato con i miei dati, funziona perfettamente! Consiglierei questa soluzione, anche se non sono sicuro del supporto di stabilità / lungo tempo delle cose github.
Gildas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.