Tabellen in R: der Datentyp table

Dar Datentyp Tabelle (table) wird verwendet, um Kontingenz-Tabellen zu erzeugen und auszuwerten. Einfachere Anwendungen, um die levels in einem Faktor zu zählen, wurden bereits in den Kapiteln über Faktoren beschrieben.

Einordnung des Artikels

Tabellen werden in R vor allem dazu eingesetzt, um Kontingenz-Tabellen zu erzeugen. Dazu sind Kenntnisse über Faktoren und Dataframes nötig, die hier nicht wiederholt werden, sondern in folgenden Artikeln nachgelesen werden können:

Einführung

Bisher wurden Tabellen (mit Hilfe der Funktion table()) nur dazu eingesetzt, Faktoren übersichtlich auszugeben, siehe Faktoren in R: der Datentyp factor. Genauer bedeutet dies: Erhält die Funktion table() als Eingabewert einen Faktor, so wird eine tabellarische Ausgabe erzeugt, aus der man ablesen kann, mit welchen Häufigkeiten die verschiedenen levels im Faktor enthalten sind. Diese Anwendung von table() wurde bei Faktoren mehrfach verwendet und diskutiert, was hier nicht wiederholt werden soll.

In diesem Kapitel werden Tabellen unter folgenden Aspekten näher betrachtet:

Kontingenz-Tabellen

Wer bereits mit Kontingenz-Tabellen vertraut ist, wird in den folgenden Erklärungen keine neuen Aspekte finden; relevant ist dann lediglich das vorgestellte Beispiel, das weiter unten verwendet wird, um die R-Konzepte rund um den Datentyp table zu erläutern.

Beispiel: Turnier-Tabelle

Im Abschnitt über Faktoren wurde schon mehrmals die folgende Turnier-Tabelle verwendet, die bei einem Turnier nach dem Modus jeder gegen jeden entstehen könnte. In ihr ist in jeder Zeile angegeben:

Sortiert ist die Tabelle nach der Plazierung. Es fehlt natürlich der Name des Spielers.

Plazierung Punkte Verein Altersklasse
1 28 A J
2 27 C S
3 27 G S
4 24 B S
5 23 A S
6 23 B J
7 21 D S
8 18 A J
9 18 F J
10 18 E S
11 17 C J
12 17 D S
13 17 B S
14 16 G J
15 14 B S
16 14 C J
17 13 E J
18 13 D S
19 13 A J
20 11 B S
21 11 G J
22 10 E S
23 9 F S
24 9 F S
25 8 D J
26 8 C S
27 4 F S
28 3 A J
29 1 B S
30 0 G S

Tabelle 1: Die Ergebnisse des Turniers. Für jeden Spieler (also in je einer Zeile) werden Plazierung, erzielte Punktzahl, Vereinszugehörigkeit und Altersklasse aufgeführt.

In der Statistik würde man hier etwa von Rohdaten sprechen, die noch weiter ausgewertet werden können. Im Kapitel über Faktoren wurden dazu einige Fragestellungen erläutert, die mit der Bildung von Klassen zusammenhängen. Eine diese Fragestellungen soll nun näher betrachtet werden: Wie kann man die Tabelle der Rohdaten in eine Kontingenz-Tabelle überführen? Und wie wird man dabei von R unterstützt?

Überführung in eine Kontingenz-Tabelle

In der Turnier-Tabelle oben ist schwer zu erkennen, ob alle Vereine etwa einen gleichen Prozentsatz an Junioren zum Turnier geschickt haben oder ob es deutliche Unterschiede gibt. Diese Information muss in der Tabelle enthalten sein, ist aber auf den ersten Blick schwer zugänglich, da sie für diese Fragestellung falsch angeordnet ist.

Die Fragestellung untersucht die beiden Kriterien:

Somit gibt es insgesamt 7*2 = 14 mögliche Kombinationen (A-J, B-J,..., F-S, G-S), deren Häufigkeiten aus der Tabelle extrahiert werden können. Man kann nun diese 14 Häufigkeiten in einer 2 × 7-Tabelle (oder 7 × 2-Tabelle) darstellen; diese Tabelle wird Kontingenz-Tabelle genannt, was ausdrücken soll, dass sie den Zusammenhang der beiden dargestellten Merkmale beschreibt.

A B C D E F G
J 4 1 2 1 1 1 2
S 1 5 2 3 2 3 2

Tabelle 2: Aus der Tabelle 1 der Turnier-Ergebnisse wird die Kontingenz-Tabelle für Vereinszugehörigkeit und Altersklasse gebildet. Dazu müssen in Tabelle 1 nur die Häufigkeiten abgezählt werden, wie oft Ereignisse der Art Vereinszugehörigkeit zu A und zugleich Altersklasse J vorkommen.

Abbildung 1: Graphische Darstellung der Kontingenz-Tabelle 2 (hier ist die Vereinszugehörigkeit gegen die Altersklasse aufgetragen).Abbildung 1: Graphische Darstellung der Kontingenz-Tabelle 2 (hier ist die Vereinszugehörigkeit gegen die Altersklasse aufgetragen).

Abbildung 2: Nochmals die graphische Darstellung der Kontingenz-Tabelle 2, mit dem Unterschied, dass hier die Altersklasse gegen die Vereinszugehörigkeit aufgetragen ist.Abbildung 2: Nochmals die graphische Darstellung der Kontingenz-Tabelle 2, mit dem Unterschied, dass hier die Altersklasse gegen die Vereinszugehörigkeit aufgetragen ist.

Tabelle 2 wird noch aussagekräftiger, wenn man jeweils die Zeilen- und Spaltensummen angibt; sie werden in der untersten Zeile beziehungsweise letzten Spalte angefügt. Da sie "am Rand" der Tabelle stehen, werden sie als Randverteilungen bezeichnet.

A B C D E F G Summe
J 4 1 2 1 1 1 2 12
S 1 5 2 3 2 3 2 18
Summe 5 6 4 4 3 4 4 30

Tabelle 3: Die Tabelle 2 wird um die Randverteilungen erweitert, also um die jeweiligen Zeilen- und Spaltensummen.

Diese Tabelle wird häufig mit relativen Häufigkeiten dargestellt:

A B C D E F G Summe
J 0.133 0.0333 0.0667 0.0333 0.0333 0.0333 0.0667 0.4
S 0.0333 0.167 0.0667 0.1 0.0667 0.1 0.0667 0.6
Summe 0.167 0.2 0.133 0.133 0.1 0.133 0.133 1

Tabelle 4: Die absoluten Häufigkeiten aus Tabelle 3 werden in relative Häufigkeiten umgerechnet (Division durch die Stichprobenlänge 30).

