12  Vektoroperationen

Work in Progress

Vektoren sind zusammengesetzte Datenstrukturen, die Werte vom gleichen Datentyp enthalten. In R bilden Vektoren die Basisstruktur für alle Daten. R unterscheidet zwischen Listen und Vektoren, wobei für Vektoren immer sichergestellt wird, dass alle Werte vom gleichen Datentyp sind.

Wichtig

Vektoren haben in R keine Orientierung, d.h. R unterscheidet nicht zwischen Zeilen- und Spaltenvektoren.

Merke

Alle R-Vektoren werden grundsätzlich als Spaltenvektoren behandelt.

12.1 Konkatenation

Vektoren werden in R mit der Funktion c() erzeugt (Beispiel 12.1).

Beispiel 12.1 (Einen Vektor aus Skalaren erstellen)  

vektor = c(2, 3, 1, 5, 4, 6)
vektor
[1] 2 3 1 5 4 6

Die Funktion c() dient nicht nur zum erzeugen von Vektoren, sondern auch zur Konkatenation von Vektoren (Beispiel 12.2). Anders als mit der list-Funktion, können mit der c()-Funktion keine komplexen Datenstrukturen erzeugt werden.

Beispiel 12.2 (Konkatenation von Vektoren)  

c(vektor, c(6, 7))
[1] 2 3 1 5 4 6 6 7
Praxis

Die Funktion c() sollte nur zur Konkatenation von alleinstehenden Vektoren eingesetzt werden und nie für Vektoren, die zu einem Datenrahmen gehören!

12.2 Vektorlänge

Die Länge eines R-Vektors wird mit der Funktion length() bestimmt. Diese Funktion liefert immer eine ganze Zahl mit der Anzahl der Vektorelemente (Beispiel 12.3).

Beispiel 12.3 (Vektorlänge bestimmen)  

c(1, 3, 2, 4) |> length()
[1] 4

R kennt den leeren Vektor. Dieser Vektor hat die Länge 0. Er wird durch den argumentlosen Aufruf der Funktion c() erzeugt (Beispiel 12.4).

Beispiel 12.4 (Vektorlänge des leeren Vektors)  

c() |> length()
[1] 0

12.3 Wertereferenzierung

Jeder Wert in einem Vektor hat eine eindeutige Position. Der erste Wert hat die Position 1 und alle weiteren Positionen sind fortlaufend nummeriert. Der Wert der Position wird auch als Vektorindex bezeichnet.

Der Index eines Vektors wird in eckigen Klammern (bzw. Blockklammern: [ und ]) gerahmt angegeben. Die Blockklammern sind R’s Indexoperator. Ein Index wird als Referenz für einen Wert verwendet. Ein Wert in einem Vektor wird über den Index referenziert.

Es werden drei Varianten der Wertereferenzierung unterschieden. Alle Varianten sind gleichwertig, dürfen aber nicht gemischt werden.

  • Die Indexreferenz
  • Die negative Indexreferenz
  • Die Referenz mit Wahrheitsvektoren

12.3.1 Indexreferenz

Beispiel 12.5 (Index eines Vektors)  

vektor[2]
[1] 3

Weil alle Werte gleichzeitig Vektoren sind, können Indizes ebenfalls als Vektoren angegeben werden, um mehrere Vektorwerte gleichzeitig abzufragen. Der Ergebnisvektor enthält die Werte in der Reihenfolge

Achtung

Werden ungültige Indizes angegeben, füllt R diese nicht existierenden Werte mit NA auf.

Beispiel 12.6 (Vektorwerte über einen Indexvektor abfragen)  

vektor[c(2, 7, 4)]
[1]  3 NA  5

Ein Indexvektor kann länger als der Wertevektor sein, ausserdem können Indexwerte wiederholt werden. Dadurch lassen sich Vektoren systematisch erzeugen.

Beispiel 12.7 (Vektorwerte über einen Indexvektor wiederholt abfragen)  

vektor[c(2, 4, 4, 2)]
[1] 3 5 5 3

12.3.2 Negative Indexreferenz

Alternativ können negative Indizes verwendet werden. Das Vorzeichen bedeutet in diesem Fall “ausser”. Es werden also alle Indizes, ausser dem angegebenen, zurückgegeben (Team et al., 2023).

