Zeigen Sie% anstelle von Zählungen in Diagrammen kategorialer Variablen an

170

Ich zeichne eine kategoriale Variable und anstatt die Anzahl für jeden Kategoriewert anzuzeigen.

Ich suche nach einer Möglichkeit, ggplotden Prozentsatz der Werte in dieser Kategorie anzuzeigen. Natürlich ist es möglich, eine andere Variable mit dem berechneten Prozentsatz zu erstellen und diese zu zeichnen, aber ich muss es mehrere Dutzend Mal tun und hoffe, dies in einem Befehl zu erreichen.

Ich habe mit so etwas experimentiert

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

aber ich muss es falsch verwenden, da ich Fehler habe.

Um das Setup einfach zu reproduzieren, hier ein vereinfachtes Beispiel:

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.

Im wirklichen Fall werde ich wahrscheinlich ggplotanstelle von verwenden qplot, aber der richtige Weg, stat_bin zu verwenden, entgeht mir immer noch.

Ich habe auch diese vier Ansätze ausprobiert:

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

aber alle 4 geben:

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

Der gleiche Fehler tritt für den einfachen Fall von auf

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

Es geht also eindeutig darum, wie ggplotmit einem einzelnen Vektor interagiert wird. Ich kratzte mir am Kopf und googelte nach diesem Fehler, was zu einem einzigen Ergebnis führte .

Wishihadabettername
quelle
2
Daten sollten ein Datenrahmen sein, kein bloßer Faktor.
Hadley
1
Das Hinzufügen zu Hadleys Kommentar, das Konvertieren Ihrer Daten in einen Datenrahmen mit mydataf = data.frame (mydataf) und das Umbenennen in names (mydataf) = foo reichen aus
Ramnath,

Antworten:

221

Seitdem dies beantwortet wurde, wurden einige bedeutende Änderungen an der ggplotSyntax vorgenommen. Fassen Sie die Diskussion in den obigen Kommentaren zusammen:

 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)

Hier ist ein reproduzierbares Beispiel mit mtcars:

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

Geben Sie hier die Bildbeschreibung ein

Diese Frage ist derzeit die Nummer 1 bei Google für "ggplot count vs prozentuales Histogramm". Hoffentlich hilft dies dabei, alle Informationen zu destillieren, die derzeit in Kommentaren zur akzeptierten Antwort enthalten sind.

Anmerkung: Wenn hpnicht als Faktor festgelegt, gibt ggplot Folgendes zurück:

Geben Sie hier die Bildbeschreibung ein

Andrew
quelle
12
Danke für diese Antwort. Irgendeine Idee, wie man es klassenmäßig macht?
WAF
3
Wie. @ WAF vorschlägt, funktioniert diese Antwort nicht mit facettierten Daten. Siehe @ Erwans
LeeZamparo
1
Möglicherweise müssen Sie percentdem Paket, aus dem es stammt , ein Präfix voranstellen , damit das oben genannte funktioniert (ich habe es getan). ggplot(mtcars, aes(x = factor(hp))) + geom_bar(aes(y = (..count..)/sum(..count..))) + scale_y_continuous(labels = scales::percent)
Mammykins
Um die Verwendung von Facetten zu umgehen, verwenden Sie geom_bar(aes(y = (..count..)/tapply(..count..,..PANEL..,sum)[..PANEL..]))stattdessen. Jede Facette sollte 100% ergeben.
JWilliman
Wurden Variablen mit ".." nicht durch den Befehl stat () - ersetzt? ggplot2.tidyverse.org/reference/stat.html
Magnus
58

Dieser geänderte Code sollte funktionieren

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

Wenn Ihre Daten NAs haben und Sie nicht möchten, dass sie in den Plot aufgenommen werden, übergeben Sie na.omit (mydataf) als Argument an ggplot.

hoffe das hilft.

Ramnath
quelle
37
Beachten Sie, dass das formatterArgument in ggplot2 Version 0.9.0 nicht mehr funktioniert. Stattdessen möchten Sie so etwas wie labels = percent_format()).
Joran
25
Und mit 0.9.0 müssen Sie die scalesBibliothek vor der Verwendung laden percent_format(), sonst funktioniert es nicht. 0.9.0 lädt nicht mehr automatisch unterstützende Pakete.
Andrew
1
Siehe ? stat_bin. Es zeigt, durch welche zusätzlichen Spalten dem Datenrahmen hinzugefügt wird ggplot2. Alle zusätzlichen Spalten haben die Form ..variable...
Ramnath
1
Ist es sinnvoll, aes(y = (..count..)/sum(..count..))einfach zu ersetzen aes(y = ..density..)? Optisch gibt es ein sehr ähnliches (aber immer noch anderes) Bild
Alexander Kosenkov
6
In ggplot 0.9.3.1.0 möchten Sie zuerst die scalesBibliothek laden und dann scale_y_continuous(labels=percent)wie in den Dokumenten erwähnt verwenden
adilapapaya
49

Mit ggplot2 Version 2.1.0 ist es

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

Ab März 2017 wird mit ggplot22.2.1 die beste Lösung in Hadley Wickhams R for Data Science-Buch erklärt:

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

stat_countBerechnet zwei Variablen: Wird countstandardmäßig verwendet, Sie können jedoch auswählen, propwelche Proportionen angezeigt werden sollen .

Olivier Ma
quelle
3
Dies ist die beste Antwort ab Juni 2017, arbeitet mit dem Füllen nach Gruppen und mit Facettieren.
Skumin
1
Aus irgendeinem Grund kann ich das fillMapping nicht verwenden (es wird kein Fehler ausgegeben, aber keine Füllfarbe hinzugefügt).
Max Candocia
@ MaxCandocia Ich musste entfernen group = 1, um eine Füllungszuordnung zu erhalten. Vielleicht hilft es
Tjebo
1
Wenn ich den groupParameter entferne , werden jedoch nicht die richtigen Prozentsätze angezeigt, da für jeden eindeutigen x-Wert alles zu einer eigenen Gruppe gehört.
Max Candocia
20

Wenn Sie Prozentsätze auf der y-Achse und Beschriftungen auf den Balken wünschen :

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

Geben Sie hier die Bildbeschreibung ein

Wenn Sie die Balkenbeschriftungen hinzufügen, möchten Sie möglicherweise die y-Achse für ein übersichtlicheres Diagramm weglassen, indem Sie am Ende Folgendes hinzufügen:

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

Geben Sie hier die Bildbeschreibung ein

Sam Firke
quelle
6

Wenn Sie prozentuale Beschriftungen, aber tatsächliche Ns auf der y-Achse wünschen , versuchen Sie Folgendes:

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

Hier ist eine Problemumgehung für facettierte Daten. (Die akzeptierte Antwort von @Andrew funktioniert in diesem Fall nicht.) Die Idee ist, den Prozentwert mit dplyr zu berechnen und dann mit geom_col das Diagramm zu erstellen.

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

Dies ist die Handlung:

Geben Sie hier die Bildbeschreibung ein

ACNB
quelle
3

Beachten Sie, dass Sie, wenn Ihre Variable kontinuierlich ist, geom_histogram () verwenden müssen, da die Funktion die Variable nach "Bins" gruppiert.

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
quelle