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


171

Я строю категориальную переменную и вместо того, чтобы показывать счетчики для каждого значения категории.

Я ищу способ 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
добавление комментария к хадли, преобразование ваших данных в фрейм данных с использованием mydataf = data.frame (mydataf) и переименование его в имена (mydataf) = foo помогут вам
Ramnath

Ответы:


222

С тех пор, как на этот вопрос был дан ответ, в 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 count vs процент гистограммы», поэтому, надеюсь, это поможет отыскать всю информацию, размещенную в настоящее время в комментариях к принятому ответу.

Примечание: Если 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)
маммикинс

Чтобы обойти использование граней, используйте geom_bar(aes(y = (..count..)/tapply(..count..,..PANEL..,sum)[..PANEL..]))вместо этого. Каждый аспект должен составлять до 100%.
Дж. Виллиман

Разве переменные с ".." вокруг них не были заменены командой 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, и вы не хотите, чтобы они были включены в график, передайте g.plot аргумент na.omit (mydataf) в качестве аргумента.

надеюсь это поможет.


37
Обратите внимание, что в ggplot2 версии 0.9.0 formatterаргумент больше не будет работать. Вместо этого вы захотите что-то вроде labels = percent_format()).
Джоран

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


38

По состоянию на март 2017 года, с ggplot22.2.1, я думаю, что лучшее решение объясняется в книге Хэдли Уикхэма R для книги по науке о данных:

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

Если вы хотите , проценты по оси у и маркированы на брусьях:

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

Это сюжет:

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


4

Обратите внимание, что если ваша переменная непрерывна, вы должны будете использовать geom_histogram (), так как функция сгруппирует переменную по "bin".

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.