15  Matrizen und Arrays

R Matrizen und Arrays können als höherdimensionale Generalisierungen von R Vektoren verstanden werden. Wie bei den Vektoren ist es wichtig, Matrizen in der Programmierung von ihren gleichnamigen mathematischen Objekten abzugrenzen. So können Matrizen in der Programmierung einfach der tabellarischen Speicherung numerischer Daten dienen, ohne dass dabei das primäre Ziel die Anwendung der mathematischen Matrizenrechnung sein muss. Andersherum bilden die elementweisen arithmetischen Operationen mit Matrizen in der Programmierung in der Mathematik eher sehr spezielle mathematische Operationen, wie das Hadamard-Produkt ab. In diesem Abschnitt wollen wir Matrizen und Arrays primär als Datencontainer in der imperativen Programmierung mit R untersuchen. Eine Einführung in die Matrizenrechnung mit den gleichen Datenstrukturen gibt Kapitel 15.1.

15.1 Matrizen

Abstrakt gesprochen sind R Matrizen zweidimensionale, rechteckige Datenstrukturen der Form \[\begin{equation} M = \begin{pmatrix} m_{11} & m_{12} & \cdots & m_{1n_c} \\ m_{21} & m_{22} & \cdots & m_{2n_c} \\ \vdots & \vdots & \ddots & \vdots \\ m_{n_r1} & m_{n_r2} & \cdots & {m_{n_rn_c}} \\ \end{pmatrix} \end{equation}\] Die Elemente \(m_{ij}, i = 1,...,n_r, j = 1,...,n_c\) der Matrix sind dabei notwendigerweise vom gleichen Datentyp. In obigem Schema bezeichnet \(n_r\) die Anzahl der Zeilen (rows) und \(n_c\) die Anzahl der Spalten (columns) der Matrix \(M\). Jedes Element einer Matrix hat damit einen Zeilenindex \(i\) und einen Spaltenindex \(j\). Intuitiv sind R Matrizen also numerisch indizierte Tabellen, formal sind Matrizen in R zweidimensional interpretierte atomare Vektoren.

15.1.1 Erzeugung

Zur Erzeugung einer Matrix wird die R Funktion matrix() genutzt, die Matrizen mit den Elementen eines Vektors befüllt. Die allgemeine Syntax dieser Funktion ist M = matrix(v, nrow, ncol, byrow), wobei

  • v einen Vektor der Länge nrow\(\cdot\) ncol,
  • nrow die gewünschte Zeilenanzahl von M,
  • ncol die gewünschte Spaltenanzahl von M,
  • die logische Variable byrow die Befüllungsordnung von M

bezeichnen. Da sich bei gegebener Länge von v und gebener Zeilen- oder Spaltenanzahl die entsprechende Spalten- oder Zeilenanzahl der Matrix ergibt, ist es lediglich nötig entweder nrow oder ncol zu spezifizieren. Folgende Beispiele verdeutlichen dies

matrix(c(1:12), nrow = 3)               # 3 x 4 Matrix der Zahlen 1,...,12, byrow = F
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
matrix(c(1:12), ncol = 4)               # 3 x 4 Matrix der Zahlen 1,...,12, byrow = F
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
matrix(c(1:12), nrow = 3, byrow = T)    # 3 x 4 Matrix der Zahlen 1,...,12, byrow = T
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12

Bestehende Matrizen gleicher Zeilenanzahl können mit der Funktion cbind() spaltenweise konkateniert werden:

A = matrix(c(1:4) , nrow = 2)           # 2 x 2 Matrix der Zahlen 1,...,4
A                                       # Ausgabe
     [,1] [,2]
[1,]    1    3
[2,]    2    4
B = matrix(c(5:10), nrow = 2)            # 2 x 3 Matrix der Zahlen 5,...,10
B                                       # Ausgabe     
     [,1] [,2] [,3]
