Показати% замість підрахунків у діаграмах категоричних змінних


170

Я будую категоричну змінну, а не показую значення для кожної категорії.

Я шукаю спосіб отримати ggplotпоказ відсотка значень у цій категорії. Звичайно, можна створити іншу змінну з обчисленим відсотком і побудувати графік цієї, але я повинен це зробити кілька десятків разів, і я сподіваюся досягти цього в одній команді.

Я експериментував із чимось подібним

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

але я повинен використовувати його неправильно, оскільки я отримав помилки.

Щоб легко відтворити налаштування, ось спрощений приклад:

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.

У реальному випадку я, ймовірно, буду використовувати ggplotзамість цього qplot, але правильний спосіб використання stat_bin все одно мені ухиляється .

Я також спробував ці чотири підходи:

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

але всі 4 дають:

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

Така ж помилка з'являється і для простого випадку

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

тому явно щось стосується ggplotвзаємодії з одним вектором. Я чухаю голову, гугл за цю помилку дає єдиний результат .


2
Дані повинні бути рамкою даних, а не голодним фактором.
Хадлі

1
додавши до коментаря hadley, перетворення ваших даних у кадр даних за допомогою mydataf = data.frame (mydataf) та перейменування його як імена (mydataf) = foo зробить трюк
Ramnath,

Відповіді:


221

З того часу, як на це відповіли, відбулися деякі змістовні зміни в ggplotсинтаксисі. Підсумовуючи обговорення у коментарях вище:

 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)

Ось відтворюваний приклад із використанням mtcars:

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

введіть тут опис зображення

Це питання зараз є хітом №1 для google для "гістограми відліку ggplot проти відсотків", тому, сподіваємось, це допомагає перекрити всю інформацію, що міститься в коментарях до прийнятої відповіді.

Зауваження: Якщо hpне встановлено як фактор, ggplot повертає:

введіть тут опис зображення


12
Дякую за цю відповідь. Будь-яка ідея, як це зробити класно?
WAF

3
Як стверджує @ WAF, ця відповідь не працює з гранітними даними. Див @ коментар Ервана в stackoverflow.com/questions/22181132 / ...
LeeZamparo

1
Можливо, вам знадобиться префікс percentіз пакетом, з якого вийшло, щоб вищезазначене працювало (я це зробив). ggplot(mtcars, aes(x = factor(hp))) + geom_bar(aes(y = (..count..)/sum(..count..))) + scale_y_continuous(labels = scales::percent)
mammykins

Щоб навпаки використати грані, використовуйте geom_bar(aes(y = (..count..)/tapply(..count..,..PANEL..,sum)[..PANEL..]))натомість. Кожна грань повинна становити 100%.
JWilliman

Чи не були змінені навколо них ".." замінені командою stat () -? ggplot2.tidyverse.org/reference/stat.html
Магнус

58

цей модифікований код повинен працювати

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

якщо у ваших даних є NA, і ви не хочете, щоб вони були включені в сюжет, передайте na.omit (mydataf) як аргумент ggplot.

сподіваюся, що це допомагає.


37
Зауважте, що у ggplot2 версії 0.9.0 formatterаргумент більше не працюватиме. Натомість вам захочеться чогось подібного labels = percent_format()).
joran

25
І з 0.9.0 вам потрібно буде завантажити scalesбібліотеку перед використанням percent_format(), інакше вона не працюватиме. 0.9.0 більше не завантажує підтримуючі пакети.
Андрій

1
Див ? stat_bin. Він показує, які додаткові стовпці додаються до кадру даних ggplot2. Усі додаткові стовпці мають форму ..variable...
Рамнат

1
Чи є сенс замінити aes(y = (..count..)/sum(..count..))на просто aes(y = ..density..)? Візуально він дає дуже схожу (але все ж іншу) картину
Олександр Косенков

6
У ggplot 0.9.3.1.0 вам потрібно спочатку завантажити scalesбібліотеку, а потім використовувати, scale_y_continuous(labels=percent)як згадується в документах
adilapapaya


37

Станом на березень 2017 року, з ggplot22.2.1, я вважаю, що найкраще рішення пояснено в книзі R Hadley Wickham для наукової книги про дані:

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

stat_countобчислює дві змінні: countвикористовується за замовчуванням, але ви можете використовувати, propяка показує пропорції.


3
Це найкраща відповідь станом на червень 2017 року, працює із заповненням за групою та з облицюванням.
Скумін

1
З якихось причин це не дозволяє мені використовувати fillвідображення (не вводиться помилка, але колір заливки не додається).
Макс Кандокія

@MaxCandocia Мені довелося видалити group = 1, щоб отримати карту заповнення. можливо, це допомагає
Tjebo

1
Якщо я видаляю groupпараметр, він не показує належних відсотків, оскільки все належить до його власної групи для кожного унікального значення x.
Макс Кандокія

20

Якщо ви хочете відсотки по осі y і позначені на брусках:

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

введіть тут опис зображення

Додаючи мітки смуги, ви можете опустити вісь y для більш чистої діаграми, додавши до кінця:

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

введіть тут опис зображення


6

Якщо вам потрібні відсоткові мітки, а фактичні N на осі y, спробуйте:

    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)

6

Ось вирішення фацетних даних. (Прийнята відповідь від @Andrew не працює в цьому випадку.) Ідея полягає в тому, щоб вирахувати значення відсотка за допомогою dplyr, а потім використовувати geom_col для створення сюжету.

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~.)

Це сюжет:

введіть тут опис зображення


3

Зауважте, що якщо ваша змінна безперервна, вам доведеться використовувати geom_histogram (), оскільки функція буде групувати змінну за "бінами".

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..))) 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.