Mostrar% em vez de contagens em gráficos de variáveis ​​categóricas

170

Estou plotando uma variável categórica e, em vez de mostrar as contagens para cada valor de categoria.

Estou procurando uma maneira ggplotde exibir a porcentagem de valores nessa categoria. Obviamente, é possível criar outra variável com a porcentagem calculada e plotá-la, mas tenho que fazê-lo várias dezenas de vezes e espero conseguir isso em um único comando.

Eu estava experimentando algo como

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

mas devo usá-lo incorretamente, pois obtive erros.

Para reproduzir facilmente a configuração, veja um exemplo 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.

No caso real, provavelmente usarei em ggplotvez de qplot, mas a maneira correta de usar stat_bin ainda me ilude.

Eu também tentei essas quatro abordagens:

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();

mas todos os 4 dão:

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

O mesmo erro aparece no caso simples de

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

então é claramente algo sobre como ggplotinterage com um único vetor. Estou coçando a cabeça, pesquisando no Google por esse erro, dá um único resultado .

wishihadabettername
fonte
2
Os dados devem ser um quadro de dados, não um fator simples.
hadley
1
adicionando ao comentário de Hadley, convertendo seus dados em um quadro de dados usando mydataf = data.frame (mydataf) e renomeá-lo como nomes (mydataf) = foo irá fazer o truque
Ramnath

Respostas:

222

Desde que isso foi respondido, houve algumas alterações significativas na ggplotsintaxe. Resumindo a discussão nos comentários acima:

 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)

Aqui está um exemplo reproduzível usando mtcars:

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

insira a descrição da imagem aqui

Atualmente, esta pergunta é o número 1 no google de 'contagem de ggplot versus histograma de porcentagem', portanto, espero que isso ajude a destilar todas as informações atualmente armazenadas em comentários sobre a resposta aceita.

Observação: Se hpnão está definido como um fator, retornos ggplot:

insira a descrição da imagem aqui

Andrew
fonte
12
Obrigado por esta resposta. Alguma idéia de como fazer isso em classe?
WAF 25/02
3
Como sugere o. @ WAF, esta resposta não funciona com dados facetados. Veja o comentário de @ Erwan em stackoverflow.com/questions/22181132/…
LeeZamparo 11/11/2015
1
Pode ser necessário prefixar percento pacote do qual ele é feito para que o trabalho acima funcione (eu fiz). ggplot(mtcars, aes(x = factor(hp))) + geom_bar(aes(y = (..count..)/sum(..count..))) + scale_y_continuous(labels = scales::percent)
Mammykins 22/05/19
Para contornar o uso de facetas, use geom_bar(aes(y = (..count..)/tapply(..count..,..PANEL..,sum)[..PANEL..])). Cada faceta deve somar 100%.
JWilliman
As variáveis ​​com ".." ao redor delas não foram substituídas pelo comando stat () -? ggplot2.tidyverse.org/reference/stat.html
Magnus
58

esse código modificado deve funcionar

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

se seus dados tiverem NAs e você não desejar que eles sejam incluídos no gráfico, passe na.omit (mydataf) como argumento para o ggplot.

espero que isto ajude.

Ramnath
fonte
37
Observe que no ggplot2 versão 0.9.0 o formatterargumento não funcionará mais. Em vez disso, você vai querer algo como labels = percent_format()).
joran
25
E com o 0.9.0, você precisará carregar a scalesbiblioteca antes de usá-la percent_format(), caso contrário, não funcionará. 0.9.0 não carrega mais pacotes de suporte automaticamente.
Andrew
1
Veja ? stat_bin. Mostra quais colunas adicionais são adicionadas ao quadro de dados ggplot2. Todas as colunas extras são da forma ..variable...
Ramnath #
1
Faz sentido substituir aes(y = (..count..)/sum(..count..))simplesmente aes(y = ..density..)? Visualmente dar imagem muito semelhante (mas ainda diferente)
Alexander Kosenkov
6
Em ggplot 0.9.3.1.0, você vai querer primeiro carregamento da scalesbiblioteca, em seguida, usar scale_y_continuous(labels=percent)como mencionado nos docs
adilapapaya
49

Com o ggplot2 versão 2.1.0, é

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

Em março de 2017, com o ggplot22.2.1, acho que a melhor solução é explicada no livro R de Hadley Wickham para ciência de dados:

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

stat_countcalcula duas variáveis: counté usada por padrão, mas você pode optar por usar as propque mostram proporções.

Olivier Ma
fonte
3
Esta é a melhor resposta em junho de 2017, trabalha com preenchimento por grupo e com faceta.
precisa
1
Por alguma razão, isso não me permite usar o fillmapeamento (nenhum erro é gerado, mas nenhuma cor de preenchimento é adicionada).
Max Candocia
@MaxCandocia Eu tive que remover group = 1para obter o mapeamento de preenchimento. talvez ele ajuda
Tjebo
1
Se eu remover o groupparâmetro, no entanto, ele não mostra as porcentagens apropriadas, pois tudo pertence ao seu próprio grupo para cada valor x exclusivo.
Max Candocia
20

Se você deseja porcentagens no eixo y e rotuladas nas 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")

insira a descrição da imagem aqui

Ao adicionar os rótulos de barra, você pode omitir o eixo y para um gráfico mais limpo, adicionando ao final:

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

insira a descrição da imagem aqui

Sam Firke
fonte
6

Se você quiser rótulos de porcentagem , mas Ns reais no eixo y, tente o seguinte:

    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
fonte
6

Aqui está uma solução alternativa para dados facetados. (A resposta aceita por @Andrew não funciona neste caso.) A idéia é calcular o valor percentual usando dplyr e, em seguida, usar geom_col para criar o 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~.)

Este é o enredo:

insira a descrição da imagem aqui

ACNB
fonte
4

Observe que se sua variável for contínua, você terá que usar geom_histogram (), pois a função agrupará a variável por "compartimentos".

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..))) 
Rtist
fonte