Jak nałożyć wykresy gęstości w R?

82

Chciałbym nałożyć 2 wykresy gęstości na tym samym urządzeniu za pomocą R. Jak mogę to zrobić? Przeszukałem sieć, ale nie znalazłem żadnego oczywistego rozwiązania.

Moim pomysłem byłoby odczytanie danych z pliku tekstowego (kolumn), a następnie użycie

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

Albo coś w tym duchu.

makaron
źródło
Dla ggplot2rodziny jest teraz pakiet, ggridgesktóry może to zrobić.
Liang Zhang

Odpowiedzi:

96

użyj linesdo drugiego:

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

upewnij się jednak, że granice pierwszego wątku są odpowiednie.

cbeleites niezadowolony z SX
źródło
9
+1 Możesz potrzebować czegoś nieco bardziej złożonego, gdy dwie gęstości mają różne zakresy, a druga krzywa nie mieści się w granicach wykresu. Następnie można obliczyć gęstości przed wykreśleniem i obliczyć odpowiednie ylimprzy użyciu obiektów range(dens1$y, dens2$y)gdzie dens1i dens2są zawierające dwa obiekty szacowania gęstości. Użyj tego ylimw wezwaniu do plot().
Gavin Simpson
2
Prawdopodobnie będziesz chciał rozróżnić te dwie linie. Powinno tu pomóc ustawienie szerokości linii ( lwd), typu linii ( lty) lub koloru linii ( col). W tym momencie możesz również rozważyć dodanie legendy, używająclegend()
nullglob
@Gavin Jeśli OP czyta z pliku, skonstruowałbym rozbudowaną funkcję, która wczytywałaby dane (sapply, lapply), znajdowała zakresy wszystkich zestawów danych, ustawiała domyślny zakres na maksymalny zakres wszystkich, a następnie rysował (linie ) gęstości.
Roman Luštrik
50

ggplot2 to kolejny pakiet graficzny, który w całkiem sprytny sposób radzi sobie z takimi problemami, jak problem z zasięgiem, o którym wspomina Gavin. Obsługuje również automatyczne generowanie odpowiednich legend i po prostu ogólnie ma bardziej dopracowany wygląd po wyjęciu z pudełka z mniejszą ręczną manipulacją.

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)

wprowadź opis obrazu tutaj

Pościg
źródło
8
Ramka danych OP musi być najpierw stopiona do długiej postaci:ggplot (melt (MyData), mapping = aes (fill = variable, x = value)) + geom_density (alpha = .5)
cbeleites niezadowolone z SX
1
Niezła fabuła. Co to jest "dat2" ...? co to jest „topienie” (nie znaleziono polecenia)?
Erik Aronesty,
@ErikAronesty - myślisz, że jest tak samo dobre jak moje w tym momencie, odpowiedziałem na to dwa lata temu! Spekuluję, że miałem inny obiekt nazwany datw moim środowisku tak go nazwał dat2... symulowane dane, które udostępniam, działają jednak zgodnie z reklamą. melt()polecenie pochodzi z pakietu reshape2. W 2011 r. reshape2Został automatycznie załadowany po ggplot2załadowaniu, ale tak już nie jest, więc musisz to zrobić library(reshape2)osobno.
Chase
23

Dodanie podstawowej wersji grafiki, która dba o limity osi y, dodaje kolory i działa dla dowolnej liczby kolumn:

Jeśli mamy zestaw danych:

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

Następnie, aby wykreślić gęstości:

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

Co daje:

wprowadź opis obrazu tutaj

Karolis Koncevičius
źródło
Podoba mi się ten przykład, ale jeśli masz kolumny danych zawierające wartości NA, to nie działa. Nie jestem pewien, jak zmodyfikować kod, ale byłoby to przydatne
daisy
1
@daisy zmień tę linię dens <- apply(myData, 2, density)na dens <- apply(myData, 2, density, na.rm=TRUE)i powinna działać.
Karolis Koncevičius
12

Aby zapewnić kompletny zestaw, oto wersja odpowiedzi Chase'a przy użyciu 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"))

który tworzy taki wykres: wprowadź opis obrazu tutaj

joran
źródło
Bez tworzenia nowych data.frame: densityplot(~rnorm(100)+rnorm(100, 10, 5), plot.points=FALSE, ref=TRUE, auto.key = list(space = "right")). Lub dla danych OP densityplot(~Column1+Column2, data=myData).
Marek
6

Tak to robię w bazie (tak naprawdę jest to wspomniane w komentarzach pierwszej odpowiedzi, ale pokażę tutaj pełny kod, w tym legendę, ponieważ nie mogę jeszcze komentować ...)

Najpierw musisz uzyskać informacje o maksymalnych wartościach dla osi y z wykresów gęstości. Więc musisz najpierw obliczyć gęstości oddzielnie

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

Następnie wykreśl je zgodnie z pierwszą odpowiedzią i zdefiniuj wartości minimalne i maksymalne dla osi y, którą właśnie otrzymałeś. (Ustawiam wartość min na 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")

Następnie dodaj legendę w prawym górnym rogu

legend("topright", c("VarA","VarB"), lty = c(1,1), col = c("blue","red"))
R. Prost
źródło
3

Wziąłem powyższy przykład kraty i wykonałem fajną funkcję. Prawdopodobnie istnieje lepszy sposób, aby to zrobić, zmieniając kształt za pomocą topienia / odlewania. (Skomentuj lub edytuj, jeśli zauważysz poprawę).

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,...)
}

Przykładowe użycie:

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
źródło
2

Możesz skorzystać z ggjoypakietu. Powiedzmy, że mamy trzy różne betadystrybucje, takie jak:

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)

Możesz uzyskać trzy różne dystrybucje w następujący sposób:

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

wprowadź opis obrazu tutaj

George Pipis
źródło
2

Zawsze, gdy występują problemy z niedopasowanymi granicami osi, basenależy użyć odpowiedniego narzędzia graficznego matplot. Kluczem jest wykorzystanie argumentów fromi . To trochę hakerskie, ale dość proste, aby się rzucić:todensity.default

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

Fabuła przedstawiająca wynik wywołania matplot.  Obserwowane są dwie krzywe, jedna czerwona, druga czarna;  czarna krzywa rozciąga się wyżej niż czerwona, podczas gdy czerwona krzywa jest „grubsza”.

Dodaj wodotryski jako pożądane ( matplotakceptuje wszystkie standardowe plot/ parargumenty, na przykład lty, type, col, lwd, ...).

MichaelChirico
źródło