Matrizen in R: der Datentyp matrix

Die Komponenten eines Vektors können in R zweidimensional angeordnet werden wie in einer Matrix. Es werden verschiedene Möglichkeiten gezeigt, wie man Matrizen erzeugen kann, wie man spezielle Matrizen erzeugt und wie man auf die Komponenten einer Matrix zugreift. Weiter werden der Dimensionsvektor (Attribut dim) und das optionale Attribut dimnames vorgestellt. Wie Matrizen verknüpft werden und weitere Anwendungen folgen im nächsten Kapitel (Matrizen in R: Anwendungen).

Inhaltsverzeichnis

Einordnung des Artikels

Dieses Kapitel setzt die Kenntnis der Eigenschaften von Vektoren voraus, die in Vektoren in R: der Datentyp vector und Vektoren in R: Anwendungen erklärt wurden.

Einführung

Dieses Kapitel sollte dann durchgearbeitet werden, wenn R tatsächlich für Matrizen-Rechnung eingesetzt werden soll; andernfalls kann es übersprungen oder nur überflogen werden.

So wie Matrizen in R definiert sind, setzt dieses Kapitel allerdings die Kenntnis der Eigenschaften von Vektoren voraus, insbesondere:

Die wesentlichen Eigenschaften von Vektoren sind:

  1. Alle Komponenten besitzen den identischen Datentyp.
  2. Die Komponenten sind indiziert.

Matrizen sind in dem Sinn eine Verallgemeinerung von Vektoren, dass sie doppelt indiziert sind. Stellt man sich einen Vektor als eine eindimensionale Anordnung seiner Elemente vor, ist eine Matrix eine zweidimensionale Anordnung der Elemente. Später wird dies nochmals verallgemeinert: Felder (array) ordnen ihre Elemente in beliebig vielen Dimensionen an; man kann daher eine Matrix auch als Spezialfall eines Feldes auffassen.

Matrizen werden intern wie Vektoren behandelt; um einen Vektor tatsächlich wie eine Matrix zu interpretieren, muss bei der Definition angegeben werden, in wieviele Zeilen und Spalten die Einträge des Vektors angeordnet werden sollen.

Viele Funktionen, die bereits für Vektoren besprochen wurden, können daher auch auf Matrizen angewendet werden. Zusätzlich gibt es Funktionen, die gerade auf der zweidimensionalen Anordnung der Elemente beruhen (und wirklich nur für Matrizen, aber nicht für Felder, definiert sind). Speziell sind alle grundlegenden Funktionen vorbereitet, die man für die Lineare Algebra benötigt:

Die Elemente einer Matrix müssen nicht Zahlen sein (numeric mode), ebenso sind Zeichen und Wahrheitswerte erlaubt; da für Anwendungen von Matrizen aber fast nur Zahlen eine Rolle spielen, werden in diesem Kapitel auch nur diese behandelt.

Später wird auch noch der Datentyp Data Frame besprochen, der viele Eigenschaften mit Matrizen gemein hat; in R sind Matrizen und Data Frame aber unterschiedliche Datentypen und viele Funktionen sind nur für einen der beiden Datentypen anwendbar.

Spezielle Matrizen

In einer m × n Matrix werden reelle Zahlen in einem rechteckigen Schema angeordnet, das im Allgemeinen aus m Zeilen und n Spalten besteht. Die Zahlen werden entsprechend indiziert:

ai,j steht für die Komponente (oder das Element) in der i-ten Zeile und j-ten Spalte (siehe Abbildung 1, Gleichung 1).

Abbildung 1: Definition einer Matrix (Gleichung 1); quadratische Matrizen (Gleichung 2) stimmen in Zeilen- und Spalten-Anzahl überein, bei rechteckigen Matrizen sind sie verschieden (Gleichung 3).Abbildung 1: Definition einer Matrix (Gleichung 1); quadratische Matrizen (Gleichung 2) stimmen in Zeilen- und Spalten-Anzahl überein, bei rechteckigen Matrizen sind sie verschieden (Gleichung 3).

Stimmen die Zeilen- und Spalten-Anzahl einer Matrix überein, spricht man von einer quadratischen Matrix (siehe Gleichung 2 in Abbildung 1). Meist spricht man von einer rechteckigen Matrix, wenn diese Anzahlen nicht übereinstimmen (siehe Gleichung 3 in Abbildung 1).

Die Hauptdiagonale einer Matrix sind die Komponenten a1,1, a2,2, ... , ak,k, wobei k die kleinere der beiden Zahlen m und n ist. Man kann also auch bei rechteckigen Matrizen von einer Hauptdiagonale sprechen.

Abbildung 2: Spezielle Matrizen. Weitere Erklärungen im Text.Abbildung 2: Spezielle Matrizen. Weitere Erklärungen im Text.

Bei einer oberen Dreiecksmatrix sind alle Komponenten unterhalb der Hauptdiagonalen gleich 0, die Komponenten auf und oberhalb der Hauptdiagonalen können von 0 verschieden sein (siehe Abbildung 2, Gleichung 1). Entsprechend sind bei einer unteren Dreiecksmatrix die Komponenten oberhalb der Hauptdiagonalen gleich 0 (siehe Abbildung 2, Gleichung 2).

Sind alle Elemente außerhalb der Hauptdiagonalen gleich 0, spricht man von einer Diagonalmatrix (siehe Abbildung 2, Gleichung 3). Die n-dimensionale Einheitsmatrix En ist eine quadratische Matrix mit n Zeilen (und Spalten), die zugleich eine Diagonalmatrix ist, wobei alle Komponenten auf der Hauptdiagonalen gleich 1 sein müssen. Abbildung 2, Gleichung 4, zeigt die drei-dimensionale Einheitsmatrix.

Die Einheitsmatrix erhält ihren Namen dadurch, dass sie das neutrale Element der Matrizen-Multiplikation ist: Für jede quadratische Matrix A gilt:

A · En = En · A = A

(dabei ist A ebenfalls eine n × n Matrix).

Erzeugen von Matrizen

Die Funktion matrix()

Die Argumente der Funktion matrix()

Die einfachste Art eine Matrix zu erzeugen besteht darin, zuerst einen Vektor anzulegen und anschließend anzugeben, wie der Vektor in Zeilen und Spalten angeordnet werden soll. Dazu gibt es die Funktion matrix(), die mehrere Eingabewerte besitzt:

matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)

Die folgende Tabelle beschreibt kurz die Bedeutung der Argumente:

Argument default-Wert Beschreibung
data NA Vektor, der in Zeilen und Spalten angeordnet wird.
nrow 1 Anzahl der Zeilen der zu erzeugenden Matrix.
ncol 1 Anzahl der Spalten der zu erzeugenden Matrix.
byrow FALSE Gibt an, ob die Matrix spaltenweise (byrow = FALSE ) oder zeilenweise (byrow = TRUE ) aufgefüllt werden soll.
dimnames NULL Setzt das Attribut dimnames: 2 Namen für die beiden Dimensionen der Matrix (Zeilen und Spalten).

Das Argument dimnames wird erst später besprochen; dazu muss man zuerst den Dimensionsvektor — das Attribut dim — verstehen.

Erste Beispiele

Im folgenden Beispiel wird zuerst ein Vektor mit 12 Komponenten angelegt. Mit Hilfe der Funktion matrix() können die Komponenten wie eine Matrix angeordnet werden; dazu muss der Funktion matrix() der Vektor übergeben werden und es muss die Anzahl der Zeilen und Spalten der Matrix festgelegt werden.

Zuerst wird eine Matrix mit drei Zeilen und vier Spalten angelegt (m_3_4 ). Anschließend wird mit dem selben Vektor eine 6×2-Matrix erzeugt (m_6_2 ).

v <- (1:12)

m_3_4 <- matrix(data = v, nrow = 3, ncol = 4, byrow = TRUE)
m_6_2 <- matrix(data = v, nrow = 6, ncol = 2, byrow = TRUE)

m_3_4
m_6_2

Die Ausgabe lautet:

> m_3_4
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12

> m_6_2
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
[4,]    7    8
[5,]    9   10
[6,]   11   12

Die Schreibweise in der Ausgabe mit den eckigen Klammern wird später ausführlich erläutert — da eine Matrix doppelt indiziert ist, kann man die Bedeutung leicht erraten.

Das Argument byrow

Unverständlich ist vielleicht noch, welche Bedeutung der Eingabewert byrow besitzt. Oben wurde mit dem Vektor v die Matrix zeilenweise aufgefüllt. Setzt man byrow = FALSE , wird die Matrix spaltenweise mit den Komponenten des Vektors v aufgefüllt — wie man am folgenden Beispiel sieht:

m_3_4 <- matrix(data = v, nrow = 3, ncol = 4, byrow = FALSE)
m_3_4