Der Vorteil ist offensichtlich: In der Wahrscheinlichkeitsrechnung würde man – falls man dafür ein geeignetes Modell zur Verfügung hat – stets die Wahrscheinlichkeiten für Ereignisse in einer Tabelle darstellen und niemals die zu erwartenden absoluten Häufigkeiten bei einer gewissen Stichprobenlänge.

Hier wären im Inneren der Tabelle die Wahrscheinlichkeiten für Ereignisse der Art:

Ein Spieler gehört einem Verein X an und ist zugleich in der Altersklasse Y.

An den Rändern der Tabelle sind dann die entsprechenden Randverteilungen zu sehen, also Wahrscheinlichkeiten für Ereignisse:

Ein Spieler gehört einem Verein X an

beziehungsweise

Ein Spieler gehört der Altersklasse Y an.

Der Nachteil dieser Darstellung der relativen Häufigkeiten liegt auch auf der Hand: In der Tabelle der absoluten Häufigkeiten ist die Länge der Stichprobe noch zu erkennen; die Tabelle der relativen Häufigkeiten ist diese nicht mehr zu erkennen und sie suggeriert durch ihre Verwandtschaft mit den Wahrscheinlichkeiten eine höhere Genauigkeit.

Aufgabe: Diskutieren Sie:

  1. Welche Informationen aus den Tabellen 2, 3, 4 sind in Abbildung 1 und 2 zu erkennen?
  2. Welche Informationen können nicht aus den Abbildungen rekonstruiert werden?
  3. Sind die Abbildungen 1 und 2 gleichwertig oder enthalten sie unterschiedliche Informationen?

Ausblick: Test auf statistische Unabhängigkeit

Eine typische Fragestellung, die sich durch die oben gezeigte Kontingenz-Tabelle aufdrängt, lautet:

Sind die beiden Merkmale Vereinszugehörigkeit und Altersklasse unabhängig voneinander oder nicht?

Man kann sich leicht folgende Grenzfälle vorstellen:

  1. Es gibt Vereine, in denen die Verteilung innerhalb der Altersklassen deutlich von der über alle Vereine gemittelten Verteilung abweicht (im Mittel sind 12 von 30 Spielern Junioren, bei den Vereinen A und B ist man davon weit entfernt).
  2. Es gibt Vereine, deren Altersverteilung in etwa dem Durchschnitt entspricht (C, D, E und G erfüllen dies).

Überwiegt der erste Grenzfall, so kann man etwa von der Altersklasse eines Spielers mit hoher Wahrscheinlichkeit auf eine Gruppe von Vereinen schließen, von denen er einem angehört. Man würde in diesem Fall die beiden Merkmale Vereinszugehörigkeit und Altersklasse als statistisch abhängig voneinander bezeichnen.

Überwiegt dagegen der zweite Grenzfall, so hilft die Zusatzinformation über die Altersklasse eines Spielers nicht, um auf seine Vereinszugehörigkeit zu schließen. Jetzt sind die beiden Merkmale statistisch unabhängig voneinander.

In der Statistik wird ein Test entwickelt, der eine Kontingenz-Tabelle wie oben auswertet; genauer, wie man testen kann, ob die beiden dargestellten Merkmale statistisch unabhängig voneinander sind. Es ist nicht schwer, die Idee hinter diesem Test zu verstehen, seine exakte Beschreibung und Begründung würde aber zu weit führen.

Im Fall der statistischen Unabhängigkeit der beiden Merkmale Vereinszugehörigkeit und Altersklasse müssten die relativen Häufigkeiten eines Verbund-Ereignisses mit dem Produkt der relativen Häufigkeiten der entsprechenden Randverteilungen übereinstimmen:

P(Vereinszugehörigkeit zu A und zugleich Altersklasse J) = P(Vereinszugehörigkeit zu A) · P(Altersklasse J)

Und dies müsste für alle 14 Verbund-Ereignisse gelten, die in Tabelle 4 dargestellt sind.

Dass diese Bedingung hier nicht erfüllt ist, sieht man sofort, indem man ein derartiges Produkt nachrechnet – man sieht sogar, dass es für keine der 14 möglichen Verbund-Ereignisse stimmt.

Um diesen Vergleich leichter zu machen, wird im Folgenden die Tabelle aufgeführt wie sie bei voller statistischer Unabhängigkeit aussehen müsste (Tabelle 5). Anschließend wird nochmals die Tabelle 4 mit den aus dem Turnier-Ergebnis abgezählten tatsächlichen relativen Häufigkeiten dargestellt (Tabelle 6).

A B C D E F G Summe
J 0.0667 0.08 0.0533 0.0533 0.04 0.0533 0.0533 0.4
S 0.1 0.12 0.08 0.08 0.06 0.08 0.08 0.6
Summe 0.167 0.2 0.133 0.133 0.1 0.133 0.133 1

Tabelle 5: Bei statistischer Unabhängigkeit der beiden dargestellten Merkmale und vorausgesetzter Richtigkeit der Randverteilungen müssten die relativen Häufigkeiten der Verbund-Ereignisse wie hier dargestellt lauten.

A B C D E F G Summe
J 0.133 0.0333 0.0667 0.0333 0.0333 0.0333 0.0667 0.4
S 0.0333 0.167 0.0667 0.1 0.0667 0.1 0.0667 0.6
Summe 0.167 0.2 0.133 0.133 0.1 0.133 0.133 1

Tabelle 6: Zum besseren Vergleich mit Tabelle 5 wird hier nochmals Tabelle 4 dargestellt (Kontingenz-Tabelle aus dem Turnier-Ergebnis ermittelt).

Die Idee zum Test der Unabhängigkeit ist jetzt einfach: Man bildet für alle 14 Verbund-Ereignisse die quadrierte Differenz der Wahrscheinlichkeiten aus Tabelle 5 und 6 und summiert sie auf. Das Ergebnis wird χ² (Chi-Quadrat) genannt.

Ist χ² gleich null oder sehr nahe daran, können die beiden Merkmale als statistisch unabhängig voneinander bezeichnet werden. Übersteigt χ² eine gewisse Schranke, besteht eine statistische Abhängigkeit.

Es sollte auch klar sein, dass man mit diesem Test nur die statistische Unabhängigkeit testen kann: Da eine statistische Abhängigkeit einen beliebig starken Grad haben kann, ist jedes Stichproben-Resultat mit einer (eventuell sehr kleinen) statistischen Abhängigkeit verträglich.

Der schwierige Teil der Theorie zum χ²-Test besteht jetzt darin, herzuleiten wie unter der Annahme, dass die Merkmale statistisch unabhängig voneinander sind, die Größe χ² verteilt ist. Klar ist nur, dass sie mit hoher Wahrscheinlichkeit sehr klein und mit kleiner Wahrscheinlichkeit sehr groß ist – aber wie lautet die exakte Verteilung? Nur wenn man diese kennt, kann man Testergebisse der Art formulieren: Mit einer Fehler-Wahrscheinlichkeit von weniger als 10 Prozent sind die Merkmale statistisch unabhängig voneinander.