[1,]    5    7    9
[2,]    6    8   10
C = cbind(A,B)                       # spaltenweise Konkatenierung von A und B
C                                       # Ausgabe     
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    5    7    9
[2,]    2    4    6    8   10

Äquivalent können bestehende Matrizen gleicher Spaltenanzahl mit der Funktion rbind() zeilenweise konkateniert werden

A = matrix(c(1:6) , nrow = 2, byrow = T)     # 2 x 3 Matrix der Zahlen 1,...,6
print(A)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
B = matrix(c(7:9), nrow = 1)                 # 1 x 3 Matrix der Zahlen 5,...,10
print(B)
     [,1] [,2] [,3]
[1,]    7    8    9
C = rbind(A,B)                               # reihenweise Konkatenierung von A und B
print(C)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

15.1.2 Charakterisierung

Mit der vertrauten Funktion typeof() kann der elementare Datentyp einer Matrix ausgegeben werden:

typeof(matrix(c(1,0,0,1)    , nrow = 2))    # 2 x 2 double    Matrix  
[1] "double"
typeof(matrix(c(1L,0L,0L,1L), nrow = 2))    # 2 x 2 integer   Matrix
[1] "integer"
typeof(matrix(c(T,T,F,F)    , nrow = 2))    # 2 x 2 logical   Matrix  
[1] "logical"
typeof(matrix(c("a","b","c"), nrow = 1))    # 1 x 3 character Matrix  
[1] "character"

Die Zeilen- bzw. Spaltenanzahl einer Matrix können mit den Funktionen nrow() (number of rows) und ncol() (number of columns) ausgegeben werden.

C = matrix(1:12, nrow = 3)                # 3 x 4 Matrix
nrow(C)                                   # Anzahl Zeilen
[1] 3
ncol(C)                                   # Anzahl Spalten
[1] 4

15.1.3 Indizierung

Generell gilt, dass Matrixelemente mit einem Zeilenindex und einem Spaltenindex indiziert werden. Der erste zweier Matrixindices indiziert dabei immer die Zeile, der zweite immer die Spalte. Die übrigen Prinzipien der Indizierung von Matrizen entsprechen im Wesentlichen den Prinzipien der Indizierung von Vektoren. Eine Besonderheit ist, dass ein fehlender Zeilen- oder Spaltenindex alle Elemente der entsprechenden Dimension indiziert.

A = matrix(c(2:7)^2, nrow = 2)  # 2 x 3 Matrix der Zahlen 2^2,...,7^2
A                               # Ausgabe
     [,1] [,2] [,3]
[1,]    4   16   36
[2,]    9   25   49
A[1,3]                          # Element in 1. Zeile, 3. Spalte von A [36]
[1] 36
A[2,2]                          # Element in 2. Zeile, 2. Spalte von A [35]
[1] 25
A[2,]                           # Alle Elemente der 2. Zeile [9,25,49]
[1]  9 25 49
A[,3]                           # Alle Elemente der 3. Spalte [36,49]
[1] 36 49
A[1:2,1:2]                      # Submatrix der ersten zwei Zeilen und Spalten
     [,1] [,2]
[1,]    4   16
[2,]    9   25
A[A>10]                         # Elemente von A groesser 10 [16,25,36,49]
[1] 16 25 36 49
A[1,c(F,F,T)]                   # Element in 1. Zeile, 3. Spalte von A [36]
[1] 36

15.1.4 Arithmetik

Wendet man unitäre arithmetische Operatoren und Funktionen auf Matrizen an, so werden diese wie bei den Vektoren elementweise ausgewertet:

A = matrix(c(1:4), nrow = 2)    # 2 x 2 Matrix der Zahlen 1,2,3,4
     [,1] [,2]
[1,]    1    3
[2,]    2    4

B = A^2                         # B[i,j]  = A[i,j]^2,  1 <= i,j <= 2
     [,1] [,2]
[1,]    1    9                         # 1^2, 3^2
[2,]    4   16                       # 2^2, 4^2

