¿Cómo superponer gráficos de densidad en R?

81

Me gustaría superponer 2 diagramas de densidad en el mismo dispositivo con R. ¿Cómo puedo hacer eso? Busqué en la web pero no encontré ninguna solución obvia.

Mi idea sería leer datos de un archivo de texto (columnas) y luego usar

plot(density(MyData$Column1))
plot(density(MyData$Column2), add=T)

O algo con este espíritu.

pasta
fuente

Respuestas:

92

utilizar linespara el segundo:

plot(density(MyData$Column1))
lines(density(MyData$Column2))

Sin embargo, asegúrese de que los límites de la primera parcela sean adecuados.

cbeleites descontentos con SX
fuente
9
+1 Es posible que necesite algo un poco más complejo cuando las dos densidades tienen rangos diferentes y la segunda curva no se ajusta a los límites del gráfico. Luego, puede calcular las densidades antes de graficar y calcular un valor apropiado ylimutilizando range(dens1$y, dens2$y)dónde dens1y dens2son los objetos que contienen los dos objetos de estimación de densidad. Use esto ylimen la llamada a plot().
Gavin Simpson
2
Probablemente también desee distinguir entre las dos líneas. Establecer el ancho de línea ( lwd), el tipo de línea ( lty) o el color de línea ( col) debería ayudar aquí. En ese punto, también podría considerar agregar una leyenda, usandolegend()
nullglob
@Gavin Si el OP está leyendo de un archivo, construiría una función elaborada que leería datos (sapply, lapply), encontraría rangos de todos los conjuntos de datos, establecería el rango predeterminado en el rango máximo de todos y luego trazaría (líneas ) las densidades.
Roman Luštrik
50

ggplot2 es otro paquete de gráficos que maneja cosas como el problema de rango que menciona Gavin de una manera bastante hábil. También maneja la generación automática de leyendas apropiadas y, en mi opinión, generalmente tiene una sensación más pulida fuera de la caja con menos manipulación manual.

library(ggplot2)

#Sample data
dat <- data.frame(dens = c(rnorm(100), rnorm(100, 10, 5))
                   , lines = rep(c("a", "b"), each = 100))
#Plot.
ggplot(dat, aes(x = dens, fill = lines)) + geom_density(alpha = 0.5)

ingrese la descripción de la imagen aquí

Persecución
fuente
8
El data.frame del OP debe fundirse en una forma larga primero:ggplot (melt (MyData), mapping = aes (fill = variable, x = value)) + geom_density (alpha = .5)
cbeleites descontentos con SX
1
Bonita parcela. ¿Qué es "dat2" ...? ¿Qué es "derretir" (comando no encontrado)?
Erik Aronesty
@ErikAronesty: supongo que es tan bueno como el mío en este momento, ¡respondí esto hace dos años! Especulo que tenía otro objeto nombrado daten mi entorno, así que lo nombré dat2... aunque los datos simulados que proporciono funcionan como se anuncia. el melt()comando proviene del paquete reshape2. En 2011, reshape2se cargó automáticamente cuando ggplot2se cargó, pero ese ya no es el caso, por lo que debe hacerlo por library(reshape2)separado.
Chase
21

Agregar una versión de gráficos base que se ocupa de los límites del eje y, agrega colores y funciona para cualquier cantidad de columnas:

Si tenemos un conjunto de datos:

myData <- data.frame(std.nromal=rnorm(1000, m=0, sd=1),
                     wide.normal=rnorm(1000, m=0, sd=2),
                     exponent=rexp(1000, rate=1),
                     uniform=runif(1000, min=-3, max=3)
                     )

Luego para trazar las densidades:

dens <- apply(myData, 2, density)

plot(NA, xlim=range(sapply(dens, "[", "x")), ylim=range(sapply(dens, "[", "y")))
mapply(lines, dens, col=1:length(dens))

legend("topright", legend=names(dens), fill=1:length(dens))

Lo que da:

ingrese la descripción de la imagen aquí

Karolis Koncevičius
fuente
Me gusta este ejemplo, pero si tiene columnas de datos que incluyen valores NA, no funciona. No estoy seguro de cómo modificar el código, pero esto sería útil
Daisy
1
@daisy cambia esta línea dens <- apply(myData, 2, density)a dens <- apply(myData, 2, density, na.rm=TRUE)y debería funcionar.
Karolis Koncevičius
12

Solo para proporcionar un conjunto completo, aquí hay una versión de la respuesta de Chase usando lattice:

dat <- data.frame(dens = c(rnorm(100), rnorm(100, 10, 5))
                   , lines = rep(c("a", "b"), each = 100))

densityplot(~dens,data=dat,groups = lines,
            plot.points = FALSE, ref = TRUE, 
            auto.key = list(space = "right"))

que produce una trama como esta: ingrese la descripción de la imagen aquí

joran
fuente
Sin crear nueva data.frame: densityplot(~rnorm(100)+rnorm(100, 10, 5), plot.points=FALSE, ref=TRUE, auto.key = list(space = "right")). O para datos OP densityplot(~Column1+Column2, data=myData).
Marek
6

Así es como lo hago en la base (en realidad se menciona en los comentarios de la primera respuesta, pero mostraré el código completo aquí, incluida la leyenda, ya que aún no puedo comentar ...)

Primero necesita obtener la información sobre los valores máximos para el eje y de las gráficas de densidad. Por lo tanto, primero debe calcular las densidades por separado

dta_A <- density(VarA, na.rm = TRUE)
dta_B <- density(VarB, na.rm = TRUE)

Luego, grábelos de acuerdo con la primera respuesta y defina los valores mínimo y máximo para el eje y que acaba de obtener. (Puse el valor mínimo en 0)

plot(dta_A, col = "blue", main = "2 densities on one plot"), 
     ylim = c(0, max(dta_A$y,dta_B$y)))  
lines(dta_B, col = "red")

Luego agregue una leyenda en la esquina superior derecha

legend("topright", c("VarA","VarB"), lty = c(1,1), col = c("blue","red"))
R. Prost
fuente
3

Tomé el ejemplo de celosía anterior e hice una función ingeniosa. Probablemente haya una mejor manera de hacer esto con remodelar a través de fusión / fundición. (Comente o edite si ve una mejora).

multi.density.plot=function(data,main=paste(names(data),collapse = ' vs '),...){
  ##combines multiple density plots together when given a list
  df=data.frame();
  for(n in names(data)){
    idf=data.frame(x=data[[n]],label=rep(n,length(data[[n]])))
    df=rbind(df,idf)
  }
  densityplot(~x,data=df,groups = label,plot.points = F, ref = T, auto.key = list(space = "right"),main=main,...)
}

Uso de ejemplo:

multi.density.plot(list(BN1=bn1$V1,BN2=bn2$V1),main='BN1 vs BN2')

multi.density.plot(list(BN1=bn1$V1,BN2=bn2$V1))
Chris
fuente
2

Puede utilizar el ggjoypaquete. Digamos que tenemos tres betadistribuciones diferentes como:

set.seed(5)
b1<-data.frame(Variant= "Variant 1", Values = rbeta(1000, 101, 1001))
b2<-data.frame(Variant= "Variant 2", Values = rbeta(1000, 111, 1011))
b3<-data.frame(Variant= "Variant 3", Values = rbeta(1000, 11, 101))


df<-rbind(b1,b2,b3)

Puede obtener las tres distribuciones diferentes de la siguiente manera:

library(tidyverse)
library(ggjoy)


ggplot(df, aes(x=Values, y=Variant))+
    geom_joy(scale = 2, alpha=0.5) +
    scale_y_discrete(expand=c(0.01, 0)) +
    scale_x_continuous(expand=c(0.01, 0)) +
    theme_joy()

ingrese la descripción de la imagen aquí

George Pipis
fuente
2

Siempre que haya problemas de límites de eje no coincidentes, basese debe utilizar la herramienta correcta en gráficos matplot. La clave es aprovechar los argumentos fromy topara density.default. Es un poco hack, pero bastante sencillo de rodar usted mismo:

set.seed(102349)
x1 = rnorm(1000, mean = 5, sd = 3)
x2 = rnorm(5000, mean = 2, sd = 8)

xrng = range(x1, x2)

#force the x values at which density is
#  evaluated to be the same between 'density'
#  calls by specifying 'from' and 'to'
#  (and possibly 'n', if you'd like)
kde1 = density(x1, from = xrng[1L], to = xrng[2L])
kde2 = density(x2, from = xrng[1L], to = xrng[2L])

matplot(kde1$x, cbind(kde1$y, kde2$y))

Un diagrama que representa el resultado de la llamada a matplot.  Se observan dos curvas, una roja y otra negra;  la curva negra se extiende más arriba que la roja, mientras que la curva roja es la "más gruesa".

Añadir campanas y silbatos como desee ( matplotacepta todos los estándar plot/ parargumentos, por ejemplo lty, type, col, lwd, ...).

MichaelChirico
fuente