Matrizen in R: Anwendungen

Vorgestellt wird, wie Matrizen miteinander verknüpft werden, welche Funktionen Eigenschaften von Matrizen anzeigen, sowie zahlreiche Funktionen aus der Linearen Algebra (Berechnung von Determinanten, Lösung von linearen Gleichungssystemen, Berechnung von transponierten und inversen Matrizen, Berechnung von Eigenwerten und Eigenvektoren).

Einordnung des Artikels

Operatoren und Funktionen für Matrizen

Eigenschaften einer Matrix

Zeilen- und Spalten-Anzahl einer Matrix

Wie schon beschrieben, wird eine Matrix intern wie ein Vektor behandelt, daher kann man mit Hilfe der Funktion length() die Anzahl der Elemente abfragen. Da aber zusätzlich die Elemente des Vektors in Zeilen und Spalten angeordnet werden, kann man auch deren Anzahl abfragen; die zugehörigen Funktionen lauten nrow() und ncol(). Ihren Einsatz zeigt das folgende Beispiel:

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

length(m)           # 12
nrow(m)             # 3
ncol(m)             # 4

Werden die Funktionen nrow() und ncol() auf einen Vektor angewendet, erhält man NULL. Für den Funktionen NROW() und NCOL() wird ein Vektor wie ein Spaltenvektor behandelt; angewendet auf Matrizen gibt es keinen Unterschied zwischen nrow() und NROW() beziehungsweise ncol() und NCOL():

# v und m wie im letzten Skript

nrow(v)         # NULL
ncol(v)         # NULL

NROW(v)         # 12
NCOL(v)         # 1

NROW(m)         # 3
NCOL(m)         # 4

Wie im obigen Beispiel gezeigt, können Zeilen- und Spaltenanzahl einzeln abgefragt werden. Mit Hilfe der Funktion dim() (Dimensionsvektor) können sie auch gleichzeitig ermittelt werden:

v <- (1:12)

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

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

length(m)       # 12
nrow(m)         # 3
ncol(m)         # 4

dim(m)
# [1] 3 4

Die erste Komponente des Dimensionsvektors ist somit die Reihen-Anzahl, die zweite Komponente die Spalten-Anzahl.

Diese Funktion dim() kann in ihrer replacement-Version dazu verwendet werden, um einem Vektor einen Dimensionsvektor zuzuordnen und ihn somit in eine Matrix zu verwandeln:

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

Man beachte:

  • Der Dimensionsvektor gibt zuerst die Zeilenanzahl und dann die Spaltenanzahl an (Zeile 5).
  • Dagegen wird die Matrix spaltenweise mit den Zahlen 1, 2, ..., 12 aufgefüllt (Zeile 7 bis 10), es entsteht also eine andere Matrix als mit der Anweisung, die bisher immer verwendet wurde – zum Vergleich:
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

Zeilen- und Spalten-Summen einer Matrix

Auch für die Berechnung von Zeilen- und Spaltensummen und sogar für deren Mittelwerte gibt es Funktionen, nämlich rowSums(), colSums(), rowMeans() und colMeans(); die Rückgabewerte der Funktionen sind Vektoren, deren Länge mir der Anzahl der Reihen beziehungsweise Spalten übereinstimmt:

m <- matrix((1:12), nrow = 3, byrow = TRUE)

rowSums(m)          # 10 26 42
colSums(m)          # 15 18 21 24

rowMeans(m)         # 2.5  6.5 10.5
colMeans(m)         # 5 6 7 8

Aufsuchen von identischen Spalten und Zeilen

Bei Vektoren wurde bereits die Funktion duplicated() vorgestellt: sie untersucht, ob in einem Vektor eine Komponente als Wiederholung vorkommt und verwandelt so den Vektor in einen logischen Vektor:

v <- c(1, 1, 2, 2)
duplicated(x = v)
# [1] FALSE TRUE FALSE TRUE

Die Funktion duplicated() kann auch auf Matrizen angewendet werden und hat dann durch ihr zusätzliches Argument MARGIN mehrere Anwendungsmöglichkeiten; man kann nämlich feststellen, ob

  • eine Zeile wiederholt wird (mit MARGIN = 1 , dies ist zugleich der default-Wert von MARGIN)
  • eine Spalte wiederholt wird (mit MARGIN = 2 ) oder
  • ein Element der Matrix wiederholt wird; dabei wird die Matrix spaltenweise gelesen (mit MARGIN = 0 ).

Das folgende Skript zeigt diese drei Anwendungen:

x <- c(1, 0, 1)
y <- c(1, 0, 1)
z <- c(1, 0, 2)

m <- cbind(x, y, z)
m
# x y z
# [1,] 1 1 1
# [2,] 0 0 0
# [3,] 1 1 2

# werden Zeilen wiederholt?
duplicated(x = m, MARGIN = 1)
# [1] FALSE FALSE FALSE

# werden Spalten wiederholt?
duplicated(x = m, MARGIN = 2)
# [1] FALSE  TRUE FALSE

x <- c(1, 2)
y <- c(2, 1)

m <- cbind(x, y)
m
# x y
# [1,] 1 2
# [2,] 2 1

# werden Elemente wiederholt? (spaltenweises Lesen der Matrix m)
duplicated(x = m, MARGIN = 0)
# x    y
# [1,] FALSE TRUE
# [2,] FALSE TRUE
# Beachte das Element [2, 1]: FALSE
# da spaltenweise gelesen wird, kommt diese 2 zum ersten Mal vor!

Man erkennt:

  • Für MARGIN = 1 und MARGIN = 2 ist der Rückgabewert ein logischer Vektor, der die Wiederholung von Zeilen beziehungsweise Spalten prüft.
  • Für MARGIN = 0 ist der Rückgabewert eine logische Matrix; die zu untersuchende Matrix wird spaltenweise gelesen und auf Wiederholung der Elemente untersucht; es wird eine logische Matrix mit identischen Dimensionen erzeugt.

Die Funktion which() bei Matrizen

Die Funktion which() wurde bereits für Vektoren vorgestellt (siehe Die Funktion which() in Vektoren in R: Anwendungen) und es wurde gezeigt, wie mit ihrer Hilfe Index-Vektoren gebildet werden. Für Matrizen (und allgemein für Felder) besitzt sie das weitere Argument arr.ind, das hier ausführlich vorgestellt wird.

Das folgende Skript zeigt nochmal die Eigenschaften der Funktion which() für Vektoren:

v <- c(1, 0, 1, 0)

iv.0 <- which(v == 0)
iv.0
# [1] 2 4

str(iv.0)
# int [1:2] 2 4

v[iv.0]
# [1] 0 0

Zur Erklärung:

Zeile 3 bis 5: Da v ein numerischer Vektor mit 4 Komponenten ist, verbirgt sich hinter v == 0 ein logischer Vektor mit (ebenfalls) 4 Komponenten. Der Vektor iv.0 gibt diejenigen Komponenten in v an, die den Wert 0 besitzen, also die zweite und vierte Komponente (siehe Ausgabe von iv.0 in Zeile 5). Ein Vektor wie iv.0 wird als Index-Vektor bezeichnet. Seine Werte sind eine Teilmenge der Indizes des Vektors v.

Zeile 7 und 8: Die Ausgabe der Struktur von iv.0 zeigt, dass es sich um einen Vektor mit 2 Komponenten und den Werten 2 und 4 handelt.

Zeile 10 und 11: Entscheidend zum Verständnis des Konzeptes Index-Vektor ist der Zugriff auf die Komponenten von v mit Hilfe des Index-Vektors iv.0: In den eckigen Klammern erwartet man vermutlich einen Index des Vektors v; ebenso kann ein Index-Vektor in die eckigen Klammern geschrieben werden. Der Vektor v wird an allen Komponenten ausgewertet, die der Index-Vektor iv.0 enthält – und so wie der Vektor iv.0 definiert war (Zeile 3), ist v dort immer gleich null. Da iv.0 zwei Komponenten hat, wird die 0 zweimal ausgegeben (Zeile 11). Oder abstrakter formuliert: Ein Index-Vektor besteht aus einer Teilmenge der Indizes eines Vektors v und man kann damit auf die zugehörige Teilmenge der Komponenten von v zugreifen.

