2009-09-04 7 views
19

Ich versuche, Gittertyp Daten mit GGPLOT2 zu plotten und dann eine Normalverteilung über die Stichprobe Daten zu überlagern, um zu veranschaulichen, wie weit entfernt von normalen die zugrunde liegenden Daten ist. Ich möchte die normale dist an der Spitze haben, um das gleiche Mittel und stdev wie das Gremium zu haben.mit stat_function und facet_wrap zusammen in GGPLOT2 in R

hier ein Beispiel:

library(ggplot2) 

#make some example data 
dd<-data.frame(matrix(rnorm(144, mean=2, sd=2),72,2),c(rep("A",24),rep("B",24),rep("C",24))) 
colnames(dd) <- c("x_value", "Predicted_value", "State_CD") 

#This works 
pg <- ggplot(dd) + geom_density(aes(x=Predicted_value)) + facet_wrap(~State_CD) 
print(pg) 

Das alles funktioniert gut und erzeugt eine schöne drei Panel grafische Darstellung der Daten. Wie füge ich das normale dist hinzu? Es scheint, ich würde stat_function verwenden, aber dies nicht gelingt:

#this fails 
pg <- ggplot(dd) + geom_density(aes(x=Predicted_value)) + stat_function(fun=dnorm) + facet_wrap(~State_CD) 
print(pg) 

Es scheint, dass die stat_function nicht mit der facet_wrap Funktion zusammen bekommt. Wie bekomme ich diese beiden gut zu spielen?

------------ EDIT ---------

Ich habe versucht, Ideen aus zwei der Antworten zu integrieren unten, und ich bin immer noch nicht da:

eine Kombination aus beiden Antworten mit diesem ich hacken zusammen:

library(ggplot) 
library(plyr) 

#make some example data 
dd<-data.frame(matrix(rnorm(108, mean=2, sd=2),36,2),c(rep("A",24),rep("B",24),rep("C",24))) 
colnames(dd) <- c("x_value", "Predicted_value", "State_CD") 

DevMeanSt <- ddply(dd, c("State_CD"), function(df)mean(df$Predicted_value)) 
colnames(DevMeanSt) <- c("State_CD", "mean") 
DevSdSt <- ddply(dd, c("State_CD"), function(df)sd(df$Predicted_value)) 
colnames(DevSdSt) <- c("State_CD", "sd") 
DevStatsSt <- merge(DevMeanSt, DevSdSt) 

pg <- ggplot(dd, aes(x=Predicted_value)) 
pg <- pg + geom_density() 
pg <- pg + stat_function(fun=dnorm, colour='red', args=list(mean=DevStatsSt$mean, sd=DevStatsSt$sd)) 
pg <- pg + facet_wrap(~State_CD) 
print(pg) 

die ... außer etwas wirklich nahe ist, ist falsch mit dem normalen dist Plotten:

enter image description here

was mache ich hier falsch?

+6

In Zukunft könnten Sie bitte mit Variablennamen verwenden entweder gemischte Fall _or_, aber nicht beides unterstreicht. Es bringt mich um! – hadley

+0

ok ok, das ist ein guter Punkt. :) –

+0

Ich habe meine "Antwort" in den Fragebereich verschoben. Ich hätte es vorwegnehmen sollen. Ich entschuldige mich bei denen, die Kommentare abgegeben haben, da sie nicht übertragen wurden. Ich werde mehr darüber nachdenken, wie ich das in der Zukunft mache. –

Antwort

34

stat_function ist entworfen, um die gleiche Funktion in jedem Panel zu überlagern. (Es gibt keine offensichtliche Möglichkeit, die Parameter der Funktion den verschiedenen Panels anzupassen).