An der Ausgabe erkennt man, dass im Vergleich zu oben eine andere Matrix erzeugt wurde — es handelt sich aber nicht um die transponierte Matrix:

> m_3_4
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12

Der default-Wert für byrow ist FALSE, das heißt ohne die Angabe von byrow werden die Matrizen spaltenweise aufgefüllt. Dadurch dass der erzeugende Vektor eventuell wiederholt wird, ist es auch nicht immer nötig nrow und ncol anzugeben — leichter lesbar sind die Quelltexte allerdings mit der vollständigen Angabe aller Eingabewerte.

v <- (1:12)
m_3_4 <- matrix(v, nrow = 3)
m_3_4

Jetzt wird eine Matrix mit 4 Spalten gebildet, die spaltenweise gefüllt wird:

> m_3_4
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12

Die Funktion matrix() und der recycling-Mechanismus

Um die Funktion matrix() anzuwenden, muss man auch wieder wissen, wie sie sich verhält, wenn die Anzahl der Komponenten des Vektors v nicht ausreichen, um alle Komponenten der Matrix aufzufüllen; in obigen Beispielen hatte v — wie alle mit v gebildeten Matrizen — genau 12 Komponenten:

v <- (1:10)
m_3_4 <- matrix(data = v, nrow = 3, ncol = 4, byrow = TRUE)
m_3_4

Wie zu erwarten wird der Vektor wiederholt; da aber bei der letzten Wiedeholung von v der Vektor nicht vollständig verwendet wird, gibt es eine Warnung beim Aufruf der Funktion matrix():

Warning message:
In matrix(data = v, nrow = 3, ncol = 4, byrow = TRUE) :
  data length [10] is not a sub-multiple or multiple of the number of rows [3]
> m_3_4
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10    1    2

Verwendet man dagegen einen Vektor, der zum Beispiel genau eine Zeile füllt, erhält man keine Fehlermeldung:

v <- (1:4)
m_3_4 <- matrix(data = v, nrow = 3, ncol = 4, byrow = TRUE)
m_3_4

Der recycling-Mechanismus sorgt dafür, dass v in jeder Zeile erscheint; die Ausgabe lautet jetzt:

> m_3_4
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    1    2    3    4
[3,]    1    2    3    4

Verdopplung im Speicher

Von den Möglichkeiten eine Matrix zu erzeugen, bietet die Funktion matrix() den am leichtesten lesbaren Quelltext — insbesondere wenn man alle Argumente angibt. Auf einen Nachteil soll aber hingewiesen werden: Oftmals wird der Vektor (hier v) nur erzeugt, um daraus eine Matrix zu bilden; der Vektor wird später nicht benötigt. Durch die Anwendung der Funktion matrix() wird im Speicher tatsächlich ein neues Objekt des Vektors erzeugt, das als Matrix interpretiert wird, und der ursprüngliche Vektor v verbleibt im Speicher. Gerade bei sehr langen Vektoren wird dadurch Speicherplatz verschwendet. Wird der Vektor v später nicht mehr benötigt, kann man auch durch Setzen des Dimensions-Attributs den Vektor v wie eine Matrix verwenden.

Spezielle Matrizen: Diagonalmatrizen und Dreiecksmatrizen

Überblick

Für spezielle Matrizen wäre es sehr umständlich zuerst den geeigneten Vektor zu erzeugen und damit die Funktion matrix() aufzurufen. Für folgende Matrizen gibt es Funktionen, die dies abkürzen:

Diagonalmatrizen müssen dabei nicht quadratisch sein: sie können sich in Zeilen- und Spalten-Anzahl unterscheiden. Gemeinsam ist ihnen, dass sie außerhalb der Hauptdiagonalen als Einträge 0 haben.

All diese Matrizen können mit Hilfe der Funktion diag() erzeugt werden. Im Allgemeinen besitzt die Funktion diag() drei Argumente:

diag(x = 1, nrow, ncol)

wobei x entweder eine Zahl oder ein Vektor sein kann; der default-Wert von x ist die Zahl 1. Die beiden Argumente nrow und ncol erklären sich selbst.

Welche Eingabewerte nötig sind, um die drei oben genannten Arten von Matrizen mit diag() zu erzeugen wird in den folgenden Unterabschnitten gezeigt.

Diagonalmatrizen (quadratisch oder rechteckig)

Im Folgenden wird die Namens-Konvention verwendet:

Um eine Diagonalmatrix zu erzeugen, reicht es den Vektor für die Einträge auf der Hauptdiagonalen anzugeben und diesen der Funktion diag() als x zu übergeben. Werden dabei die Argumente nrow und ncol nicht gesetzt, wird eine quadratische Matrix gebildet, deren Größe durch die Länge des erzeugenden Vektors gegeben ist.

m_3 <- diag(x = (3:1))
m_3
> m_3
     [,1] [,2] [,3]
[1,]    3    0    0
[2,]    0    2    0
[3,]    0    0    1

Möchte man eine rechteckige Diagonalmatrix erzeugen (also mit unterschiedlicher Zeilen- und Spalten-Anzahl), muss man zusätzlich die Argumente nrow und ncol setzen:

m_3_4 <- diag(x = (3:1), nrow = 3, ncol = 4)
m_3_4
> m_3_4
     [,1] [,2] [,3] [,4]
[1,]    3    0    0    0
[2,]    0    2    0    0
[3,]    0    0    1    0

Die Einheitsmatrix

Falls auf der Hauptdiagonalen immer die 1 stehen und die Matrix quadratisch sein soll (Einheitsmatrix), reicht es für x die Zahl 1 anzugeben und die Zeilen-Anzahl nrow einzugeben. Da der default-Wert von x gleich 1 ist, kann das Argument x sogar weggelassen werden. Die folgenden beiden Befehle definieren die drei-dimensionale Einheitsmatrix:

e_3 <- diag(x = 1, nrow = 3)

e_3 <- diag(nrow = 3)

Die Ausgabe lautet jeweils:

> e_3
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    1    0
[3,]    0    0    1

Man beachte, dass man die drei-dimensionale Einheitsmatrix nicht erzeugt, wenn man statt der Zeilen-Anzahl die Spalten-Anzahl angibt:

e_3 <- diag(x = 1, ncol = 3)

Jetzt lautet die Ausgabe nämlich:

> e_3
     [,1] [,2] [,3]
[1,]    1    0    0

Hier wurde also eine 1 × 3-Matrix erzeugt.

Vielfache der Einheitsmatrix

Ein Vielfaches der Einheitsmatrix erhält man, indem man den entsprechenden x-Wert angibt und die Anzahl der Zeilen; im folgenden Skript wird das 5-fache der drei-dimensionlen Einheitsmatrix erzeugt:

m <- diag(x = 5, nrow = 3)

Die Ausgabe lautet:

> m
     [,1] [,2] [,3]
[1,]    5    0    0
[2,]    0    5    0
[3,]    0    0    5

Indem man zusätzlich ncol setzt, kann man auch wieder eine rechteckige Matrix erzeugen:

m <- diag(x = 5, nrow = 3, ncol =  4)
m
# [,1] [,2] [,3] [,4]
# [1,]    5    0    0    0
# [2,]    0    5    0    0
# [3,]    0    0    5    0

Dreiecksmatrizen

Es gibt Funktionen, mit denen obere und untere Dreiecksmatrizen erzeugt werden können; allerdings sind die Elemente dieser Matrizen logische Werte (TRUE und FALSE), die sich aber leicht in die Zahlen 1 und 0 umwandeln lassen. Die Funktionen zum Erzeugen einer Matrix mit den Werten TRUE im unteren beziehungsweise oberen Dreieck lauten:

lower.tri(x, diag = FALSE)
upper.tri(x, diag = FALSE)

Dabei ist jeweils:

Das folgende Skript zeigt die Verwendung der Funktionen lower.tri() und upper.tri():

# drei-dimensionale Einheitsmatrix:
e3 <- diag(nrow = 3)

# untere Dreiecksmatrizen:

lower.tri(x = e3)
# [,1]  [,2]  [,3]
# [1,] FALSE FALSE FALSE
# [2,]  TRUE FALSE FALSE
# [3,]  TRUE  TRUE FALSE

lower.tri(x = e3, diag = TRUE)
# [,1]  [,2]  [,3]
# [1,] TRUE FALSE FALSE
# [2,] TRUE  TRUE FALSE
# [3,] TRUE  TRUE  TRUE

# obere Dreiecksmatrizen:

upper.tri(x = e3)
# [,1]  [,2]  [,3]
# [1,] FALSE  TRUE  TRUE
# [2,] FALSE FALSE  TRUE
# [3,] FALSE FALSE FALSE