Man kann das Konzept des Index-Vektors auf Matrizen übertragen, sollte hier aber besser von einer Index-Matrix sprechen; das folgende Skript zeigt ein ähnliches Beispiel wie oben:

# drei-dim Einheitsmatrix
e_3 <- diag(nrow = 3)

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

iv.1 <- which(e_3 == 1)

iv.1
# [1] 1 5 9

str(iv.1)
# int [1:3] 1 5 9

e_3[iv.1]
# [1] 1 1 1

Zur Erklärung:

Zeile 2: e_3 wird als die drei-dimensionale Einheitsmatrix definiert.

Zeile 10: Ähnlich wie im letzten Beispiel wird ein Index-Vektor zur Matrix e_3 definiert; der Vektor iv.1 soll diejenigen Elemente angeben, bei denen e_3 gleich 1 ist. Da e_3 eine Matrix ist, ist zunächst nicht klar, wie diese Elemente identifiziert werden.

Zeile 12 und 13: Die Ausgabe von iv.1 zeigt, dass der der Matrix e_3 zugrundeliegende Vektor (mit 9 Komponenten) verwendet wird; die Hauptdiagonale in e_3 hat darin die Indizes 1, 5 und 9.

Zeile 15 und 16: Die Ausgabe der Struktur von iv.1 zeigt, dass es sich um einen integer-Vektor mit 3 Komponenten und den Werten 1, 5 und 9 handelt.

Zeile 18 und 19: Entscheidend ist wieder der Zugriff auf die Matrix e_3 mit Hilfe des Index-Vektors iv.1 in Zeile 18: es ensteht dreimal die 1.

Gerade bei großen Matrizen ist es sehr mühsam, mit den Indizes des zugrundeliegenden Vektors zu arbeiten, und man möchte lieber die Zeilen- und Spalten-Indizes verwenden. Dazu gibt es die Möglichkeit, beim Aufruf der Funktion which() das Argument arr.ind zu setzen: jetzt wird anstelle eines Index-Vektors eine Index-Matrix gebildet – genauer eine Matrix, in der sofort die gesuchten Komponenten der Matrix e_3 durch eine Zeilen- und Spalten-Angabe charakterisiert werden.

Das folgende Skript identifiziert wieder die Elemente von e3, die gleich 1 sind, definiert den Index-Vektor (eigentlich: Index-Matrix) aber mit arr.ind == TRUE im Aufruf von which()_:

# drei-dim Einheitsmatrix
e_3 <- diag(nrow = 3)

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

iv.1 <- which(e_3 == 1, arr.ind = TRUE)
iv.1
# row col
# [1,]   1   1
# [2,]   2   2
# [3,]   3   3

str(iv.1)
# int [1:3, 1:2] 1 2 3 1 2 3
# - attr(*, "dimnames")=List of 2
# ..$ : NULL
# ..$ : chr [1:2] "row" "col"

dim(iv.1)
# [1] 3 2

is.matrix(iv.1)
# [1] TRUE

e_3[iv.1]
# [1] 1 1 1

Zur Erklärung:

Zeile 1 bis 8: bedarf keiner Erklärung, da alle Schritte identisch sind wie im Skript oben.

Zeile 10: Neu ist, dass beim Aufruf von which() das Argument arr.ind == TRUE gesetzt wird.

Zeile 11 bis 15: Man erkennt an der Ausgabe des Index-Vektors iv.1:

  • Es gibt 3 Elemente in e_3, die den Wert 1 besitzen.
  • Diese drei Elemente werden durch die Angabe eines Zeilen-Index (row) und eines Spalten-Index (col) charakterisiert.
  • Die Elemente befinden sich genau auf der Hauptdiagonale: (1, 1), (2, 2), (3, 3).

Zeile 17: Die Ausgabe der Struktur von iv.1 ist jetzt deutlich komplizierter:

  • Es handelt sich um eine Matrix mit 3 Zeilen und 2 Spalten.
  • Das Attribut dimnames ist gesetzt, allerdings nicht für die Zeilen, sondern nur für die beiden Spalten (nämlich "row" und "col").

Zeile 23: Der Dimensionsvektor zeigt, dass iv.1 eine Matrix ist, die 3 Zeilen und 2 Spalten besitzt.

Zeile 26: Es handelt sich bei iv.1 jetzt tatsächlich um eine Matrix (und keinen Vektor).

Zeile 29: Die entscheidende Zeile ist wieder der Zugriff auf die Komponenten von e_3 mit dem Index-Vektor iv.1. Der Zugriff ist möglich und liefert dreimal den Wert 1.

Elementare Operationen

Im Kapitel Vektoren in R: Anwendungen wurde im Abschnitt Punktweise Ausführung von Operationen und der recycling-Mechanismus der für die Sprache R typische Mechanismus vorgestellt, wie Operationen ausgeführt werden, wenn die Vektor-Längen eigentlich nicht zusammenpassen. Die Kenntnis dieses Abschnitts wird vorausgesetzt, wenn jetzt die Operationen mit Matrizen besprochen werden.

Bei Matrizen ist wie bei Vektoren zu beachten, dass die meisten Operationen komponentenweise ausgeführt werden. Es kann daher leicht vorkommen, dass eine Operation in R anders als erwartet ausgeführt wird. Man sollte daher die folgenden Beispiele unbedingt zur Kenntnis nehmen, bevor man eine Anwendung schreibt, in der Operationen mit Matrizen vorkommen.

Behandelt werden in diesem Unterabschnitt:

  1. Die Addition zweier Matrizen
  2. Die Multiplikation einer Matrix mit einem Skalar
  3. Die komponentenweise Multiplikation und Division zweier Matrizen
  4. Die Matrizenmultiplikation.
  5. Prüfung auf näherungsweise Gleichheit

Die Addition zweier Matrizen

In der Mathematik ist die Addition zweier Matrizen nur dann erlaubt, wenn sie in Reihen- und Spaltenanzahl übereinstimmen. In R kann man die Addition mit dem Operator + ausführen:

m1 <- matrix((1:12), nrow = 3, byrow = TRUE)
m2 <- matrix((12:1), nrow = 3, byrow = TRUE)

m <- m1 + m2            # Addition von Matrizen
m
     [,1] [,2] [,3] [,4]
[1,]   13   13   13   13
[2,]   13   13   13   13
[3,]   13   13   13   13

Bei der Anwendung der Addition muss man aber bedenken, dass sie in R auch möglich ist, wenn die Einschränkung die Matrizen müssen in Reihen- und Spaltenanzahl übereinstimmen nicht erfüllt ist. Das folgende Skript zeigt einige Beispiele:

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

m1 <- m + 1             # 1 wird zu jedem Element der Matrix m addiert
m1
     [,1] [,2] [,3] [,4]
[1,]    2    3    4    5
[2,]    6    7    8    9
[3,]   10   11   12   13

m2 <- matrix((1:8), nrow = 2, byrow = TRUE)

m3 <- m + m2            # Fehler
m3
Error in m + m2 : non-conformable arrays

v <- (1:4)              # v wird als Spaltenvektor behandelt
v
[1] 1 2 3 4

m3 <- m + v             # recycle: v passt nicht zu m und wird daher wiederholt (aber als Spaltenvektor)
m3
     [,1] [,2] [,3] [,4]
[1,]    2    6    6    6
[2,]    7    7   11   11
[3,]   12   12   12   16

Zur Erklärung:

Zeile 8: Die Addition einer Matrix und eines Skalares m1 <- m + 1 ist möglich; der Skalar (hier 1) wird zu jeder Komponente der Matrix addiert. Man könnte das Ergebnis auch mit dem recycling-Mechanismus interpretieren: der Skalar zu einer Matrix mit denselben Dimensionen wie m erweitert und dann wird die übliche Addition von Matrizen ausgeführt.

Zeile 17: Die beiden Matrizen auf der rechten Seite in m3 <- m + m2 können in der Mathematik nicht adddiert werden. Sie stimmen zwar in der Spalten-Anzahl aber nicht in der Zeilen-Anzahl überein. In R erhält man hier eine Fehlermeldung.

