7 Häufigkeiten
In diesem Kapitel betrachten wir ein einzelnes Merkmal
Die beobachteten Werte von tmdb
, der eine Auswahl aus “The Movies Database” enthält.
<- read_csv("../data/tmdb.csv", col_types = "cfnnnnn")
tmdb head(tmdb)
# A tibble: 6 × 7
title genre year budget revenue duration avgvote
<chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Avatar Acti… 2009 237 2788. 162 7.2
2 Pirates of the Caribbean: At Worl… Adve… 2007 300 961 169 6.9
3 Spectre Acti… 2015 245 881. 148 6.3
4 The Dark Knight Rises Acti… 2012 250 1085. 165 7.6
5 John Carter Acti… 2012 260 284. 132 6.1
6 Spider-Man 3 Fant… 2007 258 891. 139 5.9
Es gibt in R mehrere Wege, um ein Merkmal als Vektor aus einem Dataframe heraus zu ziehen. Zwei dieser Wege haben wir im Abschnitt 3.3 bereits kennen gelernt. Hier sind sie erneut, ergänzt um eine dritte Möglichkeit:
- Spaltennummer in doppelten Klammern
<- tmdb[[2]] x
- Auswahl mit dem Dollarzeichen und dem Spaltennamen
<- tmdb$genre x
- Der pull-Befehl in tidyverse
<- pull(tmdb, genre) x
oder
<- tmdb %>% pull(genre) x
In diesem Beispiel ist x
nun ein Vektor, der die univariaten Daten zum Ursprungsland der Filme im Dataframe tmdb
enthält. Wenn man den Vektor (also die Urliste) mit dem Befehl
print(x)
anzeigt, denn erhält man schlicht eine Auflistung aller Werte. Interaktiv kann man auch einfach nur x
eingeben. Da der Vektor mit 4079 Elementen sehr lang ist, wird der Output hier nicht gezeigt.
Um den Umfang (engl. size)
<- dim(tmdb)[1] n
oder man ermittelt die Länge des aus dem Dataframe herausgezogenen Vektors,
<- length(x) n
In beiden Fällen erhält man den Wert
print(n)
[1] 4079
Wenn eine Variable
7.1 Absolute Häufigkeiten
Die absolute Häufigkeit (engl. absolute frequency) gibt für jeden möglichen Wert (Ausprägung) an, wie oft dieser Wert angenommen wird. Wenn wir die möglichen Werte mit
Die Summe aller absoluten Häufigkeiten ergibt den gesamten Populationsumfang,
In R gibt es mehrere Wege, die absoluten Häufigkeiten auszuzählen.
Wenn die Daten in Form eines Vektors vorliegen, lautet der R-Befehl für die absoluten Häufigkeiten table
. Er liefert folgenden Output (für einen Vektor x
):
table(x)
x
Action Adventure Fantasy Animation Drama Thriller Comedy Romance
726 333 115 121 1088 180 951 99
Crime Horror
188 278
Offenbar ist die Tabelle hier nicht senkrecht, sondern waagerecht angeordnet. Man erkennt, dass in dem Dataframe viele Actionfilme, Dramen und Komödien zu finden sind, aber nur wenige Romanzen oder Fantasy-Filme.
Die Häufigkeiten lassen sich auch ermitteln, wenn die Variable nicht als Vektor aus dem Dataframe gezogen wurden. Man verwendet für die Auszählung die Funktion group_by
, um den Dataframe nach den Ausprägungen der Variable zu gruppieren, für die man die Häufigkeiten berechnen will. Anschließend kann man in der summarise
-Funktion mit n()
die Häufigkeiten ermitteln:
group_by(tmdb, genre) %>%
summarise(n=n())
# A tibble: 10 × 2
genre n
<fct> <int>
1 Action 726
2 Adventure 333
3 Fantasy 115
4 Animation 121
5 Drama 1088
6 Thriller 180
7 Comedy 951
8 Romance 99
9 Crime 188
10 Horror 278
Ein Vorteil dieses Vorgehens ist, dass man den Output leicht umsortieren kann, z.B. nach der Häufigkeit absteigend:
group_by(tmdb, genre) %>%
summarise(n=n()) %>%
arrange(desc(n))
# A tibble: 10 × 2
genre n
<fct> <int>
1 Drama 1088
2 Comedy 951
3 Action 726
4 Adventure 333
5 Horror 278
6 Crime 188
7 Thriller 180
8 Animation 121
9 Fantasy 115
10 Romance 99
Wenn die Häufigkeiten nicht in Form einer Tabelle, sondern als Grafik dargestellt werden sollen, kann man in ggplot
folgendermaßen vorgehen.
ggplot(tmdb, aes(x=genre)) + geom_bar()
Zur Erklärung: Das erste Argument in ggplot
(also tmdb
) ist der Dataframe, der die Variable enthält. Mit Hilfe von aes
wird festgelegt, welche Variable als Aesthetic gezeigt werden soll. Hier wird (im Gegensatz zu einem Streudiagramm) nur eine Variable ausgewählt, die Angabe x=
legt fest, dass die Ausprägungen entlang der x-Achse angezeigt werden sollen. Nach dem Pluszeichen folgt die Angabe, durch welche geometrische Form die Darstellung erfolgen soll, hier also durch ein Balkendiagramm (bar plot).
Wenn man als Aesthetic y=
eingibt, werden die Ausprägungen entlang der y-Achse angezeigt, also als horizontale Balken. Das ist manchmal empfehlenswert, weil sich die Beschriftungen der Balken bei längeren Labels dann nicht überlappen.
ggplot(tmdb, aes(y=genre)) + geom_bar()
Das Lesen eines Balkendiagramms ist einfacher, wenn die Balken nach ihrer Länge geordnet werden. Das ist in R leider nicht auf elementare Weise möglich, wenn die Variable nominal skaliert und als Datentyp factor
gespeichert ist. Das tidyverse
-Paket forcats
bietet eine Reihe von Funktionen, mit denen man Variablen vom Datentyp factor
bearbeiten kann. Als Beispiel wird hier gezeigt, wie mit der Funktion fct_infreq
die Ausprägungen der factor
-Variable genre
der Häufigkeit nach geordnet werden können.
ggplot(tmdb, aes(x=fct_infreq(genre))) + geom_bar()
7.2 Relative Häufigkeiten
Neben den absoluten Häufigkeiten sind oft auch die relativen Häufigkeiten (engl. relative frequencies) von Interesse. Absolute Häufigkeiten sind Anzahlen, relative Häufigkeiten sind Anteile, sie werden durch eine Zahl zwischen 0 und 1 oder in Prozent (zwischen 0 und 100) angegeben. Die relative Häufigkeit der Ausprägung
Wenn die Daten als Vektor vorliegen, kann man die Anteile einer Tabelle bestimmen, indem man die Funktion proportions
auf das table
-Objekt wendet.
proportions(table(x))
x
Action Adventure Fantasy Animation Drama Thriller Comedy
0.17798480 0.08163766 0.02819318 0.02966413 0.26673204 0.04412846 0.23314538
Romance Crime Horror
0.02427065 0.04608973 0.06815396
Der Output ist nicht gut lesbar, weil die Zahl der Nachkommastellen zu groß ist. Mit der Funktion round
runden wir die Ausgabe auf eine vorgegebene Anzahl von Nachkommastellen, z.B. auf vier Stellen:
round(proportions(table(x)), 4)
x
Action Adventure Fantasy Animation Drama Thriller Comedy Romance
0.1780 0.0816 0.0282 0.0297 0.2667 0.0441 0.2331 0.0243
Crime Horror
0.0461 0.0682
Wir sehen, dass ein Viertel der Filme Komödien sind. Der Anteil der Actionfilme ist ebenfalls fast ein Viertel. Dagegen sind nur 0.5 Prozent der Filme im Datensatz Thriller.
Mit Hilfe von group_by
und summarise
können wir die relativen Häufigkeiten errechnen, wenn vorher der Populationsumfang n
gespeichert wurde.
<- dim(tmdb)[1]
n group_by(tmdb, genre) %>%
summarise(f = round(n()/n, 4)) %>%
arrange(desc(f))
# A tibble: 10 × 2
genre f
<fct> <dbl>
1 Drama 0.267
2 Comedy 0.233
3 Action 0.178
4 Adventure 0.0816
5 Horror 0.0682
6 Crime 0.0461
7 Thriller 0.0441
8 Animation 0.0297
9 Fantasy 0.0282
10 Romance 0.0243
Die grafische Darstellung von relativen Häufigkeiten mit ggplot
ist leider etwas komplizierter und sieht etwas unsystematisch aus.
ggplot(tmdb, aes(x=genre)) +
geom_bar(aes(y=after_stat(count/sum(count))))
Die Angabe in geom_bar
besagt, dass die relativen Häufigkeit als Aesthetic in Richtung der y-Achse interpretiert werden sollen. Die Schreibweise after_stat
steht für eine Variable in ggplot
, die intern aus den Daten der Variable genre
berechnet wird. In diesem Fall wird die absolute Häufigkeit count
durch die Summe der absoluten Häufigkeiten dividiert, es handelt sich also um die relativen Häufigkeiten.
Eine alternative Möglichkeit ist der Umweg über die relative Häufigkeitstabelle. Zunächst wird die Häufigkeitstabelle als eigener Dataframe gespeichert.
<- dim(tmdb)[1]
n <- group_by(tmdb, genre) %>%
relTable summarise(f = round(n()/n, 4))
Anschließend wird nicht der Inhalt des Dataframes tmdb
, sondern die Häufigkeitstabelle relTable
grafisch dargestellt. Dabei muss jedoch beachtet werden, dass die rechte Spalte die Häufigkeiten ggplot
durch die Angabe stat="identity"
als Argument der Funktion geom_bar
:
ggplot(relTable, aes(x=genre, y=f)) +
geom_bar(stat="identity")
7.3 Klassierte Daten
Häufigkeiten sind für das Verständnis der Daten nur dann hilfreich, wenn die Originalinformationen ausreichend stark verdichtet werden. Das Beispiel zu den Genres in der Movie-Database ist eine deutliche Verdichtung, denn aus den 4079 Original-Ausprägungen wurde durch die Auszählung der Häufigkeiten eine übersichtliche Tabelle mit nur noch 10 Zeilen (nämlich eine für jedes Genre).
Wenn wir die Verteilung der Variable duration
darstellen wollen, ist eine Häufigkeitsauszählung nicht sinnvoll, weil diese Variable 144 verschiedene Werte annimmt - viele davon nur ein einziges Mal.
Die Information über die Verteilung von Variablen, die viele verschiedene Werte annehmen, lassen sich gut verdichten und grafisch darstellen, indem man Klassen (Intervalle) bildet und dann auszählt, wie viele Werte in jeder Klasse liegen.
Wenn wir insgesamt
Die absoluten Klassenhäufigkeiten sind für cut
. Wenn die Daten in dem Vektor x
gespeichert sind, kann man mit der Funktion
<- cut(x, breaks=J) x_klass
den Vektor der zugehörigen klassierten Werte erzeugen. Dabei gibt breaks
-Option alternativ einen Vektor von Klassengrenzen in die Funktion zu übergeben. Angenommen, der Vektor a
enthält die Klassengrenzen, dann lautet der Aufruf
<- cut(x, breaks=a) x_klass
Wenn einige Werte des Vektors x
außerhalb aller Intervalle liegen, kommt es zu einer Fehlermeldung.
Standardmäßig gehört beim cut
-Befehl die Untergrenze nicht zum Intervall dazu (sondern zum nächsttieferen Intervall). Will man für das unterste Intervall eine Ausnahme machen und include.lowest
erreichen:
cut(x, breaks=a, include.lowest=TRUE)
Die klassierten Daten x_klass
werden in R als Faktor (also als nominal skaliert) behandelt. Sie können ganz normal mit der Funktion table
ausgezählt werden.
Beispiel:
Wir möchten die Länge (in Minuten) der Filme aus “The Movies Database” analysieren. Dazu erstellen wir eine Tabelle mit den absoluten Häufigkeiten. Die Daten werden klassiert, weil es über 140 verschiedene Minutenwerte gibt, die in dem Datensatz tmdb
vorkommen.
Zuerst ziehen wir die Variable duration
aus dem Dataframe heraus und speichern sie in einem Vektor mit dem Namen laenge
ab.
<- tmdb$duration
laenge head(laenge)
[1] 162 169 148 165 132 139
Der erste Film im Datensatz hat also eine Länge von 162 Minuten, der zweite von 169 Minuten usw.
Nun werden die Beobachtungen klassiert. Als Klassengrenzen verwenden wir den Vektor
<- c(10,90,95,100,105,110,115,125,135,340) a
Dieser Vektor enthält die kleinste Duration, die im Datensatz vorkommt (nämlich 14), die Obergrenze des letzten Intervalls ist jedoch größer als die maximale Filmlänge (nämlich größer als 338). Der Vektor der klassierten Beobachtungen wird als laenge_kl
gespeichert. Damit der kleinste Wert dem ersten Intervall zugewiesen wird, setzen wir die Option include.lowest=TRUE
.
<- cut(laenge, breaks=a, include.lowest=TRUE) laenge_kl
Die absoluten Häufigkeiten können nun durch mit table
ausgezählt werden.
table(laenge_kl)
laenge_kl
[10,90] (90,95] (95,100] (100,105] (105,110] (110,115] (115,125] (125,135]
621 482 564 460 427 331 561 294
(135,340]
339
7.4 Histogramme
Die grafische Darstellung der Klassenhäufigkeiten erfolgt in Form von Histogrammen (engl. histograms). Bei einem Histogramm werden die Klassen auf der x-Achse abgetragen. Über jeder Klasse bildet man einen Balken, dessen Fläche proportional zur (absoluten oder relativen) Häufigkeit ist. Die Breite des Balkens
Mit ggplot
ist es sehr einfach Histogramme zu erstellen, z.B.
ggplot(tmdb, aes(duration)) + geom_histogram(bins=40)
Zur Erläuterung: Das erste Argument in der Funktion ggplot
ist wieder der Dataframe, der die Variable enthält, für die wir das Histogramm zeichnen wollen. Das zweite Argument gibt das Aesthetic an, also die Variable, die grafisch dargestellt werden soll, hier ist es die Dauer des Films duration
. Nach dem Pluszeichen folgt das Geom, hier ist es das Histogramm. Als Argument ist die Anzahl der Balken (bins) angeben. In der Abbildung ist auf der y-Achse die absolute Zahl von Filmen in jeder Klasse abgetragen.
Man erkennt an der Abbildung, dass es sehr viele Filme gibt, die etwa 90 bis 100 Minuten dauern. Es gibt in dem Datensatz kaum Filme, die kürzer sind als 75 Minuten oder länger als 200 Minuten.
Als Alternative zur Anzahl der Klassen (bins
) ist es auch möglich einen Vektor von Klassengrenzen als Argument zu übergeben. Das folgende Beispiel zeigt, wie man die Klassengrenzen vorgibt. Leider ist das Vorgehen etwas komplizierter, wenn die Klassengrenzen nicht äquidistant sind, weil zusätzlich zu den Klassengrenzen (breaks
) noch sichergestellt werden muss, dass die Flächeninhalte der Balken proportional zur Klassenbreite sind. Letzteres erfolgt durch das zusätzliche Argument aes(y=after_stat(density))
.
<- c(60,75,80,85,90,95,100,110,130,150,200,230)
a ggplot(tmdb, aes(duration)) +
geom_histogram(breaks=a, aes(y=after_stat(density)))
In dieser Abbildung ist auf der y-Achse die relative Häufigkeit abgetragen, und zwar so skaliert, dass die Fläche der Balken proportional zur relativen Häufigkeit ist. Daraus folgt, dass die Gesamtfläche unter dem Histogramm den Wert 1 annimmt, denn
(Einen knappen Überblick über die Verwendung des Summenzeichens findet man im Anhang C.)
7.5 Kerndichten
Die genaue Form eines Histogramms hängt davon ab, wie man die Klassengrenzen auswählt. Außerdem ändert sich die Höhe der Balken natürlich plötzlich, wenn man in die nächste Klasse wechselt. Man kann eine geglättete Variante des Histogramms definieren, sie wird Kerndichteschätzung (engl. kernel density estimation) genannt. Auf die genaue Definition gehen wir in diesem Kurs nicht ein.
Die Kerndichte kann in ggplot
durch das Geom geom_density
dargestellt werden.
ggplot(tmdb, aes(duration)) +
geom_density()
Dass es sich tatsächlich um ein geglättetes Histogramm handelt, erkennt man gut, wenn beide Darstellungsweise gemeinsam in einer Abbildung zu sehen sind.
ggplot(tmdb, aes(duration)) +
geom_histogram(breaks=a, aes(y=after_stat(density)))+
geom_density()