Als Ian schon sagt, ist der beste Weg, um die normalen Kurven selbst zu erzeugen und zeichnen sie als separaten Datensatz (das ist, wo Sie falsch, bevor sie wurden - Verschmelzung macht einfach keinen Sinn für dieses Beispiel machen, und wenn du schaust genau hin, du wirst sehen, deshalb bekommst du das seltsame Sägezahnmuster.

Hier ist, wie ich über die Lösung des Problems gehen würde:

dd <- data.frame(
    predicted = rnorm(72, mean = 2, sd = 2), 
    state = rep(c("A", "B", "C"), each = 24) 
) 

grid <- with(dd, seq(min(predicted), max(predicted), length = 100)) 
normaldens <- ddply(dd, "state", function(df) { 
    data.frame( 
    predicted = grid, 
    density = dnorm(grid, mean(df$predicted), sd(df$predicted)) 
) 
}) 

ggplot(dd, aes(predicted)) + 
    geom_density() + 
    geom_line(aes(y = density), data = normaldens, colour = "red") + 
    facet_wrap(~ state) 

enter image description here

+0

Das macht total Sinn, nachdem du es erklärst. Es war für mich nicht intuitiv, dass stat_function für einzelne Kurven entworfen wurde. Ich habe einfach angenommen, dass ich es falsch mache. Danke, dass du dir die Zeit genommen hast, ein Beispiel zu geben, es ist fantastisch hilfreich. –

+0

Kann 'stat_function' immer noch keine andere Kurve für jedes Panel bereitstellen? Es scheint so, als würde man einfach eine benannte Liste von Funktionen übergeben und diese Namen mit der kategorialen Variable facet_wrap abgleichen oder die Funktion als Argument in der ursprünglichen Datentabelle bereitstellen. – cboettig

+0

@cboettig nein und es ist unwahrscheinlich, dass es jemals wird. Eine benannte Liste funktioniert nicht für mehrere Facettierungsvariablen. – hadley

3

Ich denke, dass Sie mehr Informationen bereitstellen müssen. Dies scheint zu funktionieren:

pg <- ggplot(dd, aes(Predicted_value)) ## need aesthetics in the ggplot 
pg <- pg + geom_density() 
## gotta provide the arguments of the dnorm 
pg <- pg + stat_function(fun=dnorm, colour='red',    
      args=list(mean=mean(dd$Predicted_value), sd=sd(dd$Predicted_value))) 
## wrap it! 
pg <- pg + facet_wrap(~State_CD) 
pg 

Wir sind für jede Platte den gleichen Mittelwert und SD-Parameter bereitstellt. Panel spezifischen Mittel und Standardabweichungen zu erhalten ist als Übung für den Leser *;)

‚*‘ Mit anderen Worten, nicht sicher, wie es getan werden kann ...

+1

Panel spezifische Mittel und Standardabweichungen können durch die Verwendung von Bibliothek (plyr) und ddply (dd,. (State_CD), summieren, ...) – Nova

+1

Guter Aufwand, aber ... OP oben angegeben "" Ich würde ich habe das normale dist an der Spitze, um das gleiche Mittel und stdev wie das Panel zu haben. "" – PatrickT

1

Ich denke, Ihre beste Wette ist, um Zeichnen Sie die Linie manuell mit geom_line.

dd<-data.frame(matrix(rnorm(144, mean=2, sd=2),72,2),c(rep("A",24),rep("B",24),rep("C",24))) 
colnames(dd) <- c("x_value", "Predicted_value", "State_CD") 
dd$Predicted_value<-dd$Predicted_value*as.numeric(dd$State_CD) #make different by state 

##Calculate means and standard deviations by level 
means<-as.numeric(by(dd[,2],dd$State_CD,mean)) 
sds<-as.numeric(by(dd[,2],dd$State_CD,sd)) 

##Create evenly spaced evaluation points +/- 3 standard deviations away from the mean 
dd$vals<-0 
for(i in 1:length(levels(dd$State_CD))){ 
    dd$vals[dd$State_CD==levels(dd$State_CD)[i]]<-seq(from=means[i]-3*sds[i], 
          to=means[i]+3*sds[i], 
          length.out=sum(dd$State_CD==levels(dd$State_CD)[i])) 
} 
##Create normal density points 
dd$norm<-with(dd,dnorm(vals,means[as.numeric(State_CD)], 
         sds[as.numeric(State_CD)])) 


pg <- ggplot(dd, aes(Predicted_value)) 
pg <- pg + geom_density() 
pg <- pg + geom_line(aes(x=vals,y=norm),colour="red") #Add in normal distribution 
pg <- pg + facet_wrap(~State_CD,scales="free") 
pg 
1

Wenn Sie die Normalverteilung Line-Graph "von Hand" zu erzeugen, nicht wollen, noch stat_function verwenden, und zeigen Sie Diagramme nebeneinander - dann könnten Sie die "Multiplot" -Funktion, die auf "Cookbook for R" veröffentlicht wurde, als Alternative zu facet_wrap verwenden. Sie können den Multiplot-Code in Ihr Projekt from here kopieren.

Nachdem Sie den Code kopieren, gehen Sie wie folgt vor:

# Some fake data (copied from hadley's answer) 
dd <- data.frame(
    predicted = rnorm(72, mean = 2, sd = 2), 
    state = rep(c("A", "B", "C"), each = 24) 
) 

# Split the data by state, apply a function on each member that converts it into a 
# plot object, and return the result as a vector. 
plots <- lapply(split(dd,dd$state),FUN=function(state_slice){ 
    # The code here is the plot code generation. You can do anything you would 
    # normally do for a single plot, such as calling stat_function, and you do this 
    # one slice at a time. 
    ggplot(state_slice, aes(predicted)) + 
    geom_density() + 
    stat_function(fun=dnorm, 
        args=list(mean=mean(state_slice$predicted), 
          sd=sd(state_slice$predicted)), 
        color="red") 
}) 

# Finally, present the plots on 3 columns. 
multiplot(plotlist = plots, cols=3) 

enter image description here