Zeile 25: Das letzte Beispiel m3 <- m + v soll als Warnung dienen und zeigen, dass in R bei der Verknüpfung von Vektoren oder Matrizen Dinge geschehen können, die man in der Mathematik nicht erwartet. Der Vektor v hat die Länge 4, also gerade die Anzahl der Spalten von m. Man wird hier vermutlich eine der folgenden Möglichkeiten erwarten:

  • Entweder die Addition ist nicht möglich (wie im Beispiel Zeile 17), da m und v – als Matrizen interpretiert – in ihrer Zeilen- und Spalten-Anzahl nicht übereinstimmen.
  • Oder der recycling-Mechanismus wird ähnlich wie in Zeile 8 angewendet. Man wird dann erwarten, dass jede Zeile von m und v addiert werden (da die Spalten-Anzahlen übereinstimmen).

Die Ausgabe (Zeile 27 bis 30) zeigt aber, dass die Matrix m spaltenweise durchlaufen wird und dabei v wiederholt wird (recycling-Mechanismus). Man erhält dabei keine Warnung, weil die 4 Komponenten von v mit den 12 Komponenten von m verträglich sind.

Die Multiplikation einer Matrix mit einem Skalar

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

m4 <- 4 * m         # jedes Element von m wird mit 4 multipliziert
m4
     [,1] [,2] [,3] [,4]
[1,]    4    8   12   16
[2,]   20   24   28   32
[3,]   36   40   44   48

Das Beispiel ist sofort verständlich, wenn man bedenkt, dass in R ein Skalar ein Spezialfall eines Vektors ist, nämlich eines Vektors der Länge 1. Die Wiederholung des Vektors sorgt dafür, dass jedes Element der Matrix mit dem Faktor 4 multipliziert wird.

Die komponentenweise Multiplikation und Division zweier Matrizen

Sie ist die Verallgemeinerung der Multiplikation einer Matrix mit einem Skalar und wird an zwei Beispielen verdeutlicht.

Im ersten Beispiel ist zu sehen, was passiert, wenn anstelle des Skalares 4 (aus dem letzten Beispiel) die Matrix m mit einem echten Vektor multipliziert wird (hier ein Vektor der Länge 2):

m5 <- (1:2) * m         # recycle: Der Vektor (1:2) wird wieder als Spaltenvektor aufgefasst
m5
     [,1] [,2] [,3] [,4]
[1,]    1    4    3    8
[2,]   10    6   14    8
[3,]    9   20   11   24

Das Beispiel wird erst verständlich, wenn man weiß, dass in R Vektoren – sofern nichts weiter angegeben ist – immer als Spaltenvektoren aufgefasst werden. Es wird also die aus (1:2) gebildete Spalte wiederholt und elementweise mit der Matrix m multipliziert.

Im zweiten Beispiel werden zwei Matrizen mit dem Operator * multipliziert: die beiden Matrizen werden elementweise multipliziert.

m6 <- m * m         # elementweise Multiplikation &ndash; dies ist NICHT die Matrizen-Multiplikation
m6
    [,1] [,2] [,3] [,4]
[1,]    1    4    9   16
[2,]   25   36   49   64
[3,]   81  100  121  144

Man beachte, dass in R die Multiplikation zweier Matrizen mit dem Operator * nicht die Matrizen-Multiplikation ist.

Anstelle der Multiplikation kann natürlich auch

  • die Division /
  • die Ganzzahl-Division %/% und
  • die Berechnung des Restes %%

als Operator zwischen zwei Matrizen eingesetzt werden.

Aufgabe:

Geben Sie geeignete Beispiele zu den letztgenannten Operationen an.

Die Matrizenmultiplikation

Sie erfolgt mit dem Operator %*% .

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_3 <- diag(3:1)
m_3
        [,1] [,2] [,3]
[1,]    3    0    0
[2,]    0    2    0
[3,]    0    0    1

m_3 %*% m           # Matrizen-Multiplikation ist möglich
         [,1] [,2] [,3] [,4]
[1,]    3    6    9   12
[2,]   10   12   14   16
[3,]    9   10   11   12

m %*% m_3           # Fehler! Matrizen-Multiplikation ist NICHT möglich
Error in m %*% m_3 : non-conformable arguments

Die spezielle Wahl von m_3 sorgt dafür, dass die erste Zeile von m mit 3, die zweite Zeile von m mit zwei und die dritte Zeile mit 1 multipliziert wird (siehe Ausgabe Zeile 14 bis 18).

Die Matrizen-Multiplikation in der umgekehrten Reihenfolge (Zeile 20) ist nicht möglich; man erhält die entsprechende Fehlermeldung.

Wie man mit Hilfe der Matrizen-Multiplikation das Skalarprodukt zweier Vektoren berechnet, wird im Abschnitt zur Linearen Algebra gezeigt.

Statistische Funktionen

Im Kapitel über die Anwendungen von Vektoren wurden bereits statistische Funktionen besprochen, die als Eingabewert einen Vektor (oder zwei Vektoren) erhalten:

  • die Standardabweichung
  • die Varianz
  • die Kovarianz
  • der Korrelationskoeffizient.

Die folgenden Unterabschnitte zeigen, wie diese Funktionen verallgemeinert werden, wenn als Eingabewert eine Matrix (oder zwei Matrizen) verwendet wird.

Die Standardabweichung

Die Funktion sd() zur Berechnung der Standardabweichung ist tatsächlich nur für einen Vektor als Eingabewert sinnvoll definiert. Übergibt man ihr dennoch eine Matrix, so wird der zugrundeliegende Vektor verwendet und davon die Standardabweichung berechnet.

Die Varianz

Für die Varianz var(x, y = NULL) gilt alles, was sogleich für die Kovarianz gesagt wird. Dies ist allerdings mit der Einschränkung gültig, dass nur die beiden Argumente x und y (oder nur x) gesetzt werden; die Varianz var(x, y = NULL) und die Kovarianz cov(x, y = NULL) besitzen noch weitere Argumente, in denen sie sich unterscheiden – diese Argumente werden hier aber nicht besprochen.

Die Kovarianz

Die Kovarianz cov(x, y = NULL) könnte den Eindruck erwecken, dass man mit ihr lediglich die Kovarianz zwischen zwei Vektoren x und y berechnen kann; im Fall, dass y nicht gesetzt wird, wird var(x) berechnet. Da die Kovarianz auch für Matrizen x und y als Eingabewerte definiert ist, kann man mit der Funktion cov(x) durch eine Anweisung die Kovarianzen zwischen beliebig vielen Vektoren berechnen. Das folgende Beispiel soll dies für drei Vektoren demonstrieren.

Zunächst werden drei Vektoren definiert:

x = (1, 0, -1)

y = (1, 0, 1)

z = (1, 0, 2)

Die drei Vektoren werden zu einer Matrix m zusammengefasst (dazu wird die Funktion cbind() verwendet).

Für diese Matrix wird cov(m) berechnet (mit digits = 3):

x <- c(1, 0, -1)
y <- c(1, 0, 1)
z <- c(1, 0, 2)

m <- cbind(x, y, z)
m
# x y z
# [1,]  1 1 1
# [2,]  0 0 0
# [3,] -1 1 2

print(x = cov(m), digits = 3)
# x     y    z
# x  1.0 0.000 -0.5
# y  0.0 0.333  0.5
# z -0.5 0.500  1.0

Vergleicht man die Ausgabe von m mit der von cov(m), kann man schnell erraten, welche Berechnungen hier durchgeführt wurden: Durch die Verwendung von cbind() werden die drei Vektoren als Spaltenvektoren aufgefasst (die Zeilen verfügen über kein Attribut dimnames, die Spalten besitzen die Namen "x", "y" und "z").

Bei der Berechnung von cov(m) entsteht wieder eine 3 × 3 Matrix, die jetzt aber für Zeilen und Spalten dimnames gesetzt hat.

Auf der Hauptdiagonalen dieser Matrix stehen var(x) , var(y) und var(z) , die Nebendiagonaleinträge sind die Kovarianzen cov(x, y) == cov(y, x) , cov(x, z) == cov(z, x) und cov(y, z) == cov(z, y) .

Das folgende Skript berechnet diese Größen ausdrücklich – man muss dabei beachten, dass die Varianz und die Kovarianz mit dem Nenner n-1 (anstelle von n) berechnet werden:

x <- c(1, 0, -1)
y <- c(1, 0, 1)
z <- c(1, 0, 2)

# Hauptdiagonale von cov(m):
var(x)
# [1] 1
var(y)
# [1] 0.3333333
var(z)
# [1] 1

# Nebendiagonale von cov(m):
cov(x, y)
# [1] 0