C = sqrt(B)                     # C[i,j]  = sqrt(A[i,j]^2),  1 <= i,j <= 2
     [,1] [,2]
[1,]    1    3                       # sqrt(1^2), sqrt(3^2)
[2,]    2    4                       # sqrt(2^2), sqrt(4^2)

D = exp(A)                      # D[i,j] = exp(A[i,j]),  1 <= i,j <= 2
     [,1] [,2]
[1,]  2.7  20.0                 # exp(1), exp(3)
[2,]  7.4  54.6                 # exp(2), exp(4)

Wie Vektoren können auch Matrizen mit identischen Zeilen- und Spaltenanzahlen mit den binären arithmetischen Operatoren +, -, * und / elementweise verknüpft werden. Folgende Beispiele verdeutlichen dies:

A = matrix(c(1:4), nrow = 2)    # 2 x 2 Matrix der Zahlen 1,2,3,4
     [,1] [,2]
[1,]    1    3
[2,]    2    4

B = matrix(c(5:8), nrow = 2)    # 2 x 2 Matrix der Zahlen 5,6,7,8
     [,1] [,2]
[1,]    5    7
[2,]    6    8

C = A + B                       # C[i,j] = A[i,j] + B[i,j], 1 <= i,j <= 2
     [,1] [,2]
[1,]    6   10                  # 1 + 5, 3 + 7
[2,]    8   12               # 2 + 6, 4 + 8

D = A * B
     [,1] [,2]
[1,]    5   21                  # 1 * 5, 3 * 7
[2,]   12   32                  # 2 * 6, 4 * 8

Darüber hinaus kann mit R Matrizen im Sinne d der Matrizenrechnung der linearen Algebra gerechnet werden. Wir zeigen hier nur einige wenige Beispiele, eine ausführliche Darstellung der mathematischen Prinzipien und ihrer R Implementation findet sich in Kapitel 15.1.

C = A  % * % B                   # 2 x 2 Matrixprodukt
      [,1] [,2]
[1,]   23   31                  # 1*5 + 3*6, 1*7+3*8
[2,]   34   46                  # 2*5 + 4*6, 2*7+4*8

A_T = t(A)                   # Transposition von A
      [,1] [,2]
[1,]   1   2                    # A[1,1], A[2,1]
[2,]   3   4                    # A[1,2], A[2,2]

A_inv = solve(A)                # Inverse von A
     [,1] [,2]
[1,]   -2  1.5
[2,]    1 -0.5

A_det = det(A)                  # Determinante von A
[1] -2                       # 1*4 - 2*3

15.1.5 Attribute

Formal sind Matrizen atomare Vektoren mit einem dim Attribut

A = matrix(1:12, nrow = 4 )              #  4 x 3 Matrix
attributes(A)                            # Aufrufen der Attribute von A
$dim
[1] 4 3

Wie bei den Vektoren kann man auch den Matrizenelementen Namen geben, allerdings ist dies auch bei Matrizen eher ungewöhnlich. Speziell definieren die Funktionen rownames() und colnames() das Matrixattribut dimnames.

rownames(A) = c("P1","P2","P3","P4")     # Benennung der Zeilen von A
colnames(A) = c("Age", "Hgt", "Wgt")     # Benennung der Spalten von A
A                                        # A mit Attribut dimnames
   Age Hgt Wgt
P1   1   5   9
P2   2   6  10
P3   3   7  11
P4   4   8  12
attr(A, "dimnames")                      # Aufrufen des Attributs dimnames
[[1]]
[1] "P1" "P2" "P3" "P4"

[[2]]
[1] "Age" "Hgt" "Wgt"

15.2 Arrays

R Arrays sind \(d\)-dimensionale, hyperrechteckige Datenstrukturen. Intuitiv können Arrays als die Generalisierung von Matrizen auf mehr als zwei Dimensionen verstanden werden. Für \(d = 1\) entspricht ein Array einem Vektor, für \(d = 2\) entspricht ein Array einer Matrix. Wie bei Vektoren und Matrizen müssen die Elemente eines Arrays vom gleichen Datentyp sein. Arrays sind dadurch charakterisiert, wieviele Elemente \(d_i, i = 1,...,d\) in der \(i\)ten Dimension repräsentieren können, jedes Element eines Arrays wird dabei durch \(d\)-dimensionalen Index \(i_1,i_2,...,i_d\) indiziert.

