Creazione di un diagramma di Pareto con ggplot2 e R
Domanda
Ho lottato con il modo di fare una Pareto Grafico in R utilizzando il pacchetto ggplot2 . In molti casi, quando si effettua un grafico a barre o istogramma vogliamo elementi ordinati per l'asse X. In un diagramma di Pareto vogliamo che gli articoli ordinati decrescente in base al valore nell'asse Y. C'è un modo per ottenere ggplot per tracciare articoli ordinati in base al valore nell'asse Y? Ho provato classificare il frame di dati prima ma sembra ggplot riordina.
Esempio:
val <- read.csv("http://www.cerebralmastication.com/wp-content/uploads/2009/11/val.txt")
val<-with(val, val[order(-Value), ])
p <- ggplot(val)
p + geom_bar(aes(State, Value, fill=variable), stat = "identity", position="dodge") + scale_fill_brewer(palette = "Set1")
Val frame di dati vengono ordinati, ma l'uscita è simile al seguente:
(fonte: cerebralmastication.com )
Hadley ha giustamente osservato che questo produce una grafica molto migliore per mostrare valori effettivi vs. predetto:
ggplot(val, aes(State, Value)) + geom_bar(stat = "identity", subset = .(variable == "estimate"), fill = "grey70") + geom_crossbar(aes(ymin = Value, ymax = Value), subset = .(variable == "actual"))
che restituisce:
(fonte: cerebralmastication.com )
Ma non è ancora un diagramma di Pareto. Eventuali suggerimenti?
Soluzione
Le barre in ggplot2 sono ordinate per l'ordinamento dei livelli del fattore.
val$State <- with(val, factor(val$State, levels=val[order(-Value), ]$State))
Altri suggerimenti
Impostazione secondaria e l'ordinamento dei dati;
valact <- subset(val, variable=='actual')
valsort <- valact[ order(-valact[,"Value"]),]
Da lì è solo un boxplot()
di serie con una funzione cumulativa molto manuale sulla parte superiore:
op <- par(mar=c(3,3,3,3))
bp <- barplot(valsort [ , "Value"], ylab="", xlab="", ylim=c(0,1),
names.arg=as.character(valsort[,"State"]), main="How's that?")
lines(bp, cumsum(valsort[,"Value"])/sum(valsort[,"Value"]),
ylim=c(0,1.05), col='red')
axis(4)
box()
par(op)
che dovrebbe assomigliare a questo
(fonte: eddelbuettel.com )
e non ha nemmeno bisogno il trucco overplotting come lines()
annota felicemente la trama iniziale.
Un grafico tradizionale Pareto ggplot2 .......
Sviluppato dopo la lettura Cano, E. L., Moguerza, J. M., & Redchuk, A. (2012). Six Sigma con R. (G. Robert, K. Hornik, & G. Parmigiani, Eds.) Springer.
library(ggplot2);library(grid)
counts <- c(80, 27, 66, 94, 33)
defects <- c("price code", "schedule date", "supplier code", "contact num.", "part num.")
dat <- data.frame(count = counts, defect = defects, stringsAsFactors=FALSE )
dat <- dat[order(dat$count, decreasing=TRUE),]
dat$defect <- factor(dat$defect, levels=dat$defect)
dat$cum <- cumsum(dat$count)
count.sum<-sum(dat$count)
dat$cum_perc<-100*dat$cum/count.sum
p1<-ggplot(dat, aes(x=defect, y=cum_perc, group=1))
p1<-p1 + geom_point(aes(colour=defect), size=4) + geom_path()
p1<-p1+ ggtitle('Pareto Chart')+ theme(axis.ticks.x = element_blank(), axis.title.x = element_blank(),axis.text.x = element_blank())
p1<-p1+theme(legend.position="none")
p2<-ggplot(dat, aes(x=defect, y=count,colour=defect, fill=defect))
p2<- p2 + geom_bar()
p2<-p2+theme(legend.position="none")
plot.new()
grid.newpage()
pushViewport(viewport(layout = grid.layout(2, 1)))
print(p1, vp = viewport(layout.pos.row = 1,layout.pos.col = 1))
print(p2, vp = viewport(layout.pos.row = 2,layout.pos.col = 1))
Con un semplice esempio:
> data
PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10
0.29056 0.23833 0.11003 0.05549 0.04678 0.03788 0.02770 0.02323 0.02211 0.01925
barplot(data)
fa le cose in modo corretto
il ggplot equivalente "dovrebbe essere": qplot(x=names(data), y=data, geom='bar')
Ma che riordina gli errato / ordina la barre in ordine alfabetico ... perché è così che levels(factor(names(data)))
sarebbe stato ordinato.
Soluzione: qplot(x=factor(names(data), levels=names(data)), y=data, geom='bar')
Accidenti!
Inoltre, si rimanda al foglio qcc che ha una funzione pareto.chart()
. Sembra che utilizza la grafica di base troppo, in modo da iniziare la vostra generosità per un ggplot2 soluzione: -)
Per semplificare le cose, facciamo solo prendere in considerazione solo le stime.
estimates <- subset(val, variable == "estimate")
Per prima cosa riordinare i livelli dei fattori, in modo che State
s sono tracciate in ordine di Value
decrescente.
estimates$State <- with(estimates, reorder(State, -Value))
Allo stesso modo, abbiamo riordinare i set di dati e calcolare un valore cumulativo.
estimates <- estimates[order(estimates$Value, decreasing = TRUE),]
estimates$cumulative <- cumsum(estimates$Value)
Ora siamo pronti per disegnare la trama. Il trucco per ottenere una linea e bar sugli stessi assi è di convertire la variabile Stato (fattore) per essere numerico.
p <- ggplot(estimates, aes(State, Value)) +
geom_bar() +
geom_line(aes(as.numeric(State), cumulative))
p
Come indicato nella domanda, cercando di disegnare due lotti di Pareto di due gruppi di variabili accanto gli uni agli altri non è molto facile. Si sarebbe probabilmente essere meglio utilizzare sfaccettatura se si vuole più grafici di Pareto.
freqplot = function(x, by = NULL, right = FALSE)
{
if(is.null(by)) stop('Valor de "by" precisa ser especificado.')
breaks = seq(min(x), max(x), by = by )
ecd = ecdf(x)
den = ecd(breaks)
table = table(cut(x, breaks = breaks, right = right))
table = table/sum(table)
intervs = factor(names(table), levels = names(table))
freq = as.numeric(table/sum(table))
acum = as.numeric(cumsum(table))
normalize.vec = function(x){
(x - min(x))/(max(x) - min(x))
}
dados = data.frame(classe = intervs, freq = freq, acum = acum, acum_norm = normalize.vec(acum))
p = ggplot(dados) +
geom_bar(aes(classe, freq, fill = classe), stat = 'identity') +
geom_point(aes(classe, acum_norm, group = '1'), shape = I(1), size = I(3), colour = 'gray20') +
geom_line(aes(classe, acum_norm, group = '1'), colour = I('gray20'))
p
}