Mostrar% en lugar de conteos en gráficos de variables categóricas

171

Estoy trazando una variable categórica y en lugar de mostrar los recuentos para cada valor de categoría.

Estoy buscando una manera de ggplotmostrar el porcentaje de valores en esa categoría. Por supuesto, es posible crear otra variable con el porcentaje calculado y trazar esa, pero tengo que hacerlo varias docenas de veces y espero lograr eso en un solo comando.

Estaba experimentando con algo como

qplot(mydataf) +
  stat_bin(aes(n = nrow(mydataf), y = ..count../n)) +
  scale_y_continuous(formatter = "percent")

pero debo usarlo incorrectamente, ya que obtuve errores.

Para reproducir fácilmente la configuración, aquí hay un ejemplo simplificado:

mydata <- c ("aa", "bb", NULL, "bb", "cc", "aa", "aa", "aa", "ee", NULL, "cc");
mydataf <- factor(mydata);
qplot (mydataf); #this shows the count, I'm looking to see % displayed.

En el caso real, probablemente usaré enggplot lugar de qplot, pero la forma correcta de usar stat_bin todavía me elude.

También probé estos cuatro enfoques:

ggplot(mydataf, aes(y = (..count..)/sum(..count..))) + 
  scale_y_continuous(formatter = 'percent');

ggplot(mydataf, aes(y = (..count..)/sum(..count..))) + 
  scale_y_continuous(formatter = 'percent') + geom_bar();

ggplot(mydataf, aes(x = levels(mydataf), y = (..count..)/sum(..count..))) + 
  scale_y_continuous(formatter = 'percent');

ggplot(mydataf, aes(x = levels(mydataf), y = (..count..)/sum(..count..))) + 
  scale_y_continuous(formatter = 'percent') + geom_bar();

pero los 4 dan:

Error: ggplot2 doesn't know how to deal with data of class factor

El mismo error aparece para el caso simple de

ggplot (data=mydataf, aes(levels(mydataf))) +
  geom_bar()

entonces es claramente algo acerca de cómo ggplotinteractúa con un solo vector. Me estoy rascando la cabeza, buscar en Google ese error da un solo resultado .

wishihadabettername
fuente
2
Los datos deben ser un marco de datos, no un factor básico.
hadley
1
agregando al comentario de hadley, convirtiendo sus datos en un marco de datos usando mydataf = data.frame (mydataf), y renombrándolo como nombres (mydataf) = foo hará el truco
Ramnath

Respuestas:

222

Desde que se respondió esto, ha habido algunos cambios significativos en la ggplotsintaxis. Resumiendo la discusión en los comentarios anteriores:

 require(ggplot2)
 require(scales)

 p <- ggplot(mydataf, aes(x = foo)) +  
        geom_bar(aes(y = (..count..)/sum(..count..))) + 
        ## version 3.0.0
        scale_y_continuous(labels=percent)

Aquí hay un ejemplo reproducible usando mtcars:

 ggplot(mtcars, aes(x = factor(hp))) +  
        geom_bar(aes(y = (..count..)/sum(..count..))) + 
        scale_y_continuous(labels = percent) ## version 3.0.0

ingrese la descripción de la imagen aquí

Esta pregunta es actualmente el éxito número 1 en Google para 'conteo de ggplot vs histograma de porcentaje', por lo que esperamos que esto ayude a destilar toda la información actualmente alojada en los comentarios sobre la respuesta aceptada.

Observación: si hpno se establece como factor, ggplot devuelve:

ingrese la descripción de la imagen aquí

Andrés
fuente
12
Gracias por esta respuesta ¿Alguna idea sobre cómo hacerlo en clase?
WAF
3
Como sugiere. @ WAF, esta respuesta no funciona con datos facetados. Vea el comentario de @ Erwan en stackoverflow.com/questions/22181132/…
LeeZamparo
1
Es posible que necesite un prefijo percentcon el paquete de donde proviene para que funcione lo anterior (lo hice). ggplot(mtcars, aes(x = factor(hp))) + geom_bar(aes(y = (..count..)/sum(..count..))) + scale_y_continuous(labels = scales::percent)
mammykins
Para evitar el uso de facetas, use geom_bar(aes(y = (..count..)/tapply(..count..,..PANEL..,sum)[..PANEL..]))en su lugar. Cada faceta debe sumar 100%.
JWilliman
¿No se reemplazaron las variables con ".." a su alrededor con el comando stat ()? ggplot2.tidyverse.org/reference/stat.html
Magnus
58

este código modificado debería funcionar

p = ggplot(mydataf, aes(x = foo)) + 
    geom_bar(aes(y = (..count..)/sum(..count..))) + 
    scale_y_continuous(formatter = 'percent')

si sus datos tienen NA y no desea que se incluyan en el diagrama, pase na.omit (mydataf) como argumento para ggplot.

espero que esto ayude.