15.2.1 Erzeugung

In Analogie zur Funktion matrix() wird die Funktion array() genutzt, um einen Array mit Vektorelementen zu befüllen. Die allgemeine Syntax dieser Funktion ist A = array(v, dim), wobei v ein Vektor von Arraydaten und dim ein Vektor ganzzahliger Werte ist, der die maximalen Indizes in jeder der length(dim) Dimensionen des Arrays repräsentiert. So erzeugt beispielsweise

A = array(1:12, dim = c(2,2,3))    # 2 x 2 x 3 Array der Zahlen 1,...,12
A
, , 1

     [,1] [,2]
[1,]    1    3
[2,]    2    4

, , 2

     [,1] [,2]
[1,]    5    7
[2,]    6    8

, , 3

     [,1] [,2]
[1,]    9   11
[2,]   10   12

einen \(2 \times 2 \times 3\) Array. Dreidimensionale Arrays kann man sich intuitiv als im Raum hintereinander aufgestellte Matrizen vorstellen, die dritte Dimension repräsentiert dann dabei die “Seiten” des Arrays. Allerdings ist es im Umgang mit höherdimensionalen Arrays sinnvoll, zu versuchen, sich von räumlichen Vorstellungen von Arrays zu lösen und Arrays stattdessen als Datencontainer zu verstehen, deren Elemente eineindeutig durch ihre Indizes addressiert werden können.

15.2.2 Charakterisierung

Die length() Funktion gibt die Anzahl der Elemente eines Arrays aus:

A = array(1:12, dim = c(2,2,3))    # 2 x 2 x 3 Array der Zahlen 1,...,12
length(A)                        # Die Anzahl der Elemente des Arrays
[1] 12

Die Funktion typeof() gibt den elementaren Datentyp eines Arrays aus:

typeof(A)                          # Der Typ des Arrays
[1] "integer"

Die Funktion dim() gibt die Dimensionen eines Arrays aus:

dim(A)                          # Dimension des Arrays
[1] 2 2 3

15.2.3 Indizierung

Die Indizierung von Arrays erfolgt analog zu Vektor- und Matrixindizierung, mit dem Unterschied, dass zur indizierung eines Arrayelements drei oder mehr Indices benötig werden.

A        = array(1:12, dim = c(2,2,3))      # 2 x 2 x 3 Array der Zahlen 1,...,12
a_223     = A[2,2,3]                    # Arrayelement mit Indexaddresse [2,2,3] (12)

15.2.4 Arithmetik

Wie bei Vektoren und Matrizen werden unitäre arithmetische Operatoren bei Arrays elementweise ausgewertet. Ebenso analog werden binäre arithmetische Operatoren bei Arrays identischer Dimensionalität elementweise ausgwertet

A       = array(1:4, dim = c(1,2,2))        # 1 x 2 x 2 Array der Zahlen 1,...,4
A
B       = array(5:8, dim = c(1,2,2))        # 1 x 2 x 2 Array der Zahlen 5,...,8
B
C       = A^2                        # elementweise Potenzierung
C
D         = A + B                            # elementweise Addition     
D

15.2.5 Attribute

Formal sind Arrays atomic vectors mit einem dim Attribut

A = array(1:12, dim = c(2,2,3))           # 2 x 2 x 3 Array der Zahlen 1,...,12
attributes(A)                             # Aufrufen der Attribute von A
$dim
[1] 2 2 3

Wie bei den Matrizen kann die Funktion dimnames() zur Benennung der Arraydimensionen benutzt werden, aber auch hier die Benennung von Arraydimensionen eher ungewöhnlich.