Erzeugen von Tabellen

Es gibt zwei Möglichkeiten eine Tabelle zu erzeugen, die im Folgenden besprochen werden:

  1. Die Funktion table(), die als Eingabewerte beliebig viele Faktoren erhält.
  2. Die Funktion as.table(), die ein geeignetes Objekt in eine Tabelle verwandelt.

Die Funktion table()

Die Funktion table() kann als Eingabewerte beliebig viele Objekte aufnehmen, die sich als Faktoren interpretieren lassen – der entsprechende Eingabewert ist ... . In den folgenden Anwendungen werden zunächst zwei Faktoren eingegeben, um das Erzeugen und Auswerten einer Kontingenz-Tabelle zu diskutieren. Erst wenn dies abgeschlossen ist, wird kurz darauf eingegangen, welche Änderungen zu beachten sind, wenn man mehrere Faktoren an table() übergibt.

Die Turnier-Tabelle aus Tabelle 1 oben, die das Ergebnis des Turniers vollständig beschreibt, wird zunächst als Dataframe namens result erzeugt (siehe auch Faktoren in R: Anwendungen):

score <- c(28, 27, 27, 24, 23, 23, 21, 18, 18, 18, 17 , 17, 17, 16, 14, 14, 13, 13, 13, 11, 11, 10, 9, 9, 8, 8, 4, 3, 1, 0)
club <- c("A", "C", "G", "B", "A", "B", "D", "A", "F", "E", "C", "D", "B", "G", "B", "C", "E", "D", "A", "B", "G", "E", "F", "F", "D", "C", "F", "A", "B", "G")
age <- c("J", "S", "S", "S", "S", "J", "S", "J", "J", "S", "J", "S", "S", "J", "S", "J", "J", "S", "J", "S", "J", "S", "S", "S", "J", "S", "S", "J", "S", "S")

length(score)           # 30
length(club)            # 30
length(age)             # 30
sum(score)              # 435 = 15*29 = 29 + 28 + ... + 1

result <- data.frame(score, club, age)

str(result)
# 'data.frame': 30 obs. of  3 variables:
#   $ score: num  28 27 27 24 23 23 21 18 18 18 ...
# $ club : Factor w/ 7 levels "A","B","C","D",..: 1 3 7 2 1 2 4 1 6 5 ...
# $ age  : Factor w/ 2 levels "J","S": 1 2 2 2 2 1 2 1 1 2 ...

Daraus soll nun die Kontingenz-Tabelle aus Tabelle 2 oben erzeugt werden, die den Zusammenhang zwischen Vereinszugehörigkeit und Altersklasse herstellt. Dazu werden zunächst die beiden Faktoren f.club und f.age gebildet.

Dazu ist folgende Eigenschaft eines Dataframes zu beachten: Die beiden Spalten club und age des Dataframes result sind character-Vektoren und werden daher beim Extrahieren aus dem Dataframe automatisch in Faktoren verwandelt. Daher enthält das folgende Skript keinen ausdrücklichen Befehl, um Faktoren zu erzeugen.

f.club <- result[ , "club"]
f.club
# [1] A C G B A B D A F E C D B G B C E D A B G E F F D C F A B G
# Levels: A B C D E F G

f.age <- result[ , "age"]
f.age
# [1] J S S S S J S J J S J S S J S J J S J S J S S S J S S J S S
# Levels: J S

Die beiden Faktoren werden jetzt an die Funktion table() übergeben; an den Ausgaben erkennt man, welche Attribute von den Faktoren auf die Tabelle übertragen werden und dass die Bezeichnung der levels weitergegeben wird.

t.age.club <- table(f.age, f.club)

t.age.club
#     f.club
# f.age A B C D E F G
# J     4 1 2 1 1 1 2
# S     1 5 2 3 2 3 2

str(t.age.club)
# 'table' int [1:2, 1:7] 4 1 1 5 2 2 1 3 1 2 ...
# - attr(*, "dimnames")=List of 2
# ..$ f.age : chr [1:2] "J" "S"
# ..$ f.club: chr [1:7] "A" "B" "C" "D" ...

Hätte man die Reihenfolge der Faktoren in table() vertauscht, wird die transponierte Tabelle erzeugt.

Die Funktion as.table()

Die oben gezeigte Funktion table() wird verwendet, wenn man den üblichen Weg einer statistischen Auswertung beschreitet: Aus den Rohdaten werden Faktoren gebildet und diese zueinander in Beziehung gesetzt, wobei eine Kontingenz-Tabelle entsteht. Diese Kontingenz-Tabelle besitzt zahlreiche Eigenschaften einer Matrix.

Ist die Kontingenz-Tabelle umgekehrt bereits als Matrix gegeben, so kann man mit Hilfe der Funktion as.table() die Matrix in eine Tabelle umwandeln. Im folgenden Skript wird zunächst die Matrix m erzeugt, die der Kontingenz-Tabelle t.age.club oben entspricht und daraus wird eine Tabelle erzeugt:

m <- matrix(data = c(4, 1, 2, 1, 1, 1, 2, 1, 5, 2, 3, 2, 3, 2), nrow = 2, byrow = TRUE)
m

t <- as.table(m)
t
#  A B C D E F G
# A 4 1 2 1 1 1 2
# B 1 5 2 3 2 3 2

str(t)
# 'table' num [1:2, 1:7] 4 1 1 5 2 2 1 3 1 2 ...
# - attr(*, "dimnames")=List of 2
# ..$ : chr [1:2] "A" "B"
# ..$ : chr [1:7] "A" "B" "C" "D" ...

An den Ausgaben erkennt man, dass für die levels der Faktoren default-Werte gesetzt werden und dass man jetzt selbst verantwortlich dafür ist, geeignete Namen für die Dimensionen zu setzen (dafür wurden oben die Namen der zugunde liegenden Faktoren f.age und f.club verwendet).

Der Zusammenhang zwischen table und Dataframe

Erzeugen einer Tabelle aus einem Dataframe

Im letzten Unterabschnitt wurde gezeigt, wie mit der Funktion as.table() Matrizen in Tabellen verwandelt werden. Da Dataframes und Matrizen eng miteinander verwandt sind, stellt sich sofort die Frage: lassen sich auch Dataframes in Tabellen verwandeln?

Und da oben zum Erzeugen der Tabelle t.age.club von einem Dataframe der Rohdaten result ausgegangen wurde, dessen Spalten age und club die Observablen bildeten, die in der Kontingenz-Tabelle in Beziehung gesetzt wurden, ist es naheliegend zu fragen: kann man dies nicht abkürzen und die Tabelle sofort aus dem Dataframe result erzeugen?