cov(x, z)
# [1] -0.5

cov(y, z)
# [1] 0.5

Welche Kovarianzen werden berechnet, wenn der Funktion cov() tatsächlich zwei Argumente übergeben werden?

Das folgende Skript gibt die Antwort – um die Berechnung leichter nachvollziehbar zu machen, werden für das zweite Argument (die Matrix n) die Namen "a", "b" und "c" gesetzt. An der Ausgabe erkennt man leicht, welche Kovarianzen in der Ausgabe-Matrix enthalten sind:

# m wie oben:
m
# x y z
# [1,]  1 1 1
# [2,]  0 0 0
# [3,] -1 1 2

n <- cbind(a = x, b = 2*y, c = 3*z)
n
# a b c
# [1,]  1 2 3
# [2,]  0 0 0
# [3,] -1 2 6

print(cov(x = m, y = n), digits = 3)
# a     b    c
# x  1.0 0.000 -1.5
# y  0.0 0.667  1.5
# z -0.5 1.000  3.0

Aufgabe:

Formulieren Sie, welche Kovarianzen hier berechnet wurden und überprüfen Sie Ihre Vermutung durch die direkte Berechnung der entsprechenden Kovarianzen.

Der Korrelationskoeffizient

Die Funktion zur Berechnung des Korrelationskoeffizienten cor(x, y = NULL) besitzt dieselben Eingabewerte wie die Kovarianz. Alles was oben zur Berechnung der Kovarianz für Matrizen als Eingabewerte gesagt wurde überträgt sich entsprechend für den Korrelationskoeffizienten.

Im Beispiel oben wurden die Vektoren a, b, c als Vielfache von x, y, z gewählt (siehe Definition der Matrix n durch n <- cbind(a = x, b = 2*y, c = 3*z) ); die entsprechenden Korrelationskoeffizienten (also cor(x, a) == cor(a, x) , cor(y, b) == cor(b, y) und cor(z, c) == cor(c, z) ) müssen daher gleich 1 sein. Durch die Anweisung cor(x = m, y = n) werden diese und weitere Korrelationskoeffizienten berechnet:

# Matrizen m und n wie im Skript oben

print(cor(x = m, y = n), digits = 3)
# a     b      c
# x  1.0 0.000 -0.500
# y  0.0 1.000  0.866
# z -0.5 0.866  1.000

Aufgabe:

Formulieren Sie, welche Korrelationskoeffizienten im letzten Skript berechnet wurden und überprüfen Sie dies, indem Sie die Korrelationskoeffizienten direkt aus den Vektoren berechnen.

Lineare Algebra mit R

Die wichtigsten Operationen der Linearen Algebra sind in R vorbereitet:

  1. Test einer Matrix auf Symmetrie.
  2. Berechnung von Determinanten
  3. Lösung von linearen Gleichungssystemen
  4. Berechnung der inversen Matrix
  5. Berechnung der Eigenwerte und Eigenvektoren einer Matrix.
  6. Die transponierte Matrix
  7. Berechnung des Skalarproduktes zweier Vektoren
  8. Die Funktionen crossprod() und tcrossprod().

Test einer Matrix auf Symmetrie

Um zu definieren, was Symmetrie bei Matrizen bedeutet, muss man unterscheiden, ob man mit reellen oder mit komplexen Zahlen rechnet.

Bei reellen Matrizen bedeutet Symmetrie, dass eine Matrix, die an ihrer Hauptdiagonalen gespiegelt wird, mit sich selbst übereinstimmt. Dies impliziert insbesondere, dass die Matrix quadratisch sein muss. Einfachste Beispiele sind die Einheitsmatrix oder eine quadratische Diagonalmatrix.

Bei komplexen Matrizen wird symmetrisch üblicherweise mit hermitesch gleichgesetzt. Dies bedeutet, dass bei Spiegelung an der Hauptdiagonalen die konjugiert komplexe Matrix entsteht. Da hier keine komplexen Zahlen untersucht werden, wird dies nicht weiter verfolgt.

In R kommt beim Begriff der Symmetrie einer Matrix eine weitere Komplikation hinzu: Ist das Attribut dimnames gesetzt, so wird beim Test auf Symmetrie auch getestet, ob die Namen der Zeilen und Spalten übereinstimmen. Möchte man nur die Zahlen vergleichen und die dimnames ignorieren, kann man unname() die dimnames beseitigen.

Der Test auf Symmetrie erfolgt mit der Funktion isSymmetric(); dr Rückgabewert ist ein logischer Wert. Das folgende Skript zeigt einige einfache Beispiele:

# quadratische Matrix
m_3 <- diag(x = (3:1))

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

isSymmetric(m_3)
# [1] TRUE

# rechteckige Matrix:
m_3_4 <- diag(x = (3:1), nrow = 3, ncol = 4)

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

isSymmetric(m_3_4)
# [1] FALSE


# quadratische Matrix mit (nicht-symmetrischen) dimnames:
m <- diag((3:1))

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

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

isSymmetric(m)
# [1] FALSE

isSymmetric(unname(m))

# [1] TRUE

Berechnung von Determinanten

Für quadratische Matrizen (also Zeilen- und Spaltenanzahl sind identisch) kann mit Hilfe der Funktion det() die Determinante berechnet werden:

m_3 <- diag(3:1)
det(m_3)            # 6 (Produkt der Hauptdiagonlelemente)

m <- matrix((1:12), nrow = 3, byrow = TRUE)         # 4x3 Matrix: Determinante ist nicht definiert
det(m)          # Fehler
Error in determinant.matrix(x, logarithm = TRUE, ...) : 
  'x' muss eine quadratische Matrix sein

Für nicht-quadratische Matrizen (Zeile 4 und 5) erhält man eine Fehlermeldung (siehe Zeile 6 und 7).

Lösung von linearen Gleichungssystemen

Zahlreiche Probleme aus der Mathematik lassen sich auf die Lösung eines linearen Gleichungssystems zurückführen, das meist in der Form

A · x = b

gegeben ist, wobei A die Koeffizientenmatrix ist, b die rechte Seite des Gleichungssystems und x die gesuchte Lösung. Falls A eine quadratische n × n Matrix ist, haben b und x identische Länge, nämlich n. Im Allgemeinen ist A eine m × n Matrix und dann hat b die Länge m (Anzahl der Zeilen von A) und x die Länge n (Anzahl der Spalten von A).

Aus der Mathematik ist bekannt, dass bei der Lösung eines linearen Gleichungssystemen drei Fälle zu unterscheiden sind:

  1. Es gibt eine eindeutige Lösung des Gleichungssystems
  2. Es gibt unendlich viele Lösungen (wobei man über die Dimension des Lösungsraumes noch genauere Angaben machen könnte)
  3. Es gibt keine Lösung.

Wie an den folgenden Beispielen zu sehen ist, kann die Funktion solve(a, b) nicht zwischen dem zweiten und dritten Fall unterscheiden; in beiden Fällen wird eine identische Fehlermeldung ausgegeben. Daher wäre es auch nicht sinnvoll, für die Koeffizientenmatrix A nicht-quadratische Matrizen zuzulassen. Gibt man dennoch eine nicht-quadratische Koeffizientenmatrix A vor, erhält man eine Fehlermeldung (Beispiel siehe unten).

Es sollen nun einfache Beispiele vorgestellt werden – so einfach, dass man sie im Kopf lösen kann –, um zu zeigen, wie man ein lineares Gleichungssystem mit Hilfe von R löst und wie die oben genannten drei Fälle angezeigt werden (genauer gesagt kann unterschieden werden, ob der erste Fall vorliegt oder nicht).

1. Beispiel: Ein lineares Gleichungssystem mit einer eindeutigen Lösung

Das lineare Gleichungssystem in Abbildung 1 (Gleichung 1) besitzt die eindeutige Lösung in Gleichung 2.

Abbildung 1: Gleichungssystem mit 3 Gleichungen und drei Unbekannten (Gleichung 1) mit eindeutiger Lösung (Gleichung 2).Abbildung 1: Gleichungssystem mit 3 Gleichungen und drei Unbekannten (Gleichung 1) mit eindeutiger Lösung (Gleichung 2).

In R wird die Lösung mit Hilfe der Funktion solve() berechnet, wie das folgende Skript zeigt:

A <- diag(3:1)

b <- rep(1, times = 3)