Achtung

Negative und positive Indizes dürfen nicht gemischt werden!

Jargon

Diese Verwendung von negativen Referenzen ist eine Eigenheit von R und wird in den meisten anderen Programmiersprachen nicht bzw. nicht so unterstützt.

Beispiel 12.8 (Negative Indizes)  

vektor[-2]
[1] 2 1 5 4 6

12.3.3 Referenz durch Wahrheitsvektoren

Die letzte Variante des Wertezugriffs ist der Zugriff mit einem Wahrheitsvektor. Ein Wahrheitsvektor zum Wertezugriff muss die gleiche Länge haben, wie der Wertevektor. Das Ergebnis dieser Operation ist ein Vektor, der nur Werte enthält, die an den Positionen stehen, an welchen im Wahrheitsvektor TRUE steht.

Beispiel 12.9 (Negative Indizes)  

vektor[c(TRUE, FALSE, TRUE, FALSE, TRUE)]
[1] 2 1 4 6

Diese Art des Wertereferenzierung wird häufig mit einer Transformation (Abschnitt 12.6) als Teil eines logischen Ausdrucks kombiniert. Beispiel 12.10 referenziert nur die gereaden Werte in vektor.

Merke

Das Referenzieren mit einem logischen Ausdruck ist eine Variante des Filterns.

Praxis

Das Filtern durch Referenzieren sollte nur für alleinstehende Vektoren eingesetzt werden. Zum Filtern von Vektoren in Datenrahmen sollte immer die dplyr-Funktion filter() verwendet werden.

Beispiel 12.10 (Gerade Werte aus einem Vektor auswählen)  

vektor[vektor %% 2 == 0]
[1] 2 4 6

12.4 Sequenzen

Sequenzen werden mit der Funktion seq() erstellt. Die Funktion hat fünf Parameter. Die drei wichtigsten Parameter sind:

  • from: Der Initialwert der Sequenz.
  • length: Die Länge der Sequenz.
  • by: Die Schrittweite der Sequenz.

Neben diesen Parameter gibt es noch die beiden Parameter:

  • to: Der Endwert der Sequenz
  • along.with: Übernimmt die Länge der Sequenz der Länge des angegebenen Vektors.

Beispiel 12.11 (Sequenzen erstellen)  

seq(5) # seq(length = 5)
[1] 1 2 3 4 5
seq(2, 5) # seq(from = 2, to = 5)
[1] 2 3 4 5
seq(from = 2, length = 5, by = 2)
[1]  2  4  6  8 10

Neben der seq()-Funktion kennt R den Sequenzoperator :. Die Operanden des Squenzoperators sind der Initial- und Endwert, wobei eine Schrittweite von 1 angenommen wird (Beispiel 12.12).

Beispiel 12.12 (Sequenzoperator verwenden)  

3:8  # identisch mit seq(from = 3, to = 8, by = 1)
[1] 3 4 5 6 7 8

12.5 Wiederholungen

Vektoren mit gleichen Werten an allen Positionen können als Sequenzen mit der Schrittweite von 0 verstanden werden. Genauso lassen sich solche Vektoren als Wiederholungen eines Werts beschreiben. Diesen Weg geht R mit der rep()-Funktion (rep für engl. repeat).

Die rep()-Funktion hat zwei Parameter:

  • x: Der Wiederholungswert
  • length: Die Länge des Zielvektors

Mit dieser Funktion lassen sich Vektoren wie der Nullvektor oder der Einsvektor leicht erzeugen (Beispiel 12.13).

Beispiel 12.13 (Null- und Einsvektor der Länge fünf erzeugen)  

rep(0, 5)
[1] 0 0 0 0 0
rep(1, 5)
[1] 1 1 1 1 1

Weil die Datengrundstruktur in R Vektoren sind, können Vektoren mit der rep()-Funktion vervielfacht werden. So lassen sich Vektoren mit Wertemustern erzeugen (Beispiel 12.14).

Beispiel 12.14 (Mustervektor erzeugen)  

rep(c(1,0), 3)
[1] 1 0 1 0 1 0

