2009-11-14 37 views
18

He estado luchando con cómo hacer un Pareto Chart en R usando el paquete ggplot2. En muchos casos, al hacer un gráfico de barras o un histograma, queremos elementos ordenados por el eje X. En un gráfico de Pareto, queremos los artículos ordenados descendiendo por el valor en el eje Y. ¿Hay alguna manera de hacer ggplot para trazar elementos ordenados por el valor en el eje Y? Intenté ordenar primero el marco de datos, pero parece que ggplot los reordena.Creando un gráfico de Pareto con ggplot2 y R

Ejemplo:

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

el val trama de datos está ordenada, pero la salida es el siguiente:

alt text http://www.cerebralmastication.com/wp-content/uploads/2009/11/exp.png

Hadley señaló correctamente que esto produce una mejor gráfica para mostrar los datos reales vs. . Predicho:

ggplot(val, aes(State, Value)) + geom_bar(stat = "identity", subset = .(variable == "estimate"), fill = "grey70") + geom_crossbar(aes(ymin = Value, ymax = Value), subset = .(variable == "actual")) 

que devuelve:

alt text http://www.cerebralmastication.com/wp-content/uploads/2009/11/exp1.png

Pero todavía no es un diagrama de Pareto. ¿Algun consejo?

+0

Usted puede hacer esto con los gráficos de base utilizando el par (nuevo) truco de overplotting - mismos principios que para el 'gráfico con dos ejes Y' habitual problema. Ggplot2 No puedo ayudarlo (sin embargo, un día tal vez tenga tiempo para ponerme al día). –

+0

Me cuesta tanto evitar el aprendizaje de gráficos básicos. Soy fantásticamente vago :) –

Respuesta

15

Las barras en ggplot2 son ordenados por el orden de los niveles del factor.

val$State <- with(val, factor(val$State, levels=val[order(-Value), ]$State)) 
+0

¡Eso es asombroso! Eso es exactamente lo que no pude descifrar cómo hacerlo. ¡Gracias! –

+4

O un poco más sucinto, cambie su primera llamada aes a: 'aes (reordenar (Estado, Valor), Valor)' – hadley

+2

Creo que necesita aes (reordenar (Estado, Valor, media), Valor) - ya que hay dos valores para cada estado? – Andreas

23

Subconjunto y clasificación de sus datos;

valact <- subset(val, variable=='actual') 
valsort <- valact[ order(-valact[,"Value"]),] 

Desde allí es sólo una norma boxplot() con una función acumulativa muy manual en la parte superior:

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) 

que debería tener este aspecto

alt text http://dirk.eddelbuettel.com/misc/jdlong_pareto.png

y ni siquiera necesita el truco de sobre trazado ya que lines() anota felizmente el trazado inicial.

+0

Acepté la respuesta de Chang porque realmente quería hacer esto con ggplot. Pero aún te debo una cerveza por dar una respuesta tan patada. –

+0

Bueno, me perdí los requisitos de ggplot2 ... –

+0

¡le diste mucho más a través de la respuesta a la parte de Perato de lo que esperaba! Mi pregunta era extremadamente estilizada y me había codificado en una esquina donde usar ggplot2 era la salida más fácil. Lo que hiciste con gráficos base fue realmente genial. Gracias de nuevo. –

3

También, ver el paquete qcc que tiene una función pareto.chart(). Parece que utiliza gráficos de base también, así que empieza su recompensa para un ggplot2 solución :-)

4

Con un simple ejemplo:

> 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) hace las cosas correctamente

la ggplot equivalente "debe ser": qplot(x=names(data), y=data, geom='bar')

Pero que reordena de forma incorrecta/ordena los bares por orden alfabético. .. porque así es como se ordenaría levels(factor(names(data))).

Solución: qplot(x=factor(names(data), levels=names(data)), y=data, geom='bar')

Uf!

1

Para simplificar las cosas, consideremos solo las estimaciones.

estimates <- subset(val, variable == "estimate") 

En primer lugar, cambiar el orden de los niveles de factor, de modo que State s se trazan con el fin de disminuir Value.

estimates$State <- with(estimates, reorder(State, -Value)) 

Del mismo modo, reordenamos el conjunto de datos y calculamos un valor acumulativo.

estimates <- estimates[order(estimates$Value, decreasing = TRUE),] 
estimates$cumulative <- cumsum(estimates$Value) 

Ahora estamos listos para dibujar la trama. El truco para obtener una línea y una barra en los mismos ejes es convertir la variable de estado (un factor) en numérica.

p <- ggplot(estimates, aes(State, Value)) + 
    geom_bar() + 
    geom_line(aes(as.numeric(State), cumulative)) 
p 

Como se menciona en la pregunta, tratando de sacar dos parcelas de Pareto de dos grupos de variables justo al lado de la otra, no es muy fácil. Probablemente sería mejor utilizar facetas si quiere múltiples diagramas de Pareto.

7

Un gráfico de Pareto tradicional en ggplot2 .......

tecnica después de leer 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)) 
0
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 
} 
Cuestiones relacionadas