Das folgende Skript zeigt, wie dazu die Funktion table() verwendet werden kann; dies ist deshalb möglich, da die Spalten eines Dataframes als Faktoren interpretiert werden können, so dass der Umweg über die Faktoren (beziehungsweise das Extrahieren der Spalten) nicht nötig ist.

# Dataframe result wie oben
t.a.c <- table(result[c(3, 2)])

t.a.c
#    club
# age A B C D E F G
# J 4 1 2 1 1 1 2
# S 1 5 2 3 2 3 2

str(t.a.c)
# 'table' int [1:2, 1:7] 4 1 1 5 2 2 1 3 1 2 ...
# - attr(*, "dimnames")=List of 2
# ..$ age : chr [1:2] "J" "S"
# ..$ club: chr [1:7] "A" "B" "C" "D" ...

Zeile 2: Aus dem Dataframe result wird ein Teil-Dataframe bestehend aus der zweiten und dritten Spalte gebildet (die Reihenfolge wird wie oben gewählt).

Zeilen 4 bis 14: Die Ausgaben zeigen, dass die identische Tabelle wie im Skript oben entsteht.

Wiederherstellen des Dataframes aus der Kontingenz-Tabelle

In einem gewissen Sinn lässt sich das Dataframe der Rohdaten sogar wieder aus der Kontingenz-Tabelle rekonstruieren. Dazu geht man im folgenden Skript von der Kontingenz-Tabelle t.a.c aus, die zuletzt gebildet wurde. Anschließend wird diese Tabelle in ein Dataframe df.a.c umgewandelt; dazu wird die Funktion as.data.frame() verwendet.

# t.a.c wie oben

df.a.c <- as.data.frame(t.a.c)
df.a.c
#    age club Freq
# 1    J    A    4
# 2    S    A    1
# 3    J    B    1
# 4    S    B    5
# 5    J    C    2
# 6    S    C    2
# 7    J    D    1
# 8    S    D    3
# 9    J    E    1
# 10   S    E    2
# 11   J    F    1
# 12   S    F    3
# 13   J    G    2
# 14   S    G    2

str(df.a.c)
# 'data.frame': 14 obs. of  3 variables:
#   $ age : Factor w/ 2 levels "J","S": 1 2 1 2 1 2 1 2 1 2 ...
# $ club: Factor w/ 7 levels "A","B","C","D",..: 1 1 2 2 3 3 4 4 5 5 ...
# $ Freq: int  4 1 1 5 2 2 1 3 1 2 ...

An den Ausgaben erkennt man:

  1. Das Dataframe besteht aus drei Spalten namens age, club und Freq (für Frequency), siehe Zeile 5.
  2. Die 14 Zeilen des Dataframes entsprechen genau den 14 Kombinationen von Altersklasse und Vereinszugehörigkeit, die in der Kontingenz-Tabelle enthalten waren (Zeile 6 bis 19).
  3. Die Spalte Freq gibt an, wie oft die jeweilige Kombination in der Kontingenz-Tabelle vorkommt.

Um "echte" Rohdaten zur gegebenen Kontingenz-Tabelle zu erhalten, muss man das Dataframe nachbearbeiten: Zeilen mit Freq > 1 müssen so oft wiederholt werden, wie es das tatsächliche Freq angibt. Das Teil-Dataframe aus den Spalten ohne Freq kann man dann als die Rohdaten zur Kontingenz-Tabelle interpretieren.

Es stellt sich die Frage, wie die Funktion as.data.frame() aus einer Tabelle ein Dataframe erzeugen kann. Der Grund ist einfach: Die Funktion as.data.frame(x) ist generisch implementiert, das heißt die Implementierung hängt von der Klasse von x ab – für eine Matrix x ist die Funktion völlig anders implementiert als für eine Tabelle. Streng genommen wird also die Funktion as.data.frame.table() aufgerufen. Man muss diesen Aufruf aber nicht selbst tätigen, da mit Hilfe der Klasse des Objektes x die richtige Implementierung gewählt wird.

Auswertung einer Kontingenz-Tabelle

Randverteilungen

Berechnung der Randverteilungen

In der Einführung wurde zur vollständigen Turnier-Tabelle (Tabelle 1) die zugehörige Kontingenz-Tabelle erzeugt (Tabelle 2); sie enthält immer noch absolute Häufigkeiten. In Tabelle 3 wurden dann zusätzlich die Randverteilungen eingetragen – und zwar wieder als absolute Häufigkeiten.

In R erfolgt die Berechnung dieser Randverteilungen mit Hilfe der Funktion margin.table(x, margin = NULL) , die zwei Eingabewerte besitzt:

  1. Die Kontingenz-Tabelle x.
  2. Die Angabe margin, die festlegt, ob die Zeilensummen (mit margin = 1 ) oder die Spaltensummen (mit margin = 2 ) berechnet werden sollen.

Das folgende Skript berechnet beide Randverteilungen und untersucht das Ergebnis mit der Funktion str():

# Kontingenz-Tabelle t.age.club wie oben
t.age.club
#       f.club
# f.age A B C D E F G
# J     4 1 2 1 1 1 2
# S     1 5 2 3 2 3 2

t.age.club.marg1 <- margin.table(x = t.age.club, margin = 1)
t.age.club.marg1
# f.age
# J  S 
# 12 18 

str(t.age.club.marg1)
# 'table' int [1:2(1d)] 12 18
# - attr(*, "dimnames")=List of 1
# ..$ f.age: chr [1:2] "J" "S"

t.age.club.marg2 <- margin.table(x = t.age.club, margin = 2)
t.age.club.marg2
# f.club
# A B C D E F G 
# 5 6 4 4 3 4 4 

str(t.age.club.marg2)
# 'table' int [1:7(1d)] 5 6 4 4 3 4 4
# - attr(*, "dimnames")=List of 1
# ..$ f.club: chr [1:7] "A" "B" "C" "D" ...

Durch einen Vergleich mit Tabelle 2 und 3 sollte sich das Skript selbst erklären.

Aufgabe: Falls Sie bereits mit der Funktion apply() vertraut sind: Wie kann man die Berechnung der Randverteilungen mit apply() realisieren?

Hinzufügen der Randverteilungen zu einer Kontingenz-Tabelle

Die Ausgaben aus dem letzten Skript haben gezeigt: Werden die Randverteilungen mit margin.table() berechnet, wird eine neue Tabelle gebildet, die nur die Randverteilung enthält. Möchte man eine Darstellung der ursprünglichen Kontingenz-Tabelle zusammen mit den Randverteilungen erzeugen (wie in Tabelle 3 oben), muss man sie geeignet zusammenfügen.