upper.tri(x = e3, diag = TRUE)
# [,1]  [,2] [,3]
# [1,]  TRUE  TRUE TRUE
# [2,] FALSE  TRUE TRUE
# [3,] FALSE FALSE TRUE

Um die logischen Werte in die Zahlen 1 und 0 zu verwandeln, muss nur der Modus auf "numeric" gesetzt werden. Für die obere Dreiecksmatrix, die auf der Hauptdiagonalen 1 enthält, zeigt dies das folgende Skript; dazu wird die letzte Matrix aus obigem Skript verwendet:

e3 <- diag(nrow = 3)

d3 <- upper.tri(x = e3, diag = TRUE)
d3
# [,1]  [,2] [,3]
# [1,]  TRUE  TRUE TRUE
# [2,] FALSE  TRUE TRUE
# [3,] FALSE FALSE TRUE

mode(d3) <- "numeric"
d3
# [,1] [,2] [,3]
# [1,]    1    1    1
# [2,]    0    1    1
# [3,]    0    0    1

Eine andere Möglichkeit, Dreiecksmatrizen zu erzeugen, wird im Zusammenhang mit dem äußeren Produkt weiter unten gezeigt.

Zusammenfassung

Die folgende Tabelle zeigt nochmal die verschiedenen Einsatzmöglichkeiten der Funktion diag():

Aufruf von diag() Eingabewerte erzeugte Matrix
diag(x, nrow, ncol) x: Vektor; nrow und ncol können verschieden sein Diagonalmatrix mit nrow Zeilen, ncol Spalten und auf der Hauptdiagonalen steht der Vektor x
diag(nrow) nrow: Anzahl der Zeilen; (x ist per default gleich 1 und ncol stimmt automatisch mit nrow überein) Einheitsmatrix mit nrow Zeilen und nrow Spalten
diag(x, nrow) x: Zahl, nrow: Anzahl der Zeilen; x-faches der Einheitsmatrix mit nrow Zeilen und nrow Spalten

Weiter unten wird gezeigt, dass die Funktion diag() noch eine weitere Verwendung zulässt: Mit ihr kann aus einer Matrix die Hauptdiagonale extrahiert werden.

Die Funktionen col() und row()

Die beiden Funktionen col() und row() bieten die Möglichkeit, den Spalten- beziehungsweise Zeilenindex für alle Elemente der entsprechenden Spalte oder Zeile zu übernehmen. Dazu muss den Funktionen nur eine Matrix x übergeben werden; als Rückgabewert erhält man eine Matrix mit identischer Zeilen- und Spalten-Anzahl mit oben beschriebenen Elementen:

v <- (1:12)

m <- matrix(data = v, nrow = 3, ncol = 4, byrow = TRUE)
m
# [,1] [,2] [,3] [,4]
# [1,]    1    2    3    4
# [2,]    5    6    7    8
# [3,]    9   10   11   12

# Matrix mit konstanten Spalten (Wert == Spaltenindex):
m.col <- col(m)
m.col
# [,1] [,2] [,3] [,4]
# [1,]    1    2    3    4
# [2,]    1    2    3    4
# [3,]    1    2    3    4

# Matrix mit konstanten Zeilen (Wert == Zeilenindex):
m.row <- row(m)
m.row
# [,1] [,2] [,3] [,4]
# [1,]    1    1    1    1
# [2,]    2    2    2    2
# [3,]    3    3    3    3

Die Funktionen rbind() und cbind()

Oft ist es einfacher Matrizen dadurch zu erzeugen, dass eine bereits bestehende Matrix verwendet wird und dieser eine Zeile oder Spalte hinzugefügt wird. Dies geschieht durch die beiden Funktionen rbind() und cbind(). (Dabei steht r für row und c für column.)

Die Funktionen rbind() und cbind() können beliebig viele Eingabewerte aufnehmen, was in ihrer Definition am Argument ... erkennbar ist:

cbind(...)
rbind(...)

Ihre wichtigsten Eigenschaften sind:

Das folgende Skript zeigt die wichtigsten Beispiele für die Verwendung von rbind() und cbind():

# reihenweises Aneinanderhängen mit rbind():
m <- rbind(diag(nrow = 2), (1:2), (3:4))
m
# [,1] [,2]
# [1,]    1    0
# [2,]    0    1
# [3,]    1    2
# [4,]    3    4


# spaltenweises Aneinanderhängen mit cbind():
m <- cbind(diag(nrow = 2), (1:2), (3:4))
m
# [,1] [,2] [,3] [,4]
# [1,]    1    0    1    3
# [2,]    0    1    2    4


# recycling bei Eingabe einer Zahl anstelle eines passenden Vektors (recycling):
m <- cbind(diag(nrow = 2), (1:2), 1)
m
# [,1] [,2] [,3] [,4]
# [1,]    1    0    1    1
# [2,]    0    1    2    1


# dritter Eingabewert ist zu langer Vektor (wird gekürzt):
m <- cbind(diag(nrow = 2), (1:2), (3:5))
# Warning message:
#   In cbind(diag(nrow = 2), (1:2), (3:5)) :
#   number of rows of result is not a multiple of vector length (arg 3)
m
# [,1] [,2] [,3] [,4]
# [1,]    1    0    1    3
# [2,]    0    1    2    4


# dritter Eingabewert ist zu kurzer Vektor (recycling):
m <- cbind(diag(nrow = 3), (1:3), (1:2))
# Warning message:
#   In cbind(diag(nrow = 3), (1:3), (1:2)) :
#   number of rows of result is not a multiple of vector length (arg 3)
m
# [,1] [,2] [,3] [,4] [,5]
# [1,]    1    0    0    1    1
# [2,]    0    1    0    2    2
# [3,]    0    0    1    3    1


# Eingabe unpassender Matrizen (Fehlermeldung, kein Rückgabewert):
rm(m)
m <- cbind(diag(nrow = 3), diag(nrow = 4) )
# Error in cbind(diag(nrow = 3), diag(nrow = 4)) : 
#   number of rows of matrices must match (see arg 2)
m
# Error: object 'm' not found


# Eingabe zweier unpassender Vektoren (recycling):
m <- cbind((1:2), (3:5))
# Warning message:
# In cbind((1:2), (3:5)) :
# number of rows of result is not a multiple of vector length (arg 1)
m
#  [,1] [,2]
# [1,]    1    3
# [2,]    2    4
# [3,]    1    5

Das äußere Produkt outer()

Die bisher vorgestellten Funktionen dienen vor allem dazu, möglichst einfache Matrizen zu erzeugen. Das äußere Produkt erlaubt deutlich komplexere Matrizen zu erzeugen.

Das folgende Beispiel zeigt eine Matrix, die mit dem äußeren Produkt mit einer Anweisung erzeugt werden kann.

Beispiel: Augensumme beim zweimaligen Werfen eines Würfels

Wird ein Würfel zweimal nacheinander und unabhängig voneinander geworfen, kann man die Augensumme durch die Matrix S in Abbildung 3 beschreiben.

Abbildung 3: Matrix, die die Augensumme beim zweimaligen Werfen eines Würfels angibt.Abbildung 3: Matrix, die die Augensumme beim zweimaligen Werfen eines Würfels angibt.

Die Matrix S ist leicht zu interpretieren. Ergibt sich beim ersten Wurf die Augenzahl i, i = 1, 2, ... , 6 und beim zweiten Wurf die Augenzahl j, j = 1, 2, ... , 6, so gilt für den Eintrag Sij der Matrix S:

Sij = i + j.

Damit gehorchen die Einträge der Matrix S einem einfachen Bildungsgesetz, das mit den bisher besprochenen Methoden zum Erzeugen von Matrizen schwer nachzuahmen ist.

Um ein Bildungsgesetz — wie es für die Augensumme beim zweimaligen Werfen eines Würfels benötigt wird — zu verwirklichen, gibt es in R das äußere Produkt outer().

Die Matrix S kann man sich wiefolgt erzeugt denken: Man bildet zunächst das Kreuzprodukt der Zahlenmenge { 1, 2, 3, 4, 5, 6} mit sich selbst (also alle möglichen Kombinationen); dabei entstehen 36 Zahlenpaare (i, j), die man in einer 6 × 6-Matrix anordnen kann. Ordnet man nun jedem Zahlenpaare (i, j) die Zahl i + j zu, entsteht gerade die Matrix S. Und genau diese Operationen verbergen sich hinter outer():

v <- (1:6)
m <- outer(X = v, Y = v, FUN = "+")
m
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    2    3    4    5    6    7
[2,]    3    4    5    6    7    8
[3,]    4    5    6    7    8    9
[4,]    5    6    7    8    9   10
[5,]    6    7    8    9   10   11
[6,]    7    8    9   10   11   12

Die Funktion outer() besitzt drei Eingabewerte:

outer(X, Y, FUN = "*")