x <- solve(a = A,b = b)
x
[1] 0.3333333 0.5000000 1.0000000

Das Beispiel soll nochmals daran erinnern, dass es bei derartigen Berechnungen immer zu Rundungsfehlern kommen kann; die Ausgabe erfolgt hier mit der default-Einstellung von 7 gültigen Stellen.

2. Beispiel: Ein lineares Gleichungssystem mit unendlich vielen Lösungen

Das lineare Gleichungssystem aus Abbildung 2 (Gleichung 1) besitzt offensichtlich unendlich viele Lösungen (Gleichung 2), da die dritte Gleichung des Gleichungssystems für alle reellen Zahlen x3 erfüllt ist.

Abbildung 2: Gleichungssystem mit 3 Gleichungen und drei Unbekannten (Gleichung 1) mit unendlich vielen Lösungen (Gleichung 2).Abbildung 2: Gleichungssystem mit 3 Gleichungen und drei Unbekannten (Gleichung 1) mit unendlich vielen Lösungen (Gleichung 2).

Die Berechnung der Lösung mit R lautet:

A <- diag(c(3, 2, 0))

b <- c(1, 1, 0)

x <- solve(a = A,b = b)
x
# Error in solve.default(A, b) : 
#   Lapack routine dgesv: system is exactly singular: U[3,3] = 0

Man sieht allerdings, dass die unendlich vielen Lösungen nicht bewältigt werden!

3. Beispiel: Ein lineares Gleichungssystem ohne Lösung

Das lineare Gleichungssystem aus Abbildung 3 (Gleichung 1) besitzt keine Lösung, da die dritte Gleichung nicht erfüllt werden kann.

Abbildung 3: Gleichungssystem mit 3 Gleichungen und drei Unbekannten (Gleichung 1), das keine Lösung besitzt (Lösungsmenge ist die leere Menge, Gleichung 2).Abbildung 3: Gleichungssystem mit 3 Gleichungen und drei Unbekannten (Gleichung 1), das keine Lösung besitzt (Lösungsmenge ist die leere Menge, Gleichung 2).

Die Simulation in R lautet:

A <- diag(c(3, 2, 0))

b <- c(1, 1, 1)

x <- solve(a = A,b = b)
x
# Error in solve.default(A, b) : 
#   Lapack routine dgesv: system is exactly singular: U[3,3] = 0

Auch hier liefert R eine Fehlermeldung, aber man kann die beiden Fälle (unendlich viele Lösungen beziehungsweise keine Lösung) nicht unterscheiden.

4. Beispiel: Ein lineares Gleichungssystem mit nicht-quadratischer Koeffizientenmatrix

Wie oben schon gesagt wurde, darf die Funktion solve(a, b) nur mit einer quadratischen Koeffizientenmatrix a aufgerufen werden. Im folgenden Beispiel wird zunächst eine nicht-quadratische Koeffizientenmatrix a definiert und anschließend solve(a, b) aufgerufen:

A <- diag(c(3, 2, 0))
A <- cbind(A, c(0, 0, 1))

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

b <- c(1, 1, 1)

x <- solve(a = A,b = b)
# Error in solve.default(A, b) : 'a' (3 x 4) must be square

Berechnung der inversen Matrix

Die Funktion solve() kann auch dazu verwendet werden, eine inverse Matrix zu berechnen; dazu wird die Funktion allein mit der Matrix (also ohne die rechte Seite b des Gleichungssystems) aufgerufen:

A <- diag(c(3, 2, 1))
A_inv <- solve(a = A)
A_inv
          [,1] [,2] [,3]
[1,] 0.3333333  0.0    0
[2,] 0.0000000  0.5    0
[3,] 0.0000000  0.0    1

Abbildung 4 zeigt in Gleichung 1 die Matrix und deren inverse Matrix, die im Skript oben berechnet wurde.

Abbildung 4: Beispiel für eine Matrix A und ihrer inversen Matrix (Gleichung 1) sowie einer singulären Matrix (Gleichung 2).Abbildung 4: Beispiel für eine Matrix A und ihrer inversen Matrix (Gleichung 1) sowie einer singulären Matrix (Gleichung 2).

In Gleichung 2 in Abbildung 4 ist eine singuläre Matrix zu sehen, also eine Matrix, deren Determinante gleich null ist und die somit keine Inverse besitzt. Versucht man hier die inverse Matrix zu berechnen, erhält man eine Fehlermeldung:

A <- matrix(rep(1, times = 4), nrow = 2, byrow = TRUE)
A_inv <- solve(a = A)
A_inv
Error in solve.default(A) : 
  Lapack routine dgesv: system is exactly singular: U[2,2] = 0

Berechnung der Eigenwerte und Eigenvektoren einer Matrix

In den folgenden Skripte werden Listen verwendet, die erst in einem späteren Kapitel erklärt werden; da aber – aus der Sicht der Mathematik – klar sein sollte, welche Berechnungen hier durchgeführt werden, werden die Eigenschaften von Listen hier noch nicht erklärt.

1. Beispiel:

Die Matrix A in Gleichung 1 in Abbildung 5 besitzt drei verschiedene Eigenwerte (Gleichung 2) und zugehörige eindimensionale Eigenräume, die durch die Eigenvektoren in Gleichung 3 ausgedrückt werden (jeder Eigenvektor kann mit einem beliebigen Faktor multipliziert werden und ist dann immer noch Eigenvektor).

Abbildung 5: Gleichung 1 zeigt eine Matrix A und die zugehörige Eigenwert-Gleichung. Die Eigenwerte sind in Gleichung 2 zu sehen, die Eigenvektoren (Einheitsvektoren in Richtung der Koordinatenachsen) in Gleichung 3.Abbildung 5: Gleichung 1 zeigt eine Matrix A und die zugehörige Eigenwert-Gleichung. Die Eigenwerte sind in Gleichung 2 zu sehen, die Eigenvektoren (Einheitsvektoren in Richtung der Koordinatenachsen) in Gleichung 3.

Das folgende Skript zeigt, wie sich Eigenwerte und Eigenvektoren mit Hilfe von R berechnen und ausgeben lassen:

A <- diag(c(3, 2, 1))
ev <- eigen(x = A)

# Eigenwerte:
ev$val
[1] 3 2 1

# Eigenvektoren:
ev$vec
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    1    0
[3,]    0    0    1

Die Funktion eigen() berechnet sowohl die Eigenwerte als auch die Eigenvektoren (Zeile 2). Das Ergebnis dieser Berechnung wird hier in der Variable ev abgespeichert. Der Zugriff auf die Eigenwerte (Zeile 5) und die Eigenvektoren (Zeile 9) erfolgt dann mit Hilfe des Dollar-Zeichens. Die Variable ev, also der Rückgabewert der Funktion eigen(), ist vom Datentyp Liste – die Syntax hierfür und wie das Dollar-Zeichen eingesetzt wird, werden später im Kapitel über Listen erklärt.

2. Beispiel:

Abbildung 6 zeigt eine Matrix A, bei der der Eigenraum zum Eigenwert 2 zweidimensional ist; der Eigenvektor zum Eigenwert 1 ist wie im Beispiel oben der Vektor e3.

Abbildung 6: Matrix mit einem zweidimensionalen Eigenraum (zum Eigenwert 2).Abbildung 6: Matrix mit einem zweidimensionalen Eigenraum (zum Eigenwert 2).

R liefert hier die Ausgabe:

A <- diag(c(2, 2, 1))
ev <- eigen(x = A)

# Eigenwerte:
ev$val
[1] 2 2 1

# Eigenvektoren:
ev$vec
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    1    0
[3,]    0    0    1

3. Beispiel:

Zuletzt noch ein nicht Beispiel, bei dem man die Eigenwerte und Eigenvektoren nicht erraten kann. Abbildung 7 zeigt eine 2×2-Matrix A (Gleichung 1), ihre Eigenwerte (Gleichung 2) und Eigenvektoren (Gleichung 3).

Abbildung 7: Matrix A (Gleichung 1) mit ihren Eigenwerten (Gleichung 2) und Eigenvektoren (Gleichung 3).Abbildung 7: Matrix A (Gleichung 1) mit ihren Eigenwerten (Gleichung 2) und Eigenvektoren (Gleichung 3).