Ramnath
fuente
37
Tenga en cuenta que en ggplot2 versión 0.9.0 el formatterargumento ya no funcionará. En cambio, querrás algo así labels = percent_format()).
joran
25
Y con 0.9.0 deberá cargar la scalesbiblioteca antes de usarla percent_format(), de lo contrario no funcionará. 0.9.0 ya no carga automáticamente los paquetes de soporte.
Andrew
1
Ver ? stat_bin . Muestra qué columnas adicionales se agregan al marco de datos mediante ggplot2. Todas las columnas adicionales son de la forma ..variable...
Ramnath
1
¿Tiene sentido reemplazarlo aes(y = (..count..)/sum(..count..))simplemente?aes(y = ..density..) ? Visualmente da una imagen muy similar (pero aún diferente)
Alexander Kosenkov
66
En ggplot 0.9.3.1.0, primero querrás cargar la scalesbiblioteca, luego usar scale_y_continuous(labels=percent)como se menciona en los documentos
adilapapaya
49

Con ggplot2 versión 2.1.0 es

+ scale_y_continuous(labels = scales::percent)
Fabian Hertwig
fuente
37

A partir de marzo de 2017, con ggplot22.2.1 creo que la mejor solución se explica en el libro R de Hadley Wickham para ciencia de datos:

ggplot(mydataf) + stat_count(mapping = aes(x=foo, y=..prop.., group=1))

stat_countcalcula dos variables: countse usa de manera predeterminada, pero puede elegir usar propque muestre proporciones.

Olivier Ma
fuente
3
Esta es la mejor respuesta a partir de junio de 2017, trabaja con relleno por grupo y con facetado.
Skumin
1
Por alguna razón, esto no me permite usar el fillmapeo (no se produce ningún error, pero no se agrega color de relleno).
Max Candocia
@MaxCandocia Tuve que eliminar group = 1para obtener el mapeo de relleno. tal vez ayuda
Tjebo
1
Sin embargo, si elimino el groupparámetro, no muestra los porcentajes adecuados, ya que todo pertenece a su propio grupo para cada valor x único.
Max Candocia
20

Si desea porcentajes en el eje y etiquetados en las barras:

library(ggplot2)
library(scales)
ggplot(mtcars, aes(x = as.factor(am))) +
  geom_bar(aes(y = (..count..)/sum(..count..))) +
  geom_text(aes(y = ((..count..)/sum(..count..)), label = scales::percent((..count..)/sum(..count..))), stat = "count", vjust = -0.25) +
  scale_y_continuous(labels = percent) +
  labs(title = "Manual vs. Automatic Frequency", y = "Percent", x = "Automatic Transmission")

ingrese la descripción de la imagen aquí

Al agregar las etiquetas de barra, es posible que desee omitir el eje y para un gráfico más limpio, agregando al final:

  theme(
        axis.text.y=element_blank(), axis.ticks=element_blank(),
        axis.title.y=element_blank()
  )

ingrese la descripción de la imagen aquí

Sam Firke
fuente
6

Si desea etiquetas de porcentaje pero Ns reales en el eje y, intente esto:

    library(scales)
perbar=function(xx){
      q=ggplot(data=data.frame(xx),aes(x=xx))+
      geom_bar(aes(y = (..count..)),fill="orange")
       q=q+    geom_text(aes(y = (..count..),label = scales::percent((..count..)/sum(..count..))), stat="bin",colour="darkgreen") 
      q
    }
    perbar(mtcars$disp)
Steve Powell
fuente
6

Aquí hay una solución para los datos facetados. (La respuesta aceptada por @Andrew no funciona en este caso). La idea es calcular el valor porcentual usando dplyr y luego usar geom_col para crear el gráfico.

library(ggplot2)
library(scales)
library(magrittr)
library(dplyr)

binwidth <- 30

mtcars.stats <- mtcars %>%
  group_by(cyl) %>%
  mutate(bin = cut(hp, breaks=seq(0,400, binwidth), 
               labels= seq(0+binwidth,400, binwidth)-(binwidth/2)),
         n = n()) %>%
  group_by(cyl, bin) %>%
  summarise(p = n()/n[1]) %>%
  ungroup() %>%
  mutate(bin = as.numeric(as.character(bin)))

ggplot(mtcars.stats, aes(x = bin, y= p)) +  
  geom_col() + 
  scale_y_continuous(labels = percent) +
  facet_grid(cyl~.)

Esta es la trama:

ingrese la descripción de la imagen aquí

ACNB
fuente
4

Tenga en cuenta que si su variable es continua, deberá usar geom_histogram (), ya que la función agrupará la variable por "bins".

df <- data.frame(V1 = rnorm(100))

ggplot(df, aes(x = V1)) +  
  geom_histogram(aes(y = (..count..)/sum(..count..))) 

# if you use geom_bar(), with factor(V1), each value of V1 will be treated as a
# different category. In this case this does not make sense, as the variable is 
# really continuous. With the hp variable of the mtcars (see previous answer), it 
# worked well since hp was not really continuous (check unique(mtcars$hp)), and one 
# can want to see each value of this variable, and not to group it in bins.
ggplot(df, aes(x = factor(V1))) +  
  geom_bar(aes(y = (..count..)/sum(..count..))) 
Rist
fuente