12.6 Transformationen

Vektortransformationen bedeuten in R das wiederholte Ausführen einer Funktion für jeden Wert eines Vektors. Alle arithmetischen, logischen und Vergleichsoperatoren sind automatisch Vektortransformationen (Beispiel 12.15).

Beispiel 12.15 (Einfache Vektortransformationen)  

# Arithmetische Operationen
vektor + 4
[1]  6  7  5  9  8 10
vektor %% 2
[1] 0 1 1 1 0 0
# Logische und Vergleichsoperationen
vektor <= 3
[1]  TRUE  TRUE  TRUE FALSE FALSE FALSE
2 < vektor & vektor < 5
[1] FALSE  TRUE FALSE FALSE  TRUE FALSE

Eine Besonderheit von R ist die Verallgemeinerung von Skalaroperationen auf Vektoren mit unterschiedlicher Länge. Dabei wird der kürzere Vektor auf die Länge des längeren Vektors durch Wiederholung erweitert, so dass eine Vektortransforamtion möglich wird (Beispiel 12.16). Bei einer Vektortransformation werden die Werte an den gleichen Positionen aus zwei Vektoren paarweise miteinander verknüpft.

Beispiel 12.16 (Erweiterte Vektortransformationen)  

vektor
[1] 2 3 1 5 4 6
vektor + 4 # vektor + rep(4, length(vektor))
[1]  6  7  5  9  8 10
vektor + c(1, 2) # vektor + rep(c(1, 2), 3)
[1] 3 5 2 7 5 8

Im Beispiel 12.16 werden Vektoren mit Längen, die Vielfache des kürzesten Vektors sind. Dadurch ist sichergestellt, dass keine überzähligen Werte bleiben. Die Wiederholung des kürzeren Vektors wird auch dann ausgeführt, wenn die Vektorenlängen keine Vielfachen voneinander sind. Dabei wird die Operation nur für alle die Werte im ursprünglich längsten Vektor ausgeführt. Dadurch bleiben nicht verwendete Werte im wiederholten Vektor. Diese überbleibenden Werte erzeugen eine Warnmeldung (Beispiel 12.17).

Beispiel 12.17 (Unvollständige Vektortransformationen)  

vektor
[1] 2 3 1 5 4 6
vektor + c(1, 2, 3, 4, 5) # vektor + c(1, 2, 3, 4, 5, 1)
Warning in vektor + c(1, 2, 3, 4, 5): Länge des längeren Objektes
     ist kein Vielfaches der Länge des kürzeren Objektes
[1] 3 5 4 9 9 7

Die Vektoroperationen von R sind sehr flexibel und leistungsfähig. Allerdings lassen sich auch damit nicht alle beliebigen Vektortransformationen durchführen.

Merke

Beliebige Transformationen lassen sich mit map() aus der Bibliothek purrr() umsetzen.

Die map()-Funktion hat immer eine Liste als Ergebnis einer Vektortransforamtion. Der eigentliche Vektor ist in dieser Liste geschachtelt und muss mit unlist() extrahiert werden (Beispiel 8.22).

12.7 Aggregationen

Aggregationen fassen mehrere Werte eines Vektors zusammen.Das Ergebnis ist ein Vekter, der höchstens so lang ist, wie der aggregierte Vektor. Alle Aggregationen werden in R durch Funktionen realisiert. Eine solche Funktion heisst Aggregator.

Häufig verwendete Aggregatoren sind:

  • sum(), zum Addieren aller Werte eines Vektors.
  • mean(), zur Mittelwertbildung.
  • max(), zum Finden des grössten Werts eines numerischen Vektors
  • min(), zum Finden des kleinsten Werts eines numerischen Vektors

Das Filtern ist eine spezielle Aggregation, die zu einem neuen und oft kürzeren Vektor führt. Das Filtern von Werten eines einzelnen Vektors erfolgt über die Wertereferenzierung mit einem logischen Ausdruck (Beispiel 12.10).

Für häufig verwendete Aggregationen finden sich in R eigene Funktionen. Sollte eine spezielle Aggregation ausnahmsweise nicht existieren, dann kann eine spezieller Aggregator implementiert werden.

Merke