Es ist klar, dass die Darstellung der Eigenvektoren nicht eindeutig ist, da sich hinter dem Eigenvektor eigentlich ein Eigenraum verbirgt, der Eigenvektor also mit einem beliebigen Faktor multipliziert werden darf.

Das folgende Skript zeigt die Berechnung der Eigenwerte und Eigenvektoren zur Matrix A aus Gleichung 1.

A <- matrix(c(1,1,1,-1), nrow = 2, byrow = TRUE)
ev <- eigen(x = A)

# Eigenwerte:
ev$val
[1] 1.414214 -1.414214

# Eigenvektoren:
ev$vec
           [,1]       [,2]
[1,] -0.9238795  0.3826834
[2,] -0.3826834 -0.9238795

Die folgende Kontrollrechnung zeigt, dass die Eigenvektoren normiert ausgegeben werden:

ev$vec[1,1]^2 + ev$vec[2,1]^2 # 1

Die transponierte Matrix

In der linearen Algebra benötigt man häufig die sogenannte transponierte Matrix Aτ zu einer gegebenen Matrix A. Die transponierte Matrix entsteht, wenn in A Zeilen und Spalten vertauscht werden. Abbildung 8 zeigt ein Beispiel.

Abbildung 8: Matrix A und ihre transponierte Matrix (Gleichung 1).Abbildung 8: Matrix A und ihre transponierte Matrix (Gleichung 1).

In R wird die transponierte Matrix mit Hilfe der Funktion t() gebildet:

A <- matrix(c(1,-1,1,1), nrow = 2, byrow = TRUE)
A
     [,1] [,2]
[1,]    1   -1
[2,]    1    1

t(x = A)
    [,1] [,2]
[1,]    1    1
[2,]   -1    1

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

t(x = B)
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

Das Skalarprodukt zweier Vektoren

Das Skalarprodukt ist ein Spezialfall der Matrizen-Multiplikation. Im Kapitel über Vektoren wurde bereits gezeigt, wie man das Skalarprodukt auf die punktweise Multiplikation zweier Vektoren und die Funktion sum() zurückführen kann (siehe Das Skalarprodukt zweier Vektoren in Vektoren in R: Anwendungen):

u <- c(1, 3, 5)
v <- c(2, 0, -2)
sum(u * v)          # -8

Berechnet man damit das Skalarprodukt zweier Vektoren unterschiedlicher Länge, wird wieder der kürzere Vektor wiederholt und man erhält eine Warnung:

u <- c(1, 3, 5)
w <- rep(1, times = 5)
sum(u * w)          # 13
# Warning message:
# In u * w : longer object length is not a multiple of shorter object length

Es wird also berechnet:

(1, 3, 5) · (1, 1, 1, 1, 1) = (1, 3, 5, 1, 3) · (1, 1, 1, 1, 1) = 13

Sobald aber die größere Vektor-Länge ein Vielfaches der kleineren Vektor-Länge ist, unterbleibt die Fehlermeldung:

u <- c(1, 3, 5)
w <- rep(1, times = 6)
sum(u * w)          # 18

Hier wird also berechnet:

(1, 3, 5) · (1, 1, 1, 1, 1, 1) = (1, 3, 5, 1, 3, 5) · (1, 1, 1, 1, 1, 1) = 18

In der Mathematik würde man bei der Skalarmultiplikation von (1, 3, 5) mit (1, 1, 1, 1, 1) erwarten:

(1, 3, 5) · (1, 1, 1, 1, 1) = (1, 3, 5, 0, 0) · (1, 1, 1, 1, 1) = 9

Wegen all dieser Spitzfindigkeiten ist die Berechnung des Skalarproduktes mit sum(u * w) nicht zu empfehlen.

Eine Alternative dazu bietet die Verwendung der Matrizen-Multiplikation mit dem Operator %*% . Sie hat den Vorteil, dass die Länge der Vektoren überprüft wird. Das Verhalten von R bei den oben diskutierten Beispielen soll nun gezeigt werden:

# Vektoren gleicher Länge:

u <- c(1, 3, 5)
v <- c(2, 0, -2)
u %*% v         # -8

# Vektoren ungleicher Länge (kein Vielfaches der Längen):

w <- rep(1, times = 5)
u %*% w         # Fehler
# Error in u %*% w : non-conformable arguments

# Vektoren ungleicher Länge (Vielfaches der Längen):

w <- rep(1, times = 6)
u %*% w         # ebenso Fehler
# Error in u %*% w : non-conformable arguments

Man sieht, dass jetzt nicht nur eine Warnung ausgegeben wird, sondern dass es sogar eine Fehlermeldung gibt. Möchte man vermeiden, dass Vektoren unterschiedlicher Länge miteinander multipliziert werden, ist also die Verwendung der Matrizen-Multiplikation gegenüber sum(u * w) vorzuziehen.

Die Matrizen-Multiplikation hat noch weitere Eigenschaften, die bisher noch nicht diskutiert wurden.

1. Rechnet man in der Mathematik gleichzeitig mit Vektoren und Matrizen, muss man bei den Vektoren unterscheiden, ob es sich um Zeilen- oder Spaltenvektoren handelt. Streng genommen ist das Skalarprodukt u · v (als Spezialfall der Matrizen-Multiplikation) nur dann definiert, wenn der erste Faktor u ein Zeilenvektor und der zweite Faktor v ein Spaltenvektor ist.

Dagegen wird in R wird nicht zwischen Zeilen- und Spaltenvektoren unterschieden: Man multipliziert einfach die beiden Vektoren (in beliebiger Reihenfolge) und erhält ihr Skalarprodukt.

2. In der Mathematik erwartet man als Ergebnis eines Skalarproduktes u · v eine reelle Zahl; in R also einen Vektor der Länge eins. Diese Erwartung ist falsch!

Eine Ausgabe des Ergebnisses der Matrizen-Multiplikation zweier Vektoren zeigt, dass eine Matrix mit einer Zeile und einer Spalte erzeugt wird:

u <- c(1, 3, 5)
v <- c(2, 0, -2)
u %*% v
         [,1]
[1,]   -8

Dieses Verhalten sollte nicht verwundern, da bei einer Matrizen-Multiplikation im Allgemeinen eine Matrix entsteht.

Die Funktionen crossprod() und tcrossprod()

In der Linearen Algebra benötigt man für gegebene Matrizen A und B oftmals nicht die Matrizen-Multiplikation A · B, sondern das Produkt Aτ · B oder A · Bτ. In R kann diese Operation durch die Kombination der Matrizen-Multiplikation und der Funktion t() (transponierte Matrix) realisiert werden. Es gibt dafür die Funktionen crossprod() und tcrossprod(), die schneller sind als obige Kombinationen.

Abbildung 9 zeigt als Beispiel zwei Matrizen A und B, für die das Produkt A · B nicht definiert ist (Gleichung 1). Dagegen sind die Produkte Aτ · B (Gleichung 2) und A · Bτ (Gleichung 3) definiert.

Abbildung 9: Zwei Matrizen A und B, die nicht miteinander multipliziert werden können (Gleichung 1); definiert ist aber, wenn eine Matrix mit der transponierten Matrix der anderen Matrix multipliziert wird (Gleichung 2 und 3).Abbildung 9: Zwei Matrizen A und B, die nicht miteinander multipliziert werden können (Gleichung 1); definiert ist aber, wenn eine Matrix mit der transponierten Matrix der anderen Matrix multipliziert wird (Gleichung 2 und 3).

In R wird dies folgendermaßen berechnet – wobei es zahllose Möglichkeiten gibt, A und B zu erzeugen:

va <- c(1, 0, 0, 1, 1, 0)
vb <- c(0, -1, -1, 0, 0, -1)

a <- matrix(va, nrow = 3, byrow = TRUE)
b <- matrix(vb, nrow = 3, byrow = TRUE)

crossprod(x = a, y = b)         # t(a) %*% b
     [,1] [,2]
[1,]    0   -2
[2,]   -1    0

tcrossprod(x = a, y = b)            # a %*% t(b)
     [,1] [,2] [,3]
[1,]    0   -1    0
[2,]   -1    0   -1
[3,]    0   -1    0

Für die Funktionen crossprod() und tcrossprod() sind einige Spezialfälle zu beachten:

1. Soll das Produkt Aτ · A beziehungsweise A · Aτ berechnet werden, geschieht dies indem den Funktionen nur ein Argument übergeben wird:

# a, b wie oben

crossprod(x = a)            # t(a) %*% a
     [,1] [,2]
[1,]    2    0
[2,]    0    1

tcrossprod(x = a)           # a %*% t(a)
     [,1] [,2] [,3]
[1,]    1    0    1
[2,]    0    1    0
[3,]    1    0    1

2. Die Funktion crossprod() kann auch dazu verwendet werden, um das Skalarprodukt zweier Vektoren zu berechnen:

u <- c(1, 3, 5)
v <- c(2, 0, -2)

crossprod(x = u, y = v)         # Skalarprodukt 
    [,1]
[1,]   -8

Die Familie der apply()-Funktionen

In R gibt es eine Gruppe von Funktionen, die sogenannten apply()-Funktionen, mit denen komplexe Aufgaben für zusammengesetzte Datentypen erledigt werden können. Manche von ihnen sind auf einen speziellen Datentyp zugeschnitten, andere können auf mehrere Datentypen angewendet werden. Da es zu ihrem Verständnis besser ist, die zusammengesetzten Datentypen zu kennen, werden die apply()-Funktionen später in einem eigenen Kapitel besprochen.

Speziell die Funktion apply() ist für Matrizen bedeutend: sie erlaubt es, über die Zeilen oder Spalten einer Matrix zu iterieren und bei jedem Iterationsschritt eine Funktion auf die ausgewählte Zeile oder Spalte anzuwenden. Sie wird in Die Funktion apply() in R: Iteration über die Zeilen oder Spalten einer Matrix ausführlich besprochen.

Diagnose-Funktionen für Matrizen

Die Funktionen is.vector() und is.matrix()

Wie für alle Datentypen in R, gibt es auch für Matrizen die is-dot-Funktion is.matrix(). Da allerdings Matrizen intern wie Vektoren abgespeichert werden, ist es zunächst nicht klar, welches Ergebnis man erhält, wenn:

  • die Funktion is.vector() auf eine Matrix angewendet wird,
  • die Funktion is.matrix() auf einen Vektor angewendet wird.

Das folgende Skript zeigt das Verhalten dieser is-dot-Funktionen:

v <- (1:3)

is.vector(v)            # TRUE
is.matrix(v)            # FALSE
dim(v)                  # NULL

m <- as.matrix(v)

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

is.vector(m)            # FALSE
is.matrix(m)            # TRUE
dim(m)
# [1] 3 1

Zur Erklärung:

Zeile 3 bis 5: Diese Ausgaben sollten klar sein; ein Vektor wird von einer Matrix unterschieden, da er noch keinen Dimensionsvektor besitzt.

Zeile 7: Mit Hilfe der as-dot-Funktion wird der Vektor in eine Matrix m verwandelt.

Zeile 9. Die Ausgabe von m zeigt einen Spaltenvektor mit drei Zeilen.

Zeile 15: m ist kein Vektor gemäß der Funktion is.vector().

Zeile 16: Aber m ist eine Matrix gemäß der Funktion is.matrix().

Zeile 17: Der Dimensionsvektor von m zeigt an, dass die Matrix drei Zeilen und eine Spalte besitzt.

Die Struktur str() einer Matrix

Die Funktion str() soll möglichst in einer Zeile die wichtigste Information über ein Objekt anzeigen. Die Ausgabe bei Vektoren und Matrizen ist auf den ersten Blick nur schwer zu unterscheiden:

v <- (1:12)
v
# [1]  1  2  3  4  5  6  7  8  9 10 11 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

str(v)
# int [1:12] 1 2 3 4 5 6 7 8 9 10 ...

str(m)
# int [1:3, 1:4] 1 5 9 2 6 10 3 7 11 4 ...

Bei der Ausgabe der Struktur einer Matrix sind zwei Dinge zu beachten:

  • Dass es sich um ein zweidimensionales Feld handelt, ist an den zwei (durch das Komma getrennten) Einträgen in den eckigen Klammern erkennbar (siehe Zeile 16); sie zeigen den Zahlenbereich des Zeilenindex (hier 1 bis 3) und des Spaltenindex (hier 1 bis 4). Im Gegensatz dazu wird beim Vektor v nur ein Zahlenbereich (von 1 bis 12) angezeigt (siehe Zeile 13).
  • Zur Ausgabe der Elemente der Matrix wird die Matrix spaltenweise durchlaufen; die Zahlen werden nicht in der Reihenfolge des zugrundeliegenden Vektors ausgegeben.

Wie schon bei Vektoren wird der Speichermodus angegeben (hier abgekürzt durch int für integer) und die Ausgabe der Zahlenwerte bricht eventuell ab (angedeutet durch die Punkte).

Statistische Auswertung mit summary()

Die Funktion summary(object) existiert auch für eine Matrix als Eingabewert. Sie liefert eine statistische Auswertung der Komponenten; dabei werden die Spalten der Matrix wie Vektoren behandelt und für diese eine kleine statistische Auswertung durchgeführt. Der Rückgabewert ist eine Tabelle (table), der hier noch nicht besprochen werden kann – die Bedeutung einer Tabelle sollte aber aus dem folgenden Beispiel klar werden:

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

summary(m)
# V1          V2           V3           V4    
# Min.   :1   Min.   : 2   Min.   : 3   Min.   : 4  
# 1st Qu.:3   1st Qu.: 4   1st Qu.: 5   1st Qu.: 6  
# Median :5   Median : 6   Median : 7   Median : 8  
# Mean   :5   Mean   : 6   Mean   : 7   Mean   : 8  
# 3rd Qu.:7   3rd Qu.: 8   3rd Qu.: 9   3rd Qu.:10  
# Max.   :9   Max.   :10   Max.   :11   Max.   :12  

# 1. Spalte:
m[ ,1]
# [1] 1 5 9

summary(m[ ,1])
# Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
# 1       3       5       5       7       9

Man erkennt, dass die Matrix in 4 Spalten zerlegt wird und für jede Spalte die Funktion summary() eines Vektors aufgerufen wird.

Zusammenfassung

Eigenschaften einer Matrix

Die folgende Tabelle zeigt Funktionen, die auf Vektoren operieren und mit einer (oder mehreren) Bedingungsprüfung verbunden sind:

Funktion Beschreibung
length(x) Anzahl der Komponenten einer Matrix x (Produkt aus der Anzahl der Zeilen und der Anzahl der Spalten)
nrow(x) Anzahl der Zeilen der Matrix x
ncol(x) Anzahl der Spalten der Matrix x
NROW(x) Anzahl der Zeilen der Matrix x (ist x ein Vektor, wird er wie eine Matrix mit einer Spalte behandelt)
NCOL(x) Anzahl der Spalten der Matrix x (ist x ein Vektor, wird er wie eine Matrix mit einer Spalte behandelt)
rowSums(x) Zeilen-Summen der Matrix x
colSums(x) Spalten-Summen der Matrix x
rowMeans(x) Zeilen-Mittelwerte der Matrix x
colMeans(x) Spalten-Mittelwerte der Matrix x
duplicated(x, MARGIN = 1) Die Matrix x kann auf drei Arten untersucht werden: Für MARGIN = 1 (default-Wert), ob eine Zeile wiederholt wird; für MARGIN = 2 (default-Wert), ob eine Spalte wiederholt wird; für MARGIN = 0 (default-Wert), ob ein Element wiederholt wird.
?nrow Weitere Informationen zu Summen und Mittelwerten im package base unter colSums
?colSums Weitere Informationen zu nrow(), ncol(), NROW(), NCOL() im package base unter nrow

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