Da dieses Zusammenfügen sehr umständlich ist, gibt es dafür eine eigene Funktion, nämlich addmargins(). Das folgende Skript zeigt ihr default-Verhalten:

t.age.club
#     f.club
# f.age A B C D E F G
# J     4 1 2 1 1 1 2
# S     1 5 2 3 2 3 2

dim(t.age.club)
# [1] 2 7

t.age.club.margins <- addmargins(A = t.age.club)

t.age.club.margins
#      f.club
# f.age  A  B  C  D  E  F  G Sum
# J      4  1  2  1  1  1  2  12
# S      1  5  2  3  2  3  2  18
# Sum    5  6  4  4  3  4  4  30

str(t.age.club.margins)
# 'table' num [1:3, 1:8] 4 1 5 1 5 6 2 2 4 1 ...
# - attr(*, "dimnames")=List of 2
# ..$ f.age : chr [1:3] "J" "S" "Sum"
# ..$ f.club: chr [1:8] "A" "B" "C" "D" ...

dim(t.age.club.margins)
# [1] 3 8

Zeile 1 bis 5: Zur Erinnerung die ursprüngliche Kontingenz-Tabelle (siehe Tabelle 2 oben).

Zeile 7 und 8: Als Matrix interpretiert hat die Kontingenz-Tabelle 2 Zeilen und 7 Spalten.

Zeile 10: Die Funktion addmargins() wird auf die Kontingenz-Tabelle angewendet; es werden keine weiteren Argumente gesetzt. Das Ergebnis wird in t.age.club.margins abgespeichert.

Zeile 12: Die Ausgabe von t.age.club.margins zeigt die Tabelle 3 oben. Dazu wurde eine weitere Zeile und eine weitere Spalte – jeweils mit dem Namen Sum – hinzugefügt, in der die Zeilen- beziehungsweise Spaltensummen eingetragen sind.

Zeile 19 bis 26: Die Ausgabe der Struktur und des Dimensions-Vektors zeigen dies ausdrücklich.

Die Funktion addmargins() besitzt weitere Eingabewerte, deren Bedeutung kurz erklärt werden soll:

addmargins(A, margin = seq_along(dim(A)), FUN = sum, quiet = FALSE)
  1. Das Argument A steht natürlich für die Kontingenz-Tabelle, die auch mehr als zwei Dimensionen besitzen kann (so wie ein Feld mehr Dimensionen haben kann als eine Matrix).
  2. Mit margin wird angegeben, für welche Dimensionen die Randverteilungen berechnet werden sollen. Da im Beispiel oben die Kontingenz-Tabelle zwei-dimensional war, wurde (per default) margin = c(1, 2) gesetzt.
  3. Die Funktion FUN gibt an, welche Funktion zur Berechnung der zusätzlichen Einträge in der Tabelle verwendet werden soll. Per default wird die Summe gebildet (wie oben, wo die Zeilen- und Spaltensummen berechnet wurden).
  4. Mit quiet kann man einen logischen Wert setzen, der angibt, ob die Reihenfolge ausgegeben wird, in der die Berechnung der neuen Tabellen-Einträge erfolgt.

Das folgende Skript zeigt die Anwendung von addmargins() mit FUN = max , es wird also jeweils das Maximum der Zeilen beziehungsweise Spalten gebildet:

# t.age.club wie oben

t.age.club.max <- addmargins(A = t.age.club, FUN = max, quiet = FALSE)
# Margins computed over dimensions
# in the following order:
# 1: f.age
# 2: f.club

t.age.club.max
#     f.club
# f.age A B C D E F G max
# J   4 1 2 1 1 1 2   4
# S   1 5 2 3 2 3 2   5
# max 4 5 2 3 2 3 2   5

Übergang von absoluten zu relativen Häufigkeiten

In der Einführung wurden in Tabelle 4 anstelle der absoluten Häufigkeiten die relativen Häufigkeiten in die Kontingenz-Tabelle eingetragen. Damit wird eigentlich nur die Normierung neu festlegt: Die Summe aller Tabellen-Einträge ergibt jetzt 1 und nicht mehr 30 wie in Tabelle 2 (dabei war 30 die Anzahl der Turnier-Teilnehmer).

Im Skript unten wird zunächst Tabelle 2 ausgegeben (Zeile 3). Anschließend werden mit addmargins() die Randverteilungen hinzugefügt; es entsteht Tabelle 3 (siehe Zeile 9), die immer noch absolute Häufigkeiten enthält.

Das Turnier hat 30 Teilnehmer; daher erhält man die relativen Häufigkeiten, indem man die Anzahlen in der Tabelle t.age.club durch 30 teilt (Zeile 16). Diese Tabelle wird in Zeile 18 ausgegeben; fügt man wieder die Randverteilungen hinzu, entsteht Tabelle 4 (siehe Zeile 24).

# t.age.club wie oben

t.age.club
#      f.club
# f.age A B C D E F G
#     J 4 1 2 1 1 1 2
#     S 1 5 2 3 2 3 2

addmargins(t.age.club)
#      f.club
# f.age  A  B  C  D  E  F  G Sum
#   J    4  1  2  1  1  1  2  12
#   S    1  5  2  3  2  3  2  18
#   Sum  5  6  4  4  3  4  4  30

t.age.club.prob <- t.age.club / 30

print(t.age.club.prob, digits = 2)
#      f.club
# f.age     A     B     C     D     E     F     G
#     J 0.133 0.033 0.067 0.033 0.033 0.033 0.067
#     S 0.033 0.167 0.067 0.100 0.067 0.100 0.067

print(addmargins(t.age.club.prob), digits = 2)
#      f.club
# f.age     A     B     C     D     E     F     G   Sum
#    J   0.133 0.033 0.067 0.033 0.033 0.033 0.067 0.400
#    S   0.033 0.167 0.067 0.100 0.067 0.100 0.067 0.600
#    Sum 0.167 0.200 0.133 0.133 0.100 0.133 0.133 1.000

Man darf diese Berechnung der Wahrscheinlichkeiten nicht verwechseln mit der Funktion prop.table(x, margin = NULL) , die zwei Eingabewerte besitzt:

Das folgende Skript zeigt den Einsatz von margin = 1 (Zeile 3); zum besseren Verständnis werden anschließend die Randverteilungen hinzugefügt (Zeile 9).

# t.age.club wie oben

print(prop.table(t.age.club, margin = 1), digits = 3)
#      f.club
# f.age      A      B      C      D      E      F      G
#     J 0.3333 0.0833 0.1667 0.0833 0.0833 0.0833 0.1667
#     S 0.0556 0.2778 0.1111 0.1667 0.1111 0.1667 0.1111