Beliebige Vektoraggregationen lassen sich mit reduce() aus der Bibliothek purrr umsetzen.

Wichtig

Implementieren Sie keinen Aggregator, falls eine entsprechende Funktion bereits existiert. Die meisten vordefinierten Aggregatoren sind effizienter umgesetzt, als es mit einer naiven Umsetzung in R möglich wäre.

Beim Reduzieren wird eine Reduktionsfunktion nacheinander auf die Werte eines Vektors ausgeführt, wobei das Zwischenergebnis im nächsten Schritt als Argument verwendet wird.

Die reduce()-Funktion erwartet einen Vektor .x und eine Reduktionsfunktion .f als Parameter. Die Reduktionsfunktion ist eine zwei-parametrige Funktion (bzw. Operator), wobei der erste Parameter als Akkumulator bezeichnet wird und das Zwischenergebnis des vorangegangenen Reduktionsschritts enthält.

Beispiel 12.18 (Summe als Reduktion)  

vektor |> reduce(function(acc, wert) { acc + wert }) 
[1] 21
# oder kürzer 
vektor |> reduce(`+`)
[1] 21

Falls die Reduktionsfunktion auch für den ersten Wert in einem Vektor ausfgeführt werden soll, muss zusätzlich ein Initialwert angegeben werden. Typische Initialwerte für eine Reduktionsfunktion sind die neutralen Elemente der wichtigsten Operationen:

  • 0 (neutrales Element der Addition)
  • 1 (neutrales Element der Multiplikation)
  • TRUE (neutrales Element des logischen Und)
  • FALSE (neutrales Element des logischen Oder)
  • "" (leere Zeichenkette, neutrales Element der Textverkettung)
  • c() (leerer Vektor, neutrales Element der Konkatenation)

Eine spezielle Form der Reduktion steht mit der purrr-Funktion accumulate(). Während reduce() nur das Endergebnis der Reduktion liefert, gibt accumulate() auch die Zwischenergebnisse. Das Ergebnis der accumulate() Funktion ist immer ein Vektor mit der gleichen Länge wie der ursprüngliche Vektor.

Beispiel 12.19 (Laufende Summe als Reduktion mit accumulate())  

vektor |> accumulate(`+`)
[1]  2  5  6 11 15 21

12.8 Zählen

Mit der Funktion length() lassen sich die Werte in einem Vektor zählen.

Hinweis

In der Literatur wird das Zählen von Werten regelmässig hinter komplexen Algorithmen verborgen. Gelegentlich müssen Werte als Teil einer komplexen Analyse gezählt werden. Um unnötigen Code zu vermeiden oder um übermässig komplexe formulierte Arbeitsschritte zu erkennen, ist es notwendig die wichtigsten Varianten des Zählens zu kennen.

12.8.1 Zählen durch Summieren

Beim Zählen durch Summieren werden zählbare Einheiten durch eine 1 markiert und von nicht-zählbaren Einheiten getrennt, die mit einer 0 markiert wurden. Dadurch entsteht ein Vektor, der nur aus den Werten 0 und 1 besteht. Durch das Bilden der Summe ergibt sich die Anzahl der zählbaren Elemente.

Der erste Schritt lässt sich durch einen logischen Ausdruck umsetzen. Der zweite Schritt wird mit R’s Summe-Funktion sum().

(vektor > 3) |> sum()
[1] 3

12.8.2 Zählen durch Filtern

Beim Zählen durch Filtern werden die zählbaren Einheiten in einem separaten Vektor isoliert. Anschliessend muss nur die Länge dieses Vektors ermittelt werden.

vektor[vektor > 3] |> length()
[1] 3

12.8.3 Zählen durch Nummerieren

Beim Zählen durch Nummerieren wird ein zweiter Vektor mit den Nummern der zählbaren Einheiten verwendet. Das Maximum der Nummerierung entspricht der Anzahl der nummerierten Elemente.

vektor2 = 1 : length(vektor)

max(vektor2)
[1] 6
Praxis

In der Regel wird dieser Vektor nicht für das Zählen neu erzeugt. Stattdessen wird dieser Vektor oft für eine andere Operation erzeugt und zum Zählen wiederverwendet.