Buoni metodi per i grafici di densità delle variabili non negative in R?


36
plot(density(rexp(100))

Ovviamente tutta la densità a sinistra di zero rappresenta una distorsione.

Sto cercando di riassumere alcuni dati per i non statistici e voglio evitare domande sul perché i dati non negativi hanno densità a sinistra di zero. I grafici sono per il controllo di randomizzazione; Voglio mostrare le distribuzioni delle variabili per gruppi di trattamento e controllo. Le distribuzioni sono spesso esponenziali. Gli istogrammi sono complicati per vari motivi.

Una rapida ricerca su Google mi dà lavoro da parte di statistici su kernel non negativi, ad esempio: questo .

Ma ne è stato implementato qualcuno in R? Dei metodi implementati, alcuni di essi sono "migliori" in qualche modo per le statistiche descrittive?

EDIT: anche se il fromcomando può risolvere il mio problema attuale, sarebbe bello sapere se qualcuno ha implementato kernel basati sulla letteratura sulla stima della densità non negativa


3
Non è quello che stai chiedendo, ma non applicherei la stima della densità del kernel a qualcosa che dovrebbe essere esponenziale, specialmente per la presentazione a un pubblico non statistico. Vorrei usare una trama quantile-quantile e spiegare che la trama dovrebbe essere diritta se la distribuzione fosse esponenziale.
Nick Cox,

6
plot(density(rexp(100), from=0))?
Stéphane Laurent,

4
Una cosa che a volte ho fatto abbastanza bene è ottenere un kde sui registri e quindi trasformare la stima della densità (senza dimenticare il giacobino). Un'altra possibilità sarebbe quella di utilizzare una stima della densità della spline di log impostata in modo che sia a conoscenza del limite.
Glen_b


1
Ho discusso del metodo di trasformazione menzionato da @Glen_b in stata-journal.com/sjpdf.html?articlenum=gr0003 (vedi pp.76-78). Gli zeri potrebbero essere sistemati usando log (x + 1) anziché log e modificando il giacobino.
Nick Cox,

Risposte:


21

Una soluzione, presa in prestito dagli approcci alla ponderazione dei bordi delle statistiche spaziali, è di troncare la densità a sinistra a zero, ma di aumentare la ponderazione dei dati più vicini allo zero. L'idea è che ogni valore sia "diffuso" in un kernel dell'area totale dell'unità centrato su xxx ; qualsiasi parte del kernel che si riverserebbe in territorio negativo viene rimossa e il kernel viene rinormalizzato nell'area dell'unità.

Ad esempio, con un kernel gaussiano , il peso di rinormalizzazione èKh(y,x)=exp(12((yx)/h)2)/2π

w(X)=1/0K(y,X)dy=11-ΦX,h(0)

dove è la funzione di distribuzione cumulativa di una variabile normale di x media e deviazione standard h . Formule comparabili sono disponibili per altri kernel.ΦXh

Questo è più semplice - e molto più veloce nel calcolo - rispetto al tentativo di restringere le larghezze di banda vicino a . È comunque difficile stabilire esattamente come modificare la larghezza di banda vicino a 0 . Tuttavia, questo metodo è anche ad hoc : ci sarà ancora una certa propensione vicino a 0 . Sembra funzionare meglio della stima della densità predefinita. Ecco un confronto usando un set di dati di grandi dimensioni:000

figura

Il blu mostra la densità predefinita mentre il rosso mostra la densità regolata per il bordo a 0 . La vera distribuzione sottostante viene tracciata come una linea tratteggiata per riferimento.


Codice R.

La densityfunzione in Rlamenterà che la somma dei pesi non è unità, perché vuole che l'integrale su tutti i numeri reali sia unità, mentre questo approccio rende l'integrale rispetto ai numeri positivi uguale all'unità. Come controllo, quest'ultimo integrale è stimato come somma di Riemann.

set.seed(17)
x <- rexp(1000)
#
# Compute a bandwidth.
#
h <- density(x, kernel="gaussian")$bw # $
#
# Compute edge weights.
#
w <- 1 / pnorm(0, mean=x, sd=h, lower.tail=FALSE)
#
# The truncated weighted density is what we want.
#
d <- density(x, bw=h, kernel="gaussian", weights=w / length(x))
d$y[d$x < 0] <- 0
#
# Check: the integral ought to be close to 1:
#
sum(d$y * diff(d$x)[1])
#
# Plot the two density estimates.
#
par(mfrow=c(1,1))
plot(d, type="n", main="Default and truncated densities", xlim=c(-1, 5))
polygon(density(x, kernel="gaussian", bw=h), col="#6060ff80", border=NA)
polygon(d, col="#ff606080", border=NA)
curve(exp(-x), from=0, to=max(x), lty=2, add=TRUE)

21

Un'alternativa è l'approccio di Kooperberg e colleghi, basato sulla stima della densità utilizzando spline per approssimare la densità di registro dei dati. Mostrerò un esempio usando i dati della risposta di @ whuber, che consentirà un confronto di approcci.

set.seed(17)
x <- rexp(1000)

Per questo avrai bisogno del pacchetto logspline ; installalo se non lo è:

install.packages("logspline")

Caricare il pacchetto e stimare la densità utilizzando la logspline()funzione:

require("logspline")
m <- logspline(x)

Di seguito, suppongo che l'oggetto ddalla risposta di @ whuber sia presente nell'area di lavoro.

plot(d, type="n", main="Default, truncated, and logspline densities", 
     xlim=c(-1, 5), ylim = c(0, 1))
polygon(density(x, kernel="gaussian", bw=h), col="#6060ff80", border=NA)
polygon(d, col="#ff606080", border=NA)
plot(m, add = TRUE, col = "red", lwd = 3, xlim = c(-0.001, max(x)))
curve(exp(-x), from=0, to=max(x), lty=2, add=TRUE)
rug(x, side = 3)

Il diagramma risultante è mostrato sotto, con la densità della logspline mostrata dalla linea rossa

Densità predefinita, troncata e logspline

Inoltre, il supporto per la densità può essere specificato tramite argomenti lbounde ubound. Se desideriamo supporre che la densità sia 0 a sinistra di 0 e che vi sia una discontinuità a 0, potremmo usare lbound = 0nella chiamata a logspline(), ad esempio

m2 <- logspline(x, lbound = 0)

Rendere la seguente stima della densità (mostrata qui con il mlogspline originale in quanto la figura precedente era già occupata).

plot.new()
plot.window(xlim = c(-1, max(x)), ylim = c(0, 1.2))
title(main = "Logspline densities with & without a lower bound",
      ylab = "Density", xlab = "x")
plot(m,  col = "red",  xlim = c(0, max(x)), lwd = 3, add = TRUE)
plot(m2, col = "blue", xlim = c(0, max(x)), lwd = 2, add = TRUE)
curve(exp(-x), from=0, to=max(x), lty=2, add=TRUE)
rug(x, side = 3)
axis(1)
axis(2)
box()

Il diagramma risultante è mostrato di seguito

Confronto delle stime di densità logspline con e senza limite inferiore sul supporto

xX=0x


1
01

@whuber Buona domanda. Mi sono imbattuto in questo approccio solo di recente. Ho il sospetto che una buona domanda da porsi qui sia, poiché i metodi troncato e logspline sono solo stime della densità reale, le differenze di adattamento sono significative, statisticamente? Tuttavia, non sono sicuro del perché esiti così bene a zero. Gradirei sapere anche perché.
Ripristina Monica - G. Simpson,

@GavinSimpson, grazie per questa bella risposta. Riesci a riprodurre l'ultima trama con l'ultima versione di logspline? Per me, la densità di entrambe, la versione limitata e la versione illimitata vanno a zero a x = 0.
cel

4

Per confrontare le distribuzioni per gruppi (che dici sia l'obiettivo in uno dei tuoi commenti) perché non qualcosa di più semplice? I grafici a scatole parallele funzionano bene se N è grande; i grafici a strisce parallele funzionano se N è piccolo (ed entrambi mostrano bene i valori anomali, che si ritiene essere un problema nei dati).


1
Sì, grazie, funziona. Ma mi piacciono i diagrammi di densità. Mostrano di più sui dati di quanto facciano i boxplot. Immagino di essere sorpreso dal fatto che nulla sia già stato implementato. Forse un giorno implementerò una di queste cose. Le persone probabilmente lo troverebbero utile.
generic_user

1
Mi piacciono anche i grafici della densità; ma devi considerare il tuo pubblico.
Peter Flom - Ripristina Monica

1
Devo essere d'accordo con @PeterFlom su questo. Non complicarti troppo se il tuo pubblico non è statisticamente informato. Potresti anche fare grafici comparativi / paralleli con una sovrapposizione di grafici a farfalla in cima. In questo modo è visibile sia il riepilogo della trama che tutti i dati.
doug.numbers,

Il suggerimento secondo cui persone diverse comprendono le trame aggregate in modo diverso è certamente corretto. Nonostante comprenda cosa sia un diagramma di densità (e comprendendo che non è una probabilità) non ho idea di quale potrebbe essere un "diagramma a scatole parallele". Suggerisce un diagramma di coordinate parallele ma sospetto che non sia corretto.
DWin

2

Come commenta Stéphane, puoi usare from = 0e, inoltre, puoi rappresentare i tuoi valori sotto la curva di densità conrug (x)


4
Correggimi se sbaglio, ma from=0sembra che elimini solo la stampa di valori inferiori a 0; non corregge il calcolo per il fatto che parte della distribuzione è stata macchiata al di sotto di 0.
Nick Cox,

1
È corretto. L'uso del fromcomando produce un diagramma che sembra avere il picco giusto a zero. Ma se guardi gli istogrammi con bin sempre più piccoli, molti dati mostreranno il picco AT zero. Il fromè solo un trucco grafico.
generic_user

@NickCox Non ne sono sicuro ma non credo che reprimi from=0nulla. Inizia solo la "griglia" da zero.
Stéphane Laurent,

La differenza è se la densità stimata è diversa da zero per valori negativi, non se è tracciata o meno. I ricercatori possono decidere di non preoccuparsi di questo se tutto ciò che vogliono è una visualizzazione.
Nick Cox,

@NickCox Il comando density(rexp(100), from=0)non ha nulla a che fare con la grafica
Stéphane Laurent
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.