print(addmargins(prop.table(t.age.club, margin = 1)), digits = 3)
#      f.club
# f.age      A      B      C      D      E      F      G    Sum
#    J   0.3333 0.0833 0.1667 0.0833 0.0833 0.0833 0.1667 1.0000
#    S   0.0556 0.2778 0.1111 0.1667 0.1111 0.1667 0.1111 1.0000
#    Sum 0.3889 0.3611 0.2778 0.2500 0.1944 0.2500 0.2778 2.0000

Man erkennt, dass die Zahlenwerte in der Tabelle so normiert werden, dass die Zeilensummen jeweils 1 ergeben.

Mit margin = 2 werden dann die Spaltensummen gleich 1 (siehe folgendes Skript).

print(prop.table(t.age.club, margin = 2), digits = 3)
#      f.club
# f.age     A     B     C     D     E     F     G
#     J 0.800 0.167 0.500 0.250 0.333 0.250 0.500
#     S 0.200 0.833 0.500 0.750 0.667 0.750 0.500

print(addmargins(prop.table(t.age.club, margin = 2)), digits = 3)
#      f.club
# f.age     A     B     C     D     E     F     G   Sum
#    J   0.800 0.167 0.500 0.250 0.333 0.250 0.500 2.800
#    S   0.200 0.833 0.500 0.750 0.667 0.750 0.500 4.200
#    Sum 1.000 1.000 1.000 1.000 1.000 1.000 1.000 7.000

Man beachte, dass man die mit prop.table() berechneten Wahrscheinlichkeiten (genauer: es handelt sich immer noch um relative Häufigkeiten) nicht als Verbund-Wahrscheinlichkeiten interpretieren kann.

Diagnose-Funktionen für Tabellen

Die Diagnose-Funktionen wurden bereits für zahlreiche Datentypen erklärt – eine ausführliche Erklärung sollte hier nicht mehr nötig sein; das folgende Skript zeigt die wichtigsten Vertreter für Tabellen wieder am Beispiel der Tabelle t.age.club:

  1. Die Abfrage, ob eine Tabelle vorliegt mit is.table().
  2. Die Ausgabe mit print().
  3. Die Struktur einer Tabelle mit str().
  4. Die Abfrage der Attribute einer Tabelle mit attributes().
  5. Die Funktion summary().
  6. Die Abfrage der Klasse einer Tabelle mit class().
# t.age.club wie oben

#      1. is.table()

is.table(t.age.club)
# [1] TRUE

#     2. print()

t.age.club
#      f.club
# f.age A B C D E F G
#     J 4 1 2 1 1 1 2
#     S 1 5 2 3 2 3 2

#     3. str()

str(t.age.club)
# 'table' int [1:2, 1:7] 4 1 1 5 2 2 1 3 1 2 ...
# - attr(*, "dimnames")=List of 2
# ..$ f.age : chr [1:2] "J" "S"
# ..$ f.club: chr [1:7] "A" "B" "C" "D" ...

#     4. attributes()

attributes(t.age.club)
# $dim
# [1] 2 7
# 
# $dimnames
# $dimnames$f.age
# [1] "J" "S"
# 
# $dimnames$f.club
# [1] "A" "B" "C" "D" "E" "F" "G"
# 
# 
# $class
# [1] "table"

#     5. summary()

summary(t.age.club)
# Number of cases in table: 30 
# Number of factors: 2 
# Test for independence of all factors:
#   Chisq = 5.833, df = 6, p-value = 0.4421
# Chi-squared approximation may be incorrect

#     6. class()

class(t.age.club)
# [1] "table"

Graphiken für Tabellen

Die Funktion plot() für Tabellen

Kontingenz-Tabellen sind zwar wichtig für eine statistische Auswertung, um einen schnellen Überblick über die Daten zu gewinnen, wird man aber eine geeignete graphische Darstellung gegenüber der Zahlenwerten bevorzugen. Man betrachte dazu nochmals Tabelle 2 und 4 sowie die Abbildungen 1 und 2 und versuche mit ihrer Hilfe möglichst schnell die Frage zu beantworten:

"Sind die Vereinszugehörigkeit und die Zugehörigkeit zu einer Altersklasse unabhängig voneinander?"

In den Basis-Paketen von R sind natürlich die Funktionen zur graphischen Darstellung einer Kontingenz-Tabelle enthalten. Die Abbildungen 1 und 2 wurden mit Hilfe der Funktion plot.table() erstellt. Da die Funktion plot() generisch implementiert ist, wird an der Klasse des Eingabewertes x erkannt, welche Implementierung aufgerufen werden muss; die explizite Angabe von plot.table() ist nicht nötig.

# Abbildung 1:
plot( t.age.club, col = "blue", xlab = "Altersklasse", ylab = "Verein", main = "Verein vs. Alter" )

# Abbildung 2:
plot( t(t.age.club), col = "blue", ylab = "Altersklasse", xlab = "Verein", main = "Alter vs. Verein" )

Indem die transponierte Tabelle mit Hilfe von t() gebildet wird, kann man die Achsen der Darstellung vertauschen (Zeile 5); entsprechend muss man die Beschriftungen anpassen.

Die Graphiken werden aussagekräftiger, wenn man die Klassen mit unterschiedlichen Farben darstellt; die einfachste Lösung dafür ist, mit Hilfe von rainbow() die Regenbogenfarben zu setzen. Das folgende Skript zeigt nochmals die Befehle zum Erzeugen der Graphiken, einziger Unterschied ist der Eingabewert col ; die Abbildungen sind darunter zu sehen.

# Abbildung 3
plot( t.age.club, col = rainbow(7), xlab = "Altersklasse", ylab = "Verein", main = "Verein vs. Alter" )

# Abbildung 4
plot( t(t.age.club), col = rainbow(2), ylab = "Altersklasse", xlab = "Verein", main = "Alter vs. Verein" )

Abbildung 3: Graphische Darstellung der Kontingenz-Tabelle mit plot.table() wie in Abbildung 1, aber mit Regenbogenfarben für die unterschiedlichen Vereine.Abbildung 3: Graphische Darstellung der Kontingenz-Tabelle mit plot.table() wie in Abbildung 1, aber mit Regenbogenfarben für die unterschiedlichen Vereine.

Abbildung 4: Graphische Darstellung der Kontingenz-Tabelle mit plot.table() wie in Abbildung 2, aber mit Regenbogenfarben für die unterschiedlichen Altersklassen.Abbildung 4: Graphische Darstellung der Kontingenz-Tabelle mit plot.table() wie in Abbildung 2, aber mit Regenbogenfarben für die unterschiedlichen Altersklassen.

Die Funktion barplot()