Gibt man keine Funktion FUN an, wird das Produkt gebildet (der default-Wert von FUN ist also * ). Dafür gibt es die abgekürzte Schreibweise mit dem Operator %o% . Und daher sind im folgenden Skript die drei Anweisungen in Zeile 3, 5 und 7 identisch:

v <- (1:6)

m <- outer(X = v, Y = v, FUN = "*")

m <- outer(X = v, Y = v)

m <- v %o% v
m
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    2    3    4    5    6
[2,]    2    4    6    8   10   12
[3,]    3    6    9   12   15   18
[4,]    4    8   12   16   20   24
[5,]    5   10   15   20   25   30
[6,]    6   12   18   24   30   36

Bisher wurde nicht besprochen:

Die folgenden Beispiele sollen diese Fragen beantworten:

v <- (1:6)
w <- (1:3)

# 6 Zeilen, 3 Spalten:
m <- v %o% w
m
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    4    6
[3,]    3    6    9
[4,]    4    8   12
[5,]    5   10   15
[6,]    6   12   18

# 3 Zeilen, 6 Spalten:
m <- w %o% v
m
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    2    3    4    5    6
[2,]    2    4    6    8   10   12
[3,]    3    6    9   12   15   18

# Aufruf von outer() mit Operation
m <- outer(X = v, Y = w, FUN = "+")
m
    [,1] [,2] [,3]
[1,]    2    3    4
[2,]    3    4    5
[3,]    4    5    6
[4,]    5    6    7
[5,]    6    7    8
[6,]    7    8    9

# Aufruf von outer() mit Funktion
m <- outer(X = v, Y = w, FUN = "pmax")
m
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    2    3
[3,]    3    3    3
[4,]    4    4    4
[5,]    5    5    5
[6,]    6    6    6

Dem Argument FUN kann anstelle einer geeigneten Operation (zum Beispiel in Zeile 24) oder einer in R definierten Funktion (wie oben mit pmax, Zeile 35) auch eine selbstdefinierte Funktion übergeben werden.

Bisher wurden für X und Y in outer() nur Vektoren eingesetzt; im Kapitel über Felder (array) wird gezeigt, dass man auch Felder beliebiger Dimension einsetzen kann.

Das folgende Beispiel erzeugt eine obere Dreiecksmatrix, die auf und oberhalb der Hauptdiagonalen 1 stehen hat und sonst 0:

m <- outer(X = (1:6), Y = (1:6), FUN = "<=")

m
# [,1]  [,2]  [,3]  [,4]  [,5] [,6]
# [1,]  TRUE  TRUE  TRUE  TRUE  TRUE TRUE
# [2,] FALSE  TRUE  TRUE  TRUE  TRUE TRUE
# [3,] FALSE FALSE  TRUE  TRUE  TRUE TRUE
# [4,] FALSE FALSE FALSE  TRUE  TRUE TRUE
# [5,] FALSE FALSE FALSE FALSE  TRUE TRUE
# [6,] FALSE FALSE FALSE FALSE FALSE TRUE

mode(m) <- "numeric"

m
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    1    1    1    1    1    1
# [2,]    0    1    1    1    1    1
# [3,]    0    0    1    1    1    1
# [4,]    0    0    0    1    1    1
# [5,]    0    0    0    0    1    1
# [6,]    0    0    0    0    0    1

Zur Erklärung:

Zeile 1: Als Argument FUN wird der Vergleichs-Operator <= eingesetzt.

Zeile 3 bis 10: Durch die Vergleiche entstehen logische Werte, daher zeigt die Ausgabe TRUE und FALSE; aber man erkennt, dass auf und oberhalb der Hauptdiagonalen immer TRUE steht, sonst FALSE.

Zeile 12: Setzt man jetzt den Modus der Matrix auf "numeric", so erhält man gerade die gewünschte Matrix (Zeile 15 bis 21).

Aufgabe:

Zeigen Sie, dass man mit der Typumwandlung

m.num <- as.numeric(m)

nicht das gewünschte Ergebnis erhält!

Haben Sie eine Erklärung dafür, warum m.num ein Vektor und keine Matrix ist?

Die Funktion as.matrix()

Mit der Funktion as.matrix(x) kann ein Vektor x in eine Matrix verwandelt werden. Da die Funktion aber kein Argument besitzt, das die Zeilen- oder Spalten-Anzahl festlegen lässt, wird eine Matrix erzeugt mit:

Das folgende Beispiel zeigt dies:

v <- (1:4)
str(v)
# int [1:4] 1 2 3 4

m <- as.matrix(v)

m
# [,1]
# [1,]    1
# [2,]    2
# [3,]    3
# [4,]    4

Die Funktion as.matrix(x) wird meist verwendet, um ein Data Frame x in eine Matrix zu verwandeln. Data Frame ist ein Datentyp, der für statistische Auswertungen sehr gut eingesetzt werden kann und der viele Eigenschaften mit einer Matrix gemeinsam hat. Aber ein Data Frame ist keine Matrix. Die Eigenschaften der Funktion as.matrix() bei Anwendung auf ein Data Frame werden erst im Kapitel Data Frame besprochen.

Erzeugen einer Matrix durch Setzen des Attributes dim

Oben wurde die Funktion matrix(data = v, nrow, ncol, byrow) verwendet, um einen gegebenen Vektor v in eine Matrix umzuwandeln; dabei wurde auch erwähnt, dass danach der Vektor zweimal im Speicher liegt — was bei großen Vektoren nicht zu empfehlen ist.

Es gibt eine weitere Methode, um einen Vektor in eine Matrix zu verwandeln: Mit Hilfe der Funktion dim() kann zu einem gegebenen Vektor v das Attribut dim gesetzt werden. Dieses Attribut sorgt dafür, dass der Vektor als Matrix interpretiert wird; aber es wird dabei kein neuer Vektor erzeugt.

Dieses Verfahren setzt die Kenntnis des Attributes dim voraus, das weiter unten besprochen wird. Dort wird auch gezeigt, wie man eine Matrix erzeugen kann.

Umwandlung eines Data Frame in eine Matrix

Bei der Besprechung des Datentyps Data Frame wird sich zeigen, dass diese sehr viele Eigenschaften mit Matrizen gemeinsam haben — aber die beiden Datentypen Matrix und Data Frame sind unterschiedlich! Zur Verarbeitung der Daten, die in einem Data Frame gegeben sind, werden dieses oft in eine Matrix umgewandelt; die zugehörige Funktion ist:

data.matrix(frame)

Sie wird allerdings erst im Kapitel über Data Frame besprochen.

Zugriff auf die Elemente einer Matrix

Zugriff auf einzelne Elemente

Ein Element einer Matrix ist durch Angabe von Zeilen- und Spaltenindex eindeutig bestimmt. Der Zugriff erfolgt ähnlich wie bei einem Vektor: bei einer Matrix werden die beiden Indizes in eckige Klammern geschrieben und durch ein Komma getrennt. Man beachte, dass der Zeilenindex immer zuerst genannt wird. Die Merkregel dafür ist einfach — sie entspricht unserer Leserichtung: man liest immer zuerst von links nach rechts (Zeile) und dann von oben nach unten (Spalte).

Im folgenden Beispiel wird eine Diagonalmatrix definiert, anschließend wird auf einige ihrer Elemente zugegriffen:

m <- diag(4:1)

m[1,1]			# 4
m[1,2]			# 0
m[2,2]			# 3
m[2,4]			# 0

m[2,5]			# Error in m[2, 5] : subscript out of bounds
m[0,3]			# integer(0) 

m[1]			# 4
m[15]			# 0
m[16]			# 1

length(m)		# 16

Zur Erklärung:

Zeile 1: Es wird eine Diagonalmatrix erzeugt mit den Einträgen 4 3 2 1 auf der Hauptdiagonalen.

Zeile 3 bis 6: In der ersten Zeile und ersten Spalte steht die 4, die weiteren Elemente sollten auch klar sein.

Zeile 8: Da es keine 5. Spalte gibt, kann das Element m[2,5] nicht angezeigt werden.

Zeile 11 bis 13: Intern wird eine Matrix wie ein Vektor behandelt, der nachträglich in Zeilen und Spalten angeordnet wird. Daher ist der Zugriff auf den zugrundeliegenden Vektor möglich; er erfolgt indem nur ein Index angegeben wird.

Zeile 15: Lässt man die Länge der Matrix ausgeben, erhält man tatsächlich die Länge des zugrundeliegenden Vektors.

Aufgabe: Das obige Beispiel ist nicht eindeutig, was den Zugriff auf den zugrundeliegenden Vektor betrifft. Klar ist, dass m[5] == 0 . Aber ist das Element m[5] :

Schreiben Sie ein geeignetes Skript, um diese Frage zu klären.

Zugriff auf Zeilen und Spalten

Oben wurden schon mehrere Matrizen definiert und ausgegeben. An der Schreibweise, wie in der Konsole Zeilen und Spalten gekennzeichnet werden, erkennt man, wie auf diese zugegriffen werden kann.

Als Beispiel wird aus den Zahlen von 1 bis 12 eine 3 × 4-Matrix gebildet und anschließend werden einige Zeilen und Spalten ausgegeben:

m <- matrix((1:12), nrow = 3, byrow = TRUE)
m
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12 

m[1, ]			# 1. Zeile: 1 2 3 4
m[ ,1]			# 1. Spalte: 1 5 9 
m[ ,4]		 	# 4. Spalte: 4 8 12

Man kann den Zugriff so erklären:

Dabei muss aber das Komma angegeben werden; denn wie oben schon gesagt, wird durch die Angabe nur eines Index auf den zugrundeliegenden Vektor zugegriffen.

Filterung: Indexvektoren

Bisher wurden folgende Zugriffe beschrieben.

Wie realisiert man den Zugriff auf eine beliebige Teilmengen der Elemente einer Matrix? Das Verfahren ist ähnlich wie bei Vektoren:

Eine Menge von Indizes wird durch einen sogenannten Indexvektor gebildet. Das folgende Skript zeigt einige Beispiele:

m <- diag((4:1))

m
# [,1] [,2] [,3] [,4]
# [1,]    4    0    0    0
# [2,]    0    3    0    0
# [3,]    0    0    2    0
# [4,]    0    0    0    1

m[c(1, 2), c(1, 2)]
# [,1] [,2]
# [1,]    4    0
# [2,]    0    3

m[c(2, 3), c(3, 4)]
# [,1] [,2]
# [1,]    0    0
# [2,]    2    0

m[c(FALSE, TRUE, TRUE, FALSE), c(FALSE, FALSE, TRUE, TRUE)]
# [,1] [,2]
# [1,]    0    0
# [2,]    2    0

Zur Erklärung:

Zeile 1: Es wird wieder die 4 × 4-Matrix mit den Zahlen 4 3 2 1 auf der Hauptdiagonalen erzeugt.

Zeile 10: Sowohl für die Zeilen als auch für die Spalten wird der Index 1 und 2 ausgewählt; das Objekt m[c(1, 2), c(1, 2)] ist eine Matrix mit zwei Zeilen und zwei Spalten, nämlich die linke obere Teilmatrix von m.

Zeile 15: Wieder werden zwei Zeilen und zwei Spalten ausgewählt, diesmal aber die 2. und 3. Zeile sowie die 3. und 4. Spalte: m[c(2, 3), c(3, 4)] Auch hier entsteht eine 2 × 2-Matrix, die man in m leicht identifizieren kann. Man beachte, dass in der Ausgabe dieser neuen Matrix die Indizes 1 und 2 verwendet werden (es ist ja tatsächlich eine neue Matrix gebildet worden und Indizes beginnen immer bei 1).

Zeile 20: Dieselbe Matrix, die in Zeile 15 erzeugt wurde, kann auch mit Hilfe logischer Vektoren erzeugt werden. Dazu werden logische Vektoren der Länge 4 verwendet und die in Zeile 15 ausgewählten Indizes TRUE gesetzt, die anderen Indizes auf FALSE.

Manchmal ist die Auswahl einer Teilmatrix einfacher durch Streichen von einzelnen Zeilen und (oder) Spalten zu erreichen, wie es etwa bei den Streichmatrizen zur Berechnung von Determinanten nach dem Laplaceschen Entwicklungssatz geschieht. Der folgende Unterabschnitt zeigt dieses Vorgehen.

Entfernen von Zeilen oder Spalten aus einer Matrix

Bei Vektoren wurde schon gezeigt, dass negative Indizes verwendet werden, um einzelne Komponenten aus einem Vektor zu entfernen. Dies wird für Matrizen verallgemeinert: es können Zeilen, Spalten oder beide gleichzeitig aus einer Matrix entfernt werden.

Das folgende Skript zeigt nochmals, wie Komponenten aus einem Vektor entfernt werden:

v <- (4:1)

# Entfernen der ersten Komponente von v:
v[-1]
# [1] 3 2 1

# Entfernen der zweiten Komponente von v:
v[-2]
# [1] 4 2 1

# Entfernen der ersten und zweiten Komponente von v:
v[c(-1, -2)]
# [1] 2 1

Da der Zugriff auf die Elemente einer Matrix über zwei Indizes erfolgt, können Zeilen, Spalten oder beide gleichzeitig (Streichmatrix) entfernt werden. Das folgende Skript erzeugt zunächst die Diagonalmatrix m mit den Elementen 4 3 2 1 auf der Hauptdiagonale; anschließend werden Elemente entfernt:

m <- diag((4:1))

m
# [,1] [,2] [,3] [,4]
# [1,]    4    0    0    0
# [2,]    0    3    0    0
# [3,]    0    0    2    0
# [4,]    0    0    0    1

# Entfernen der ersten Zeile von m:
m[-1, ]
# [,1] [,2] [,3] [,4]
# [1,]    0    3    0    0
# [2,]    0    0    2    0
# [3,]    0    0    0    1

# Entfernen der zweiten Spalte von m:
m[ , -2]
# [,1] [,2] [,3]
# [1,]    4    0    0
# [2,]    0    0    0
# [3,]    0    2    0
# [4,]    0    0    1

# Entfernen der ersten Zeile und der zweiten Spalte von m (Streichmatrix):
m[-1, -2]
# [,1] [,2] [,3]
# [1,]    0    0    0
# [2,]    0    2    0
# [3,]    0    0    1

# Entfernen der ersten und zweiten Zeile von m:
m[c(-1, -2), ]
# [,1] [,2] [,3] [,4]
# [1,]    0    0    2    0
# [2,]    0    0    0    1

Die Funktionen head() und tail()

Die Funktionen head() und tail() wurden schon für Vektoren vorgestellt. Da sie generisch implementiert sind, können sie auch den vorderen oderen hinteren Teil einer Matrix zurückgeben; dabei ist vorderer Teil und hinterer Teil so zu verstehen, dass die Matrix zeilenweise gelesen wird. Die Eingabewerte sind eine Matrix x sowie die Zeilen-Anzahl n, die von x ausgewählt werden soll; der default-Wert für n ist 6:

head(x, n = 6L)
tail(x, n = 6L)

Es folgen einige Beispiele:

m <- diag((10:1))

m.head <- head(m)
m.head
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,]   10    0    0    0    0    0    0    0    0     0
# [2,]    0    9    0    0    0    0    0    0    0     0
# [3,]    0    0    8    0    0    0    0    0    0     0
# [4,]    0    0    0    7    0    0    0    0    0     0
# [5,]    0    0    0    0    6    0    0    0    0     0
# [6,]    0    0    0    0    0    5    0    0    0     0
# Beachte: default-Wert für n ist 6

m.head2 <- head(x = m, n = 2)
m.head2
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,]   10    0    0    0    0    0    0    0    0     0
# [2,]    0    9    0    0    0    0    0    0    0     0
# andere Werte müssen explizit angegeben werden

m.tail <- tail(x = m, n = 2)
m.tail
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [9,]    0    0    0    0    0    0    0    0    2     0
# [10,]    0    0    0    0    0    0    0    0    0     1

m.tail[10, ]
# Error in m.tail[10, ] : subscript out of bounds

m.tail[2, ]
# [1] 0 0 0 0 0 0 0 0 0 1
# Beachte die Ausgabe von m.tail: Die Zeilen werden zwar mit 9 und 10 bezeichnet, die
# tatsächlichen Indizes sind aber 1 und 2.

Zur Erklärung:

Zeile 1: Es wird eine Diagonalmatrix m mit 10 Zeilen und 10 Spalten erzeugt.

Zeile 3: Wird an die Funktion head() nur die Matrix m, aber keine Zeilen-Anzahl n übergeben, so wird n gleich 6 gesetzt; es entsteht eine Matrix mit 6 Zeilen (die ersten 6 Zeilen von m) und 10 Spalten.

Zeile 14: Es wird ausdrücklich n = 2 gesetzt.

Zeile 21: Beim Aufruf von tail() mit n = 2 ist zu beachten, dass die Ausgabe zwar die 9. und 10. Zeile von m anzeigt, die neu erzeugte Matrix hat aber 1 und 2 als Zeilen-Indizes (siehe Zeile 27 und 30).

Ähnlich wie man durch negative Indizes Zeilen (oder Spalten) aus einer Matrix entfernen kann, ist es erlaubt, für das Argument n negative Zahlen einzugeben (die Matrix m von oben wird weiterverwendet):

