usar a função de estado e a faceta enrolar em ggplot2 em R
estou a tentar desenhar dados do tipo Retículo com ggplot2 e depois sobrepor uma distribuição normal sobre os dados da amostra para ilustrar quão longe do normal estão os dados subjacentes. Eu gostaria de ter o dist normal em cima para ter a mesma média e stdev como o painel.
Aqui está um exemplo: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)
que tudo funciona bem e produz um bom gráfico de três painéis dos dados. Como eu adiciono o dest normal em cima? Parece que eu usaria o stat_function, mas isto falha:
#this fails
pg <- ggplot(dd) + geom_density(aes(x=Predicted_value)) + stat_function(fun=dnorm) + facet_wrap(~State_CD)
print(pg)
parece que a função estat_ não se está a dar bem com a funcionalidade facet_wrap. Como faço com que estes dois joguem bem?
------------EDITAR---------
eu tentei integrar ideias de duas das respostas abaixo e ainda não estou lá:
Usando uma combinação de ambas as respostas, posso hackear isto.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)
O que é muito perto... mas há algo de errado com o comportamento normal. plotting:
O que estou a fazer de errado aqui?
4 answers
stat_function
é projetado para sobrepor a mesma função em cada painel. (Não há nenhuma maneira óbvia de igualar os parâmetros da função com os diferentes painéis).
Como Ian sugere, a melhor maneira é gerar as curvas normais por si mesmo, e desenhá - las como um conjunto de dados separado (é aqui que você estava a ir mal antes-a junção não faz sentido para este exemplo e se você olhar com atenção, verá que é por isso que está a obter o estranho padrão sawtooth).
Eis como eu resolveria o problema: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)
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
Estamos a fornecer o mesmo parâmetro média e sd para cada painel. Obter meios específicos do painel e desvios-padrão é deixado como um exercício para o leitor*;)
'* ' em outras palavras, não sei como pode ser feito...
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
Se não quiser gerar o grafo normal da linha de distribuição "à mão", ainda use a função stat_function e mostre os grafos lado a lado -- então poderá considerar usar a função" multiplot "publicada no" Cookbook for R " como uma alternativa ao facet_wrap. Pode copiar o código multiplot para o seu projecto a partir daqui .
Depois de copiar o código, faça o seguinte:
# 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)