Funktion Rückgabewert Datentyp
length(x) Anzahl der Komponenten einer Matrix x (Produkt aus der Anzahl der Zeilen und der Anzahl der Spalten) Zahl
nrow(x) Anzahl der Zeilen der Matrix x Zahl
ncol(x) Anzahl der Spalten der Matrix x Zahl
NROW(x) Anzahl der Zeilen der Matrix x (ist x ein Vektor, wird er wie eine Matrix mit einer Spalte behandelt) Zahl
NCOL(x) Anzahl der Spalten der Matrix x (ist x ein Vektor, wird er wie eine Matrix mit einer Spalte behandelt) Zahl
rowSums(x) Vektor mit den Zeilen-Summen der Matrix x; Länge des Vektors ist gleich der Zeilen-Anzahl von x Vektor
colSums(x) Vektor mit den Spalten-Summen der Matrix x; Länge des Vektors ist gleich der Spalten-Anzahl von x Vektor
rowMeans(x) Vektor mit den Zeilen-Mittelwerten der Matrix x; Länge des Vektors ist gleich der Zeilen-Anzahl von x Vektor
colMeans(x) Vektor mit den Spalten-Mittelwerten der Matrix x; Länge des Vektors ist gleich der Spalten-Anzahl von x Vektor
duplicated(x, MARGIN = 1) Der Rückgabewert hängt von MARGIN ab: logischer Vektor für MARGIN = 1 und MARGIN = 2 ; die Länge des logischen Vektors stimmt mit der Anzahl der Zeilen beziehungsweise Anzahl der Spalten von x überein. Logische Matrix für MARGIN = 0 (mit identischen Dimensionen wie x). logischer Vektor oder logische Matrix

Elementare Operationen mit Matrizen

Die folgende Tabelle zeigt, welche elementaren Operationen mit Matrizen ausgeführt werden können:

Funktion Beschreibung
m1 + m2 Berechnet komponentenweise die Summe der Matrizen m1 und m2 (die Matrizen sollten in Zeilen- und Spalten-Anzahl übereinstimmen, ansonsten kann es zu Komplikationen kommen).
k * m Ist k eine Zahl und m eine Matrix, wird jede Komponente von m mit k multipliziert; das Ergebnis ist eine Matrix mit denselben Dimensionen wie m.
m1 * m2 Die beiden Matrizen m1 und m2 werden komponentenweise multipliziert (die Matrizen sollten in Zeilen- und Spalten-Anzahl übereinstimmen, ansonsten kann es zu Komplikationen kommen); diese Operation ist nicht die Matrizen-Multiplikation.
m1 / m2 Die beiden Matrizen m1 und m2 werden komponentenweise dividiert (die Matrizen sollten in Zeilen- und Spalten-Anzahl übereinstimmen, ansonsten kann es zu Komplikationen kommen).
m1 %/% m2 Für die beiden Matrizen m1 und m2 wird komponentenweise die Ganzzahl-Division ausgeführt (die Matrizen sollten in Zeilen- und Spalten-Anzahl übereinstimmen, ansonsten kann es zu Komplikationen kommen).
m1 %% m2 Für die beiden Matrizen m1 und m2 wird komponentenweise die Berechnung des Restes ausgeführt (die Matrizen sollten in Zeilen- und Spalten-Anzahl übereinstimmen, ansonsten kann es zu Komplikationen kommen).
m1 %*% m2 Matrizen-Multiplikation von m1 und m2; damit man die Matrizen multiplizieren kann, müssen die Anzahl der Spalten von m1 und die Anzahl der Zeilen von m2 übereinstimmen. Das Ergebnis ist eine Matrix mit der Anzahl der Zeilen von m1 und der Anzahl der Spalten von m2.
?matmult Mehr Informationen zur Matrizen-Multiplikation im package base unter matmult.

Statistische Funktionen

Die folgende Tabelle zeigt die wichtigsten statistischen Funktionen, die auf Vektoren oder auch Matrizen operieren; werden beide Eingabewerte x und y gesetzt, müssen beide entweder Vektoren oder Matrizen sein. Zur Berechnung der Varianz und der Kovarianz wird der Nenner n-1 verwendet (und nicht n).

Funktion Beschreibung
cov(x, y = NULL) Sind x und y Vektoren, wird ihre Kovarianz berechnet; wird dabei y nicht gesetzt, wird die Varianz von x berechnet. Sind x und y Matrizen, so werden sie spaltenweise in Vektoren zerlegt und die Kovarianzen zwischen diesen Spaltenvektoren berechnet; wird dabei y nicht gesetzt, werden die Kovarianzen zwischen den Spalten von x berechnet.
cor(x, y = NULL) Alles wie bei cov(x, y = NULL) : anstelle der Kovarianzen werden die Korrelationskoeffizienten berechnet.
?cor Weitere Informationen zu den Funktionen var(), cov() und cor() im package stats unter cor.

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

Funktion Rückgabewert Datentyp
cov(x, y = NULL) Matrix, aus der die Kovarianzen zwischen den Spalten von x und y abgelesen werden können. Anzahl der Zeilen des Rückgabewertes: Anzahl der Spalten von x. Anzahl der Spalten des Rückgabewertes: Anzahl der Spalten von y. Matrix
cor(x, y = NULL) Matrix, aus der die Korrelationskoeffizienten zwischen den Spalten von x und y abgelesen werden können. Anzahl der Zeilen des Rückgabewertes: Anzahl der Spalten von x. Anzahl der Spalten des Rückgabewertes: Anzahl der Spalten von y. Matrix

Funktionen aus der Linearen Algebra

Die folgende Tabelle zeigt Funktionen für Aufgaben aus der Linearen Algebra:

Funktion Beschreibung
isSymmetric(object, ...) Testet, ob die Matrix object symmetrisch ist (falls dimnames gesetzt ist, werden auch diese auf Symmetrie überprüft).
det(x) Berechnet die Determinante der quadratischen Matrix x.
solve(a, b) Berechnet die Lösung der Gleichung a %*% x = b ; dabei muss a eine quadratische Matrix sein
solve(a) Berechnet die inverse Matrix von a.
eigen(x) Berechnet die Eigenwerte und Eigenvektoren der Matrix x.
t(x) Berechnet die transponierte Matrix der Matrix x.
crossprod(x, y = NULL) Berechnet t(x) %*% y (schneller als in dieser direkten Form); falls das Argument y fehlt, wird y gleich x gesetzt.
tcrossprod(x, y = NULL) Berechnet x %*% t(y) (schneller als in dieser direkten Form); falls das Argument y fehlt, wird y gleich x gesetzt.
?crossprod Mehr Informationen zu crossprod und tcrossprod im package base unter crossprod.

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

Funktion Rückgabewert Datentyp
isSymmetric(object, ...) logischer Wert, der angibt, ob die Matrix object symmetrisch ist (falls dimnames gesetzt ist, werden auch diese auf Symmetrie überprüft) logical
det(x) Determinante der quadratischen Matrix x numeric
solve(a, b) Vektor, der die Gleichung a %*% x = b löst; falls keine Lösung oder unendlich viele Lösungen existieren, gibt es eine Fehlermeldung. Vektor
solve(a) inverse Matrix von a Matrix
eigen(x) Liste mit zwei Komponenten (values und vectors), die die Eigenwerte und die Eigenvektoren der Matrix x bilden. (Die Eigenwerte werden zu einem Vektor zusammengefasst, die Eigenvektoren werden als Spaltenvektoren zu einer Matrix zusammengefasst.) Liste
t(x) transponierte Matrix der Matrix x Matrix
crossprod(x, y = NULL) Das Matrizen-Produkt t(x) %*% y ; falls das Argument y fehlt, wird y gleich x gesetzt. Matrix
tcrossprod(x, y = NULL) Das Matrizen-Produkt x %*% t(y) Matrix

Diagnose-Funktionen

Die folgende Tabelle zeigt Diagnose-Funktionen für Matrizen:

Funktion Beschreibung
is.matrix(x) Feststellen, ob x eine Matrix ist
str(object) Ausgabe der Struktur der Matrix object (Modus, Vektor der Indizes, Werte)
summary(object, digits) Ausgabe einer einfachen statistischen Auswertung der Matrix object; für jede Spalte wird die Funktion summary() für Vektoren aufgerufen. Die Zahlenwerte werden mit digits Nachkommastellen angegeben.

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

Funktion Rückgabewert Datentyp
is.matrix(x) logischer Wert, der angibt, ob x eine Matrix ist logical
str(object) kein Rückgabewert; nur Ausgabe der Struktur der Matrix object NULL
summary(object, digits) Tabelle mit einer einfachen statistischen Auswertung der Matrix object; Zahlenwerte werden mit digits Nachkommastellen angegeben Tabelle (table), genauer: Klasse ("summaryDefault" "table")
Durch die Nutzung dieser Website erklären Sie sich mit der Verwendung von Cookies einverstanden. Außerdem werden teilweise auch Cookies von Diensten Dritter gesetzt. Genauere Informationen finden Sie in unserer Datenschutzerklärung sowie im Impressum.