m.upper3 <- head(x = m, n = -7)
m.upper3
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,]   10    0    0    0    0    0    0    0    0     0
# [2,]    0    9    0    0    0    0    0    0    0     0
# [3,]    0    0    8    0    0    0    0    0    0     0

m.lower3 <- tail(x = m, n = -7)
m.lower3
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [8,]    0    0    0    0    0    0    0    3    0     0
# [9,]    0    0    0    0    0    0    0    0    2     0
# [10,]    0    0    0    0    0    0    0    0    0     1

Beim Aufruf von head() mit einem negativen n werden die letzten n Zeilen abgeschnitten und der verbleibende vordere Teil von x zurückgegeben (siehe Zeile 1).

Beim entsprechenden Aufruf von tail() werden die vorderen n Zeilen abgeschnitten und der verbleibende hintere Teil von x zurückgegeben (siehe Zeile 8).

Zugriff über Zeilen- und Spalten-Namen

Ähnlich wie bei Vektoren Namen für die Komponenten vergeben werden können, lassen sich für Matrizen Namen für die Zeilen und Spalten vergeben. Und diese Namen können verwendet werden, um Teile einer Matrix auszuwählen.

Die ausführliche Erklärung wird später gegeben, wenn die Attribute dim und dimnames eingeführt wurden (siehe Das optionale Attribut dimnames).

Extrahieren der Hauptdiagonale einer Matrix

Mit Hilfe der Funktion diag() können — wie oben gezeigt — Diagonalmatrizen und die n-dimensionale Einheitsmatrix erzeugt werden. Umgekehrt kann bei einer gegebenen Matrix der Vektor extrahiert werden, der die Elemente auf der Hauptdiagonalen der Matrix besitzt. Das einfachste Beispiel erfolgt mit der Einheitsmatrix:

# Erzeugen der vierdimensionalen Einheitsmatrix

m_4 <- diag(4)
m_4
     [,1] [,2] [,3] [,4]
[1,]    1    0    0    0
[2,]    0    1    0    0
[3,]    0    0    1    0
[4,]    0    0    0    1

# Extrahieren der Hauptdiagonale als Vektor

v <- diag(m_4)
v
[1] 1 1 1 1

Das Extrahieren der Hauptdiagonalen ist nicht auf quadratische Matrizen beschränkt. Im folgenden Beispiel wird die vierdimensionale Einheitsmatrix (nämlich m_4 aus dem Beispiel oben) mit Hilfe der Funktion rbind() in eine 5 × 4-Matrix verwandelt und anschließend wird die Hauptdiagonale als Vektor gespeichert und angezeigt:

m_5_4 <- rbind((1:4), m_4)
m_5_4
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    1    0    0    0
[3,]    0    1    0    0
[4,]    0    0    1    0
[5,]    0    0    0    1

v <- diag(m_5_4)
v
[1] 1 0 0 0

Dokumentation: ?Extract

Im Paket base unter ?Extract finden sich ausführliche Informationen über

Die Attribute dim und dimnames

Übersicht

Die Funktion length() ist für jedes Objekt in R definiert: sie gibt zum Beispiel bei Vektoren die Anzahl der Komponenten an. Vektoren kann man als eindimensionale Objekte auffassen, weil hier Zahlen der Reihe nach angeordnet werden. (Dies hat nichts damit zu tun, dass etwa ein Vektor mit drei Komponenten als Richtungsangabe im drei-dimensionlen Raum aufgefasst werden kann.)

Dagegen sind Matrizen eine zweidimensionale (rechteckige) Anordnung ihrer Komponenten, die man durch zwei Zahlenangaben charakterisieren kann:

Fasst man diese beiden Zahlen zu einem Vektor zusammen, entsteht der sogenannte Dimensionsvektor einer Matrix. Man kann sich den Dimensionsvektor somit als eine Verallgemeinerung der Länge eines Vektors vorstellen.

Dieser Dimensionsvektor ist zugleich das Attribut dim einer Matrix; es wird beim Erzeugen einer Matrix automatisch gesetzt. Es sorgt dafür, dass der Vektor, der die Komponenten der Matrix enthält, als zweidimensionales Objekt interpretiert wird.

Später werden Felder (array) vorgestellt: diese werden wie Vektoren abgespeichert, haben aber einen Dimensionsvektor beliebiger Länge — sie können somit als eine Anordnung von Komponenten in beliebig vielen Dimensionen interpretiert werden.

Als spezielles Attribut sollte dim nur so verwendet werden, wie es in der Dokumentation beschrieben ist.

Das weitere Attribut dimnames ist im Gegensatz zu dim lediglich optional. So wie das Attribut names erlaubt, die Komponenten eines Vektors mit Namen zu versehen, kann man mit dem Attribut dimnames den Zeilen und Spalten einer Matrix Namen geben. Über diese Namen kann man dann auch auf die Elemente der Matrix zugreifen — dies ist oft weniger fehleranfällig als der Zugriff über die leicht zu verwechselnden Indizes.

Man kann das Attribut dimnames entweder als Ganzes setzen und somit allen Zeilen und allen Spalten Namen geben — dies geschieht mit der replacement-Version von dimnames(). Oder man kann nur den Zeilen beziehungsweise nur den Spalten Namen geben — mit Hilfe der replacement-Versionen der Funktionen rownames() beziehungsweise colnames().

Das Dimensions-Attribut dim

Automatisches Setzen des Dimensions-Attributs

Wie in der Übersicht gesagt wurde, wird der Dimensionsvektor — das Attribut dim — beim Erzeugen einer Matrix automatisch gesetzt. Das folgende Skript zeigt dies am Beispiel einer Matrix, die durch matrix() erzeugt wird:

rm(v)
rm(m)

v <- (1:12)
v

attributes(v)
# NULL

dim(v)
# NULL

m <- matrix(v, nrow = 3, ncol = 4, byrow = TRUE)

m
# [,1] [,2] [,3] [,4]
# [1,]    1    2    3    4
# [2,]    5    6    7    8
# [3,]    9   10   11   12

attributes(m)
# $dim
# [1] 3 4

dim(m)
# [1] 3 4

Zur Erklärung:

Zeile 1 und 2: Die Objekte, die später erzeugt und untersucht werden sollen, werden zuerst gelöscht.

Zeile 4: Es wird zunächst ein Vektor v erzeugt.

Zeile 7 und 10: Es werden die Attribute von v und der Dimensionsvektor von v abgefragt. Beide existieren nicht: die Ausgabe ist NULL.

Zeile 13: Mit Hilfe der Funktion matrix() wird aus v eine Matrix m erzeugt, genauer eine Matrix mit 3 Zeilen und 4 Spalten.

Zeile 21 bis 26: Fragt man die Attribute von m ab, wird als einziges Attribut dim angezeigt. Dessen Wert kann auch mit der Funktion dim() festgestellt werden: es ist ein Vektor der Länge 2, wobei die Einträge gleich der Zeilen- und Spalten-Anzahl sind.

Erzeugen einer Matrix aus einem Vektor

Das letzte Skript liefert den Hinweis, wie man eine Matrix aus einem Vektor erzeugen kann, ohne die Funktion matrix() anzuwenden: Da sich eine Matrix von einem Vektor nur durch das Attribut dim unterscheidet, reicht es den geeigneten Dimensionsvektor zu erzeugen und diesen dem Vektor als Attribut dim zu übergeben.

Im folgenden Skript wird zuerst ein Vektor v mit 12 Komponenten erzeugt. Anschließend wird der Dimensionsvektor für eine Matrix mit 3 Zeilen und 4 Spalten erzeugt. Dieser Dimensionsvektor wird als Attribut dim für den Vektor v gesetzt; dazu wird die replacement-Version von dim() verwendet.

rm(v)
v <- (1:12)
v
# [1]  1  2  3  4  5  6  7  8  9 10 11 12

dim(v) <- c(3, 4)

v
# [,1] [,2] [,3] [,4]
# [1,]    1    4    7   10
# [2,]    2    5    8   11
# [3,]    3    6    9   12

is.matrix(v)
# [1] TRUE

is.vector(v)
# [1] FALSE

Zur Erklärung:

Zeile 6: Der Dimensionsvektor für eine 3 × 4-Matrix lautet: c(3, 4) . Dieser wird an den Vektor v als Attribut dim übergeben.

Zeile 8 bis 12: Die Ausgabe von v zeigt jetzt tatsächlich eine 3 × 4-Matrix.

Zeile 14: Mit Hilfe der is-dot-Funktion is.matrix() wird abgefragt, ob v eine Matrix ist; die Ausgabe ist TRUE.

Zeile 17: Dagegen liefert is.vector() den Wert FALSE.

Die hier vorgestellte Methode eine Matrix zu erzeugen, hat gegenüber der Funktion matrix() den Vorteil, dass keine Kopie des Vektors v angelegt wird; wenn also der Vektor wirklich dazu da war, die Zahlenwerte für die Matrix zu liefern, ist diese Methode vorzuziehen. Der Nachteil ist, dass die Anweisung, die aus dem Vektor eine Matrix macht (Zeile 6 oben) im Quelltext schwerer als solche zu erkennen ist (im Vergleich dazu ist der Aufruf von matrix() klarer verständlich).

Das optionale Attribut dimnames

Setzen von dimnames und der Zusammenhang zwischen dimnames() und den Funktionen colnames() und rownames()

Das folgende Beispiel zeigt:

rm(m)

m <- diag((3:1))
m
# [,1] [,2] [,3]
# [1,]    3    0    0
# [2,]    0    2    0
# [3,]    0    0    1

dim(m)
# [1] 3 3

dimnames(m)
# NULL

colnames(m)
# NULL

rownames(m)
# NULL

dimnames(m) <- list(c("X1", "X2", "X3"), c("Y1", "Y2", "Y3"))

dimnames(m)
# [[1]]
# [1] "X1" "X2" "X3"
# 
# [[2]]
# [1] "Y1" "Y2" "Y3"

m
# Y1 Y2 Y3
# X1  3  0  0
# X2  0  2  0
# X3  0  0  1

colnames(m)
# [1] "Y1" "Y2" "Y3"

rownames(m)
# [1] "X1" "X2" "X3"

# Nachdem die dimnames gesetzt wurden, 
# ist der Zugriff auf die Matrix-Komponenten mit den dimnames möglich:
m["X1", "Y1"]
# [1] 3

Zur Erklärung:

Zeile 1: Damit kein Objekt m mit bereits gesetzten Attributen vorliegt, wird m zuerst gelöscht.

Zeile 3: Es wird eine Diagonalmatrix m erzeugt; auf der Hauptdiagonale stehen die Einträge 3 2 1.

Zeile 4 bis 8: Die Ausgabe von m erfolgt wie gewohnt mit der Indizierung in eckigen Klammern.

Zeile 10: Der Dimensionsvektor besteht aus zwei Komponenten, die beide gleich 3 sind (die Matrix hat drei Zeilen und drei Spalten).

Zeile 13 bis 20: Die Funktionen dimnames(), colnames() und rownames() liefern jeweils NULL: keiner dieser Namen wurde gesetzt.

Zeile 22: Diese Anweisung ist hier noch unverständlich, da Listen noch nicht besprochen wurden. Man kann die rechte Seite der Anweisung aber leicht erklären. Für jede Komponente des Dimensionsvektors wird ein Vektor mit drei Namen angelegt; der erste Vektor gibt den Zeilen die Namen c("X1", "X2", "X3") , der zweite Vektor den Spalten c("Y1", "Y2", "Y3") . Da man jetzt einen Datentyp benötigt, der zwei "character"-Vektoren beinhaltet, muss es sich um eine rekursive Struktur handeln — mit einem Vektor kann man dies nicht realisieren. Daher wird eine Liste (list) gebildet.

Zeile 24 bis 29: Unverständlich ist auch noch die Ausgabe des Attributs dimnames. In den doppelten eckigen Klammern wird die Indizierung der Liste angezeigt: Die Liste hat zwei Komponenten; die erste Komponente enthält den Vektor für die Zeilen-Namen, die zweite Komponente den Vektor für die Spalten-Namen.

Zeile 31 bis 35: Die Ausgabe der Matrix m erfolgt jetzt mit den neu gesetzten Namen der Zeilen und Spalten anstelle der Indizierung mit eckigen Klammern.

Zeile 37 bis 41: Mit der Funktion dimnames() konnten alle Namen gleichzeitig abgefragt werden; die Ausgabe war die einer Liste. Dagegen können mit den Funktionen colnames() und rownames() die Komponenten dieser Liste einzeln abgefragt werden.

Zeile 45: Die Namen der Zeilen und Spalten können jetzt für den Zugriff auf die Matrix-Elemente anstelle der doppelten Indizes eingesetzt werden; die eckigen Klammern müssen dennoch verwendet werden.

Aufgabe:

Im Beispiel oben wurde das Attribut dimnames mit Hilfe der replacement-Version von dimnames() gesetzt. Überprüfen Sie, ob sich das Attribut dimnames auch setzen lässt, indem man die Spalten- und Zeilen-Namen einzeln mit den replacement-Versionen von colnames() und rownames() setzt.

Setzen von dimnames mit der Funktion matrix()

Es gibt sogar noch eine weitere Möglichkeit, wie man das Attribut dimnames setzen kann: Die ersten hier vorgestellten Matrizen wurden mit der Funktion matrix() erzeugt; diese hat ein weiteres Argument, nämlich dimnames, mit dem man sofort beim Erzeugen das Attribut dimnames setzen kann. Dem Argument dimnames muss man dann wie im Beispiel oben (Zeile 22) eine Liste übergeben werden:

v <- as.vector(m)
v
# [1] 3 0 0 0 2 0 0 0 1

m1 <- matrix(data = v, nrow =  3, ncol = 3, dimnames = list(c("X1", "X2", "X3"), c("Y1", "Y2", "Y3")))
m1
# Y1 Y2 Y3
# X1  3  0  0
# X2  0  2  0
# X3  0  0  1

Aus der Diagonalmatrix m von oben wird der zugrundeliegende Vektor mit Hilfe von as.vector() erzeugt (Zeile 1). Dieser Vektor wird an die Funktion matrix() als Argument data übergeben; das Attribut dimnames wird in der Funktion matrix() durch die Liste gesetzt (Zeile 5).

An der Ausgabe von m1 sieht man, dass dieselbe Matrix wie im Beispiel oben entsteht.

Löschen von dimnames mit unname()

Bei Vektoren wurde schon die Funktion unname() vorgestellt. Mit ihr kann das Attribut names eines Vektors gelöscht werden; die Werte der Komponenten bleiben dabei unverändert. Für Matrizen und für Felder (array) löscht unname() das Attribut dimnames.

Wie bei den Vektoren wird durch den Aufruf von unname(obj = m) das Objekt m nicht verändert, sondern es wird ein neues Objekt erzeugt, das in allen Eigenschaften mit m übereinstimmt — bis auf das Attribut dimnames, das gleich NULL gesetzt wird. Das folgende Skript sollte sich damit von alleine erklären:

m <- diag((3:1))

m
# [,1] [,2] [,3]
# [1,]    3    0    0
# [2,]    0    2    0
# [3,]    0    0    1

dimnames(m) <- list(c("X1", "X2", "X3"), c("Y1", "Y2", "Y3"))

dimnames(m)
# [[1]]
# [1] "X1" "X2" "X3"
# 
# [[2]]
# [1] "Y1" "Y2" "Y3"

m
# Y1 Y2 Y3
# X1  3  0  0
# X2  0  2  0
# X3  0  0  1

n <- unname(m)
n
# [,1] [,2] [,3]
# [1,]    3    0    0
# [2,]    0    2    0
# [3,]    0    0    1

dimnames(n)
# NULL

m
# Y1 Y2 Y3
# X1  3  0  0
# X2  0  2  0
# X3  0  0  1

Zusammenfassung

Funktionen zum Erzeugen von Matrizen

Die folgende Tabelle zeigt Funktionen, mit denen Matrizen erzeugt werden können:

Funktion Beschreibung
matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) Erzeugen einer Matrix aus einem Vektor data; die Argumente nrow und ncol legen die Anzahl der Zeilen beziehungsweise Spalten fest, das Argument byrow gibt an, ob die Matrix zeilenweise oder spaltenweise mit Werten aufgefüllt wird; das Argument dimnames setzt das entsprechende Attribut (Namen für die Zeilen beziehungsweise Spalten).
diag(x = 1, nrow, ncol) Erzeugt eine Diagonalmatrix mit nrow Zeilen und nrow Spalten; wird für x ein Vektor vorgegeben, stehen dessen Komponenten auf der Hauptdiagonalen der Matrix.
lower.tri(x, diag = FALSE) Erzeugt eine untere Dreiecksmatrix (vom Modus "logical"), deren Zeilen- und Spalten-Anzahl mit der der Matrix x übereinstimmt. Unterhalb der Hauptdiagonalen steht jeweils TRUE, oberhalb der Hauptdiagonalen steht jeweils FALSE; das Argument diag bestimmt, welche Werte auf der Hauptdiagonalen stehen.
upper.tri(x, diag = FALSE) Erzeugt eine obere Dreiecksmatrix (vom Modus "logical"), deren Zeilen- und Spalten-Anzahl mit der der Matrix x übereinstimmt. Oberhalb der Hauptdiagonalen steht jeweils TRUE, unterhalb der Hauptdiagonalen steht jeweils FALSE; das Argument diag bestimmt, welche Werte auf der Hauptdiagonalen stehen.
col(x) Erzeugen einer Matrix, deren Elemente gerade gleich dem jeweiligen Spalten-Index sind; Zeilen- und Spalten-Anzahl ist wie bei der Matrix x.
row(x) Erzeugen einer Matrix, deren Elemente gerade gleich dem jeweiligen Zeilen-Index sind; Zeilen- und Spalten-Anzahl ist wie bei der Matrix x.
cbind(...) Mehrere Vektoren oder Matrizen werden spaltenweise aneinandergehängt.
rbind(...) Mehrere Vektoren oder Matrizen werden reihenweise aneinandergehängt.
outer(X, Y, FUN = "+") Von den Vektoren X und Y wird zuerst das Kreuzprodukt gebildet, anschließend werden die Komponenten mit der Funktion FUN verknüpft; der default-Wert für FUN ist die Addition.
as.matrix(x) Das Objekt x wird in eine Matrix verwandelt (ist x ein Vektor, wird eine Matrix mit einer Spalte erzeugt; die Funktion wird meist auf Data Frame angewendet).

Die folgende Tabelle beschreibt die Rückgabewerte der Funktionen und ihre Datentypen:

Funktion Rückgabewert Datentyp
matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) Der Vektor data wird als Matrix mit nrow Zeilen und ncol Spalten interpretiert. Das Attribut dim wird automatisch gesetzt, dimnames nur wenn es ausdrücklich gesetzt wird. Matrix
diag(x = 1, nrow, ncol) Diagonalmatrix mit nrow Zeilen und nrow Spalten; wird für x ein Vektor vorgegeben, stehen dessen Komponenten auf der Hauptdiagonalen der Matrix. Matrix
lower.tri(x, diag = FALSE) Untere Dreiecksmatrix (vom Modus "logical"), deren Zeilen- und Spalten-Anzahl mit der der Matrix x übereinstimmt. Unterhalb der Hauptdiagonalen steht jeweils TRUE, oberhalb der Hauptdiagonalen steht jeweils FALSE; das Argument diag bestimmt, welche Werte auf der Hauptdiagonalen stehen. Matrix
upper.tri(x, diag = FALSE) Obere Dreiecksmatrix (vom Modus "logical"), deren Zeilen- und Spalten-Anzahl mit der der Matrix x übereinstimmt. Oberhalb der Hauptdiagonalen steht jeweils TRUE, unterhalb der Hauptdiagonalen steht jeweils FALSE; das Argument diag bestimmt, welche Werte auf der Hauptdiagonalen stehen. Matrix
col(x) Matrix, deren Elemente gerade gleich dem jeweiligen Spalten-Index sind; Zeilen- und Spalten-Anzahl ist wie bei der Matrix x. Matrix
row(x) Matrix, deren Elemente gerade gleich dem jeweiligen Zeilen-Index sind; Zeilen- und Spalten-Anzahl ist wie bei der Matrix x. Matrix
cbind(...) Matrix, die dadurch entsteht, dass die Eingabewerte (Vektoren oder Matrizen) spaltenweise aneinandergehängt werden. Matrix
rbind(...) Matrix, die dadurch entsteht, dass die Eingabewerte (Vektoren oder Matrizen) zeilenweise aneinandergehängt werden. Matrix
outer(X, Y, FUN = "+") Matrix, deren Komponente [i, j] durch die Verknüpfung von X[i] und Y[j] durch die Funktion FUN gebildet wird. Matrix
as.matrix(x) Das Objekt x wird in eine Matrix verwandelt (ist x ein Vektor, wird eine Matrix mit einer Spalte erzeugt; die Funktion wird meist auf Data Frame angewendet). Matrix

Zugriff auf die Komponenten einer Matrix

Funktion Beschreibung
m[i, j] Zugriff auf die i-te Zeile und j-te Spalte der Matrix m
m[i, ] Zugriff auf die i-te Zeile der Matrix m
m[ ,j] Zugriff auf die j-te Spalte der Matrix m
m[i] Zugriff auf die i-te Komponente des Vektors, der der Matrix m zugrundeliegt.
?Extract Mehr Informationen über den Zugriff auf die Komponenten eines Objektes im package base unter Extract.

In der letzten Tabelle wurde beschrieben, wie der Zugriff auf Zeilen, Spalten oder einzelne Elemente einer Matrix erfolgt; dabei wurde angenommen, dass jeweils ein gültiger Index eingesetzt wird. Wird stattdessen ein negativer Index eingesetzt, wird das entsprechende Element aus der Matrix entfernt.

Die folgende Tabelle zeigt weitere Funktionen, mit denen auf Teile einer Matrix zugegriffen werden kann:

Funktion Beschreibung
head(x, n = 6L) Es wird eine Matrix erzeugt, die aus den ersten n Zeilen der Matrix x besteht. Ist n negativ, werden die letzten n Zeilen der Matrix gestrichen. (Der default-Wert für n ist 6.)
tail(x, n = 6L) Es wird eine Matrix erzeugt, die aus den letzten n Zeilen der Matrix x besteht. Ist n negativ, werden die ersten n Zeilen der Matrix gestrichen. (Der default-Wert für n ist 6.)
diag(x) Falls x eine Matrix ist, wird ein Vektor mit den Elementen der Hauptdiagonale von x erzeugt.

Die folgende Tabelle beschreibt die Rückgabewerte der Funktionen und ihre Datentypen:

Funktion Rückgabewert Datentyp
head(x, n = 6L) n positiv: Matrix, die aus den ersten n Zeilen von x besteht. n negativ: Matrix, wobei die letzten n Zeilen aus x gestrichen werden. (Der default-Wert für n ist 6.) Matrix
tail(x, n = 6L) n positiv: Matrix, die aus den letzten n Zeilen von x besteht. n negativ: Matrix, wobei die ersten n Zeilen aus x gestrichen werden. (Der default-Wert für n ist 6.) Matrix
diag(x) Falls x eine Matrix ist, wird ein Vektor mit den Elementen der Hauptdiagonale von x erzeugt. Vektor

Die Attribute dim und dimnames einer Matrix

Die folgende Tabelle zeigt Funktionen, mit denen die Attribute dim und dimnames gesetzt und abgefragt werden können sowie einige verwandte Funktionen:

Funktion Beschreibung
dim(x) Abfragen des Dimensionsvektors von x.
dim(x) <- value replacement-Version von dim() zum Setzen des Dimensions-Attributs mit dem Vektor value.
dimnames(x) Abfragen der Dimensions-Namen von x.
dimnames(x) <- value replacement-Version von dimnames() zum Setzen des Attributs dimnames mit der Liste value (der Aufbau dieser Liste ist durch den Dimensionsvektor vorgegeben).
rownames(x) Abfragen der Zeilen-Namen von x.
rownames(x) <- value replacement-Version von rownames() zum Setzen der Zeilen-Namen mit mit dem Vektor value (Die Länge von value muss mit der Anzahl der Zeilen von x übereinstimmen).
colnames(x) Abfragen der Spalten-Namen von x.
colnames(x) <- value replacement-Version von colnames() zum Setzen der Spalten-Namen mit mit dem Vektor value (Die Länge von value muss mit der Anzahl der Spalten von x übereinstimmen).
unname(x) Löschen des Attributes dimnames von x; dabei bleibt x unverändert und es wird ein neues Objekt zurückgegeben.

Die folgende Tabelle beschreibt die Rückgabewerte der Funktionen und ihre Datentypen:

Funktion Rückgabewert Datentyp
dim(x) Dimensionsvektors von x; falls x eine Matrix ist, hat er die Länge 2; die erste Komponente gibt die Anzahl der Zeilen an, die zweite Komponente die Anzahl der Spalten. Vektor der Länge 2
dim(x) <- value replacement-Version von dim() zum Setzen des Dimensions-Attributs mit dem Vektor value. kein Rückgabewert
dimnames(x) Dimensions-Namen von x. Liste mit zwei Komponenten; die erste Komponente ist ein character-Vektor mit den Namen der Zeilen, die zweite Komponente ein character-Vektor mit den Namen der Spalten. Liste
dimnames(x) <- value replacement-Version von dimnames() kein Rückgabewert
rownames(x) Zeilen-Namen von x: character-Vektor, dessen Länge mit der Anzahl der Zeilen übereinstimmt. character-Vektor
rownames(x) <- value replacement-Version von rownames() kein Rückgabewert
colnames(x) Spalten-Namen von x: character-Vektor, dessen Länge mit der Anzahl der Spalten übereinstimmt.. character-Vektor
colnames(x) <- value replacement-Version von colnames() kein Rückgabewert
unname(x) Matrix, die in allen Eigenschaften mit x übereinstimmt, nur das Attribut dimnames wurde NULL gesetzt. Matrix