Leichter zu interpretieren als die Darstellung der Kontingenz-Tabellen mit Hilfe von plot() sind vermutlich Histogramme (oder Säulen-Diagramme). Zunächst wird die absolute Häufigkeit der Vereinszugehörigkeit im Turnier dargestellt, siehe Abbildung 5.

Dazu wird die Funktion barplot() mit height = table(club) konfiguriert, das heißt dass aus dem Vektor club, der die Vereinszugehörigkeit aller Turnier-Teilnehmer beschreibt, eine Tabelle gebildet wird; sie gibt die absoluten Häufigkeiten der vertretenen Vereine an, die auf der y-Achse aufgetragen wird. Entlang der x-Achse wird für jeden Verein eine Säule gezeichnet. Als Farben werden hier heat.colors eingesetzt (die Farben von rot bis gelb).

barplot( height = table(club), col = heat.colors(7), beside = TRUE,
         main = "Vereinszugehörigkeit" )

Abbildung 5: Graphische Darstellung der absoluten Häufigkeit der Vereinszugehörigkeit der Turnier-Teilnehmer mit Hilfe von barplot().Abbildung 5: Graphische Darstellung der absoluten Häufigkeit der Vereinszugehörigkeit der Turnier-Teilnehmer mit Hilfe von barplot().

Die Funktion barplot() kann auch eingesetzt werden, um Daten zu gruppieren. Das folgende Skript zeigt die Anzahl der Turnier-Teilnehmer

Die entsprechenden Abbildungen sind darunter gezeigt (siehe Abbildung 6 und 7). Für das Argument height wird jetzt die entsprechende Kontingenz-Tabelle beziehungsweise die transponierte Kontingenz-Tabelle eingesetzt.

# Kontingenz-Tabelle t.age.club wie oben

# Abbildung 6:
barplot(height = t.age.club, col = heat.colors(2), beside = TRUE, 
        legend = levels(f.age), main = "Altersklasse je Verein",
        args.legend = list(x = "topright", ncol = 2) )

# Abbildung 7:
barplot( height = t(t.age.club), col = heat.colors(7), beside = TRUE )

Abbildung 6: Graphische Darstellung der Kontingenz-Tabelle: die Anzahl der Turnier-Teilnehmer je Altersklasse wird nach Vereinen gruppiert.Abbildung 6: Graphische Darstellung der Kontingenz-Tabelle: die Anzahl der Turnier-Teilnehmer je Altersklasse wird nach Vereinen gruppiert.

Abbildung 7: Graphische Darstellung der Kontingenz-Tabelle: die Anzahl der Turnier-Teilnehmer je Verein wird nach Altersklassen gruppiert.Abbildung 7: Graphische Darstellung der Kontingenz-Tabelle: die Anzahl der Turnier-Teilnehmer je Verein wird nach Altersklassen gruppiert.

Höher-dimensionale Kontingenz-Tabellen

Bisher wurden nur zwei-dimensionale Tabellen untersucht. Ähnlich wie ein Feld (Datentyp array) die mehr-dimensionale Verallgemeinerung einer Matrix ist (Datentyp matrix), kann man auch höherdimensionale Tabellen betrachten. Dafür gibt es aber keinen eigenen Datentyp, sondern der Datentyp table ist bereits so konfiguriert, dass man beliebig viele Dimensionen für die Tabelle vorgeben kann.

Als Beispiel soll hier eine drei-dimensionale Tabelle gezeigt werden, die Verallgemeinerung auf beliebige Dimensionen sollte dann ohne Schwierigkeiten vollzogen werden können – lediglich die Ausgaben werden immer unübersichtlicher.

Dazu gehe man nochmals zu Tabelle 1, der Tabelle der Rohdaten zurück. Bisher wurde immer die Tabelle t.age.club untersucht, die die Beziehung zwischen den Merkmalen Vereinszugehörigkeit und Altersklasse herstellt. Da in den Rohdaten drei Merkmale enthalten sind, kann man auch eine Tabelle definieren, die die Beziehungen dieser drei Merkmale herstellt.

Die Rohdaten sind im Dataframe result abgespeichert, deren Struktur wird nochmals angezeigt (Zeile 3). Anschließend wird das Dataframe mit Hilfe von table() in die Tabelle t.score.club.age verwandelt (Zeile 9).

# Dataframe result wie oben (siehe auch Tabelle 1)

str(result)
# 'data.frame': 30 obs. of  3 variables:
# $ score: num  28 27 27 24 23 23 21 18 18 18 ...
# $ club : Factor w/ 7 levels "A","B","C","D",..: 1 3 7 2 1 2 4 1 6 5 ...
# $ age  : Factor w/ 2 levels "J","S": 1 2 2 2 2 1 2 1 1 2 ...

t.score.club.age <- table(result)

t.score.club.age
# , , age = J
# 
#      club
# score A B C D E F G
#   0  0 0 0 0 0 0 0
#   1  0 0 0 0 0 0 0
#   3  1 0 0 0 0 0 0
#   4  0 0 0 0 0 0 0
#   8  0 0 0 1 0 0 0
#   9  0 0 0 0 0 0 0
#   10 0 0 0 0 0 0 0
#   11 0 0 0 0 0 0 1
#   13 1 0 0 0 1 0 0
#   14 0 0 1 0 0 0 0
#   16 0 0 0 0 0 0 1
#   17 0 0 1 0 0 0 0
#   18 1 0 0 0 0 1 0
#   21 0 0 0 0 0 0 0
#   23 0 1 0 0 0 0 0
#   24 0 0 0 0 0 0 0
#   27 0 0 0 0 0 0 0
#   28 1 0 0 0 0 0 0
# 
# , , age = S
# 
#      club
# score A B C D E F G
#   0  0 0 0 0 0 0 1
#   1  0 1 0 0 0 0 0
#   3  0 0 0 0 0 0 0
#   4  0 0 0 0 0 1 0
#   8  0 0 1 0 0 0 0
#   9  0 0 0 0 0 2 0
#   10 0 0 0 0 1 0 0
#   11 0 1 0 0 0 0 0
#   13 0 0 0 1 0 0 0
#   14 0 1 0 0 0 0 0
#   16 0 0 0 0 0 0 0
#   17 0 1 0 1 0 0 0
#   18 0 0 0 0 1 0 0
#   21 0 0 0 1 0 0 0
#   23 1 0 0 0 0 0 0
#   24 0 1 0 0 0 0 0
#   27 0 0 1 0 0 0 1
#   28 0 0 0 0 0 0 0

Die Ausgabe der Tabelle t.score.club.age ist ab Zeile 11 zu sehen. Die Ausgabe erfolgt wie die eines Feldes, das heißt die eigentlich drei-dimensionale Anordnung der Zahlenwerte erfolgt "schichtenweise", nämlich zuerst die Matrix für die Altersklasse J, dann die Matrix für die Altersklasse S. Die Einträge der Tabelle sind folgendermaßen zu lesen, siehe etwa Zeile 16 und 39:

Da die Ausgaben aus dem letzten Skript sehr unübersichtlich sind, gibt es die Funktion ftable(), mit der sich die Tabelle anders anordnen lässt. Die Funktion ftable() befindet sich im Paket stats und das f im Namen steht für flat, das soll heißen, dass sich mit ihr "flat tables" erzeugen lassen.

Im folgenden Skript wird die Tabelle t.score.club.age von oben mit ftable() ausgegeben, wobei für die Zeilen (das Argument row.vars) die Merkmale club und age gewählt werden.

# t.score.club.age wie oben

ftable(x = t.score.club.age, row.vars = 2:3)
#          score 0 1 3 4 8 9 10 11 13 14 16 17 18 21 23 24 27 28
# club age                                                      
# A    J         0 0 1 0 0 0  0  0  1  0  0  0  1  0  0  0  0  1
#      S         0 0 0 0 0 0  0  0  0  0  0  0  0  0  1  0  0  0
# B    J         0 0 0 0 0 0  0  0  0  0  0  0  0  0  1  0  0  0
#      S         0 1 0 0 0 0  0  1  0  1  0  1  0  0  0  1  0  0
# C    J         0 0 0 0 0 0  0  0  0  1  0  1  0  0  0  0  0  0
#      S         0 0 0 0 1 0  0  0  0  0  0  0  0  0  0  0  1  0
# D    J         0 0 0 0 1 0  0  0  0  0  0  0  0  0  0  0  0  0
#      S         0 0 0 0 0 0  0  0  1  0  0  1  0  1  0  0  0  0
# E    J         0 0 0 0 0 0  0  0  1  0  0  0  0  0  0  0  0  0
#      S         0 0 0 0 0 0  1  0  0  0  0  0  1  0  0  0  0  0
# F    J         0 0 0 0 0 0  0  0  0  0  0  0  1  0  0  0  0  0
#      S         0 0 0 1 0 2  0  0  0  0  0  0  0  0  0  0  0  0
# G    J         0 0 0 0 0 0  0  1  0  0  1  0  0  0  0  0  0  0
#      S         1 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  1  0

Aufgaben:

  1. Beschreiben Sie, wie die drei-dimensionale Darstellung der Tabelle in die "flache" Darstellung im letzten Skript überführt wird.
  2. Testen Sie den Aufruf von ftable() mit row.vars = c(1, 2) und row.vars = c(1, 3) und beschreiben Sie die Ausgabe.
  3. Testen Sie, ob anstelle von t.score.club.age an ftable() auch das ursprüngliche Dataframe result übergeben werden kann.

Zusammenfassung

Die folgenden Tabellen zeigen eine Kurzbeschreibung der in diesem Kapitel vorgestellten Funktionen. Man beachte dabei aber, dass die gezeigten Argumente meist nicht die komplette Liste der Eingabewerte darstellt. Es werden immer nur diejenigen Eingabewerte gezeigt, die hier auch besprochen wurden. Für die allgemeine Verwendung der Funktionen ist es erforderlich, die Dokumentation zu Rate zu ziehen.

Es werden immer 2 Tabellen gezeigt (außer bei den Diagnose-Funktionen):

Erzeugen von Tabellen

Funktion Beschreibung
table(...) Erzeugen einer Tabelle aus den eingegebenen Objekten; sie müssen sich als Faktor interpretieren lassen (wie die Spalten eines Dataframes).
as.table(x) Das Objekt x wird in eine Tabelle verwandelt (meist ist x eine Matrix).

 

Funktion Rückgabewert Datentyp
table(...) Kontingenz-Tabelle, die die Beziehung zwischen den Merkmalen der eingegebenen Faktoren herstellt. Die Dimension der Tabelle hängt von der Anzahl der Objekte und deren Dimensionen ab. Tabelle (table)
as.table(x) Das Objekt x wird in eine Tabelle verwandelt (meist ist x eine Matrix). Tabelle (table)

Diagnose-Funktionen

Funktion Beschreibung
is.table(x) Abfragen, ob x eine Tabelle ist.
print(x) Ausgabe der Tabelle (die Ausgabe ähnelt der eines Feldes).
str(x) Ausgabe der Struktur einer Tabelle x.
attributes(x) Ausgabe der Attribute einer Tabelle x.
summary(x) Ausgabe einer Zusammenfassung einer Tabelle x.
class(x) Ausgabe der Klasse einer Tabelle x.

Auswertung von Kontingenz-Tabellen

Funktion Beschreibung
as.data.frame(x) Verwandelt die Kontingenz-Tabelle x in ein Dataframe.
margin.table(x, margin = NULL) Für die Kontingenz-Tabelle x wird die Randverteilung zum gegebenen margin berechnet (bei Matrizen 1 für Zeilen und 2 für Spalten) .
addmargins(A, margin = seq_along(dim(A)), FUN = sum, quiet = FALSE) Zu einer gegebenen Kontingenz-Tabelle A werden zu margin die Randverteilung berechnet und zur Tabelle hinzugefügt.
prop.table(x, margin = NULL) Die Werte der Kontingenz-Tabelle x werden neu normiert, so dass die Zeilensummen (mit margin = 1 ) beziehungsweise Spaltensummen (mit margin = 2 ) gleich 1 ergeben.
ftable(..., exclude = c(NA, NaN), row.vars = NULL, col.vars = NULL) Aus den Eingabewerten... wird eine "flache" Tabelle gebildet, die für höherdimensionale Kontingenz-Tabellen besser zur Ausgabe geeignet ist. Dazu werden mehrere Dimensionen in Zeilen beziehungsweise Spalten angeordnet, was sich durch die Eingabewerte row.vars und col.vars konfigurieren lässt.

 

Funktion Rückgabewert Datentyp
as.data.frame(x) Dataframe, das man als die Rohdaten zur Kontingenz-Tabelle x interpretieren kann. Dataframe (data.frame)
margin.table(x, margin = NULL) Tabelle mit den Häufigkeiten der berechneten Randverteilung. Tabelle (table)
addmargins(A, margin = seq_along(dim(A)), FUN = sum, quiet = FALSE) Kontingenz-Tabelle, die um die Randverteilungen erweitert ist. Tabelle (table)
prop.table(x, margin = NULL) Kontingenz-Tabelle, in der die Einträge bezüglich des gegebenen margin als Wahrscheinlichkeiten normiert sind. Tabelle (table)
ftable(..., exclude = c(NA, NaN), row.vars = NULL, col.vars = NULL) Kontingenz-Tabelle mit neuer Anordnung, die bei höherdimensionalen Feldern besser zur Ausgabe geeignet ist. ftable