Ein vector (technisch ein atomic vector) ist in R eine Sammlung von Werten desselben type: häufig integer, numeric, character, logical; selten complex oder raw.
Sie werden zusammenhängend im Speicher abgelegt, ähnlich einem Array in C.
Übergibst du gemischte Eingaben, wandelt R sie stillschweigend in einen gemeinsamen Typ um, meist character. Das kann zu unerwarteten Ergebnissen führen.
v <- c(2, 5.4, "txt")
v
#> [1] "2" "5.4" "txt"
typeof(v)
#> [1] "character"
Wenn du alle Werte bereits hast, verwende c() (kurz für „concatenate“):
x <- 10
v <- c(4, 7, x)
Die Funktion c() ist sehr flexibel, und die Eingaben können andere Vektoren und Bereiche enthalten.
c() nimmt jede Anzahl und Vielfalt von Eingaben entgegen und fügt sie zu einem einzigen Vektor zusammen.
Wenn ein Vektor klein anfängt und zur Laufzeit stark wächst (zum Beispiel, wenn du in einer Schleife Werte hinzufügst), kann es deutlich schneller sein, einen langen Vektor im Voraus anzulegen, den du später mit echten Daten füllen kannst:
v <- vector(length = 100)
Das minimiert die Notwendigkeit, das Objekt zu kopieren: eine langsame und speicherhungrige Operation bei langen Vektoren.
Für einen Bereich aufeinanderfolgender Werte (aufsteigend oder absteigend) kannst du die :-Notation verwenden
v <- 1:5 # equivalent to c(1, 2, 3, 4, 5)
w <- 10:7 # c(10, 9, 8, 7)
In R sind Bereiche kein eigener Typ: nur eine Kurzschreibweise, um einen Vektor zu erzeugen.
Die Funktion seq() bietet eine feinere Steuerung:
# specify step size
seq(2, 11, by = 3) # c(2, 5, 8, 11)
# specify number of values, evenly-spaced
seq(2.5, 4, length.out = 5) # c(2.500, 2.875, 3.250, 3.625, 4.000)
Mit der Funktion rep() lassen sich wiederholende Muster leicht erzeugen:
count <- 3
rep(7, count)
#> [1] 7 7 7
rep(1:3, count)
#> [1] 1 2 3 1 2 3 1 2 3
rep(1:3, each = 2) # the "each" keyword is required in this case
#> [1] 1 1 2 2 3 3
Einige Bereiche sind als eingebaute Konstanten vordefiniert:
letters # LETTERS is the UPPERCASE equivalent
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
month.name
#> [1] "January" "February" "March" "April" "May" "June" "July" "August"
#> [9] "September" "October" "November" "December"
month.abb
#> [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
Operationen werden automatisch elementweise auf den Vektor angewendet. Die Schleifen, List Comprehensions und Rekursionen, die in anderen Sprachen üblich sind, brauchst du nicht, und aus Gründen der Performance solltest du sie möglichst vermeiden.
2 + 1:3 # c(3, 4, 5)
2 * 1:3 # c(2, 4, 6)
12 / 1:3 # c(12 6 4)
2 ^ (1:3) # c(2, 4, 8) : exponentiation, operator precedence order here needs ()
Auch Paare von Vektoren funktionieren, wobei die Elemente paarweise behandelt werden:
v <- 1:3
w <- 5:7
v + w
#> [1] 6 8 10
v * w
#> [1] 5 12 21
v ^ w
#> [1] 1 64 2187
Das ist mächtiger, als es zunächst scheint, und in späteren Konzepten gibt es noch mehr zu entdecken.
Wie in vielen Sprachen können wir den Index in eckigen Klammern verwenden:
v <- 4:7
v[2]
#> [1] 5
v[2:4]
#> [1] 5 6 7
Aber Vorsicht: R verwendet standardmäßig 1-basierte Indizes. Das ist bei wissenschaftlich geprägten Sprachen üblich (Fortran, Matlab, Julia), unterscheidet sich aber von der 0-basierten Indizierung von C und seinen vielen Nachfolgern.
Bereiche kannst du wie im obigen Beispiel verwenden, aber auch in der sehr flexiblen Funktion c():
v <- c(4, 7, 10)
w <- c(2, v[2:3], 11) # c(2, 7, 10, 11)
vectors (wie die meisten Dinge in R) gelten als veränderlich; mit einer ähnlich flexiblen Syntax kannst du einzelne oder mehrere Elemente setzen:
v <- 1:10
v[2] <- 42
v[4:6] <- c(11, 12, 13)
v
#> [1] 1 42 3 11 12 13 7 8 9 10
Programmierer, die andere Sprachen kennen, könnten vermuten, dass v[-1] ein Weg ist, auf das letzte Element eines Vektors zuzugreifen.
Falsch!
Dafür nimmst du tail().
v <- c(2, 4, 6) # defaults to last 6 entries
tail(v)
#> [1] 2 4 6
tail(v, n=1) # just the last entry
#> [1] 6
Negative Indizes sind nämlich ein Weg, ein Element zu entfernen:
v <- c(2, 4, 6)
v[-2]
#> [1] 2 6 # second element gone
Das gibt eine kürzere Kopie des Vektors zurück. v selbst bleibt unverändert.
Wenn du Vergleiche auf einen Vektor anwendest, erhältst du einen gleich langen Vektor boolescher Werte.
Das ist oft sehr praktisch in Funktionen wie all() und any():
v <- c(4, 7, 10)
v >= 6
#> [1] FALSE TRUE TRUE
all(v > 6)
#> [1] FALSE # not all elements match this condition
any(v > 6)
#> [1] TRUE # at least one element matches
Für kompliziertere logische Ausdrücke ist es wichtig, die Operatoren & und | zu verwenden, die auf Vektoren arbeiten.
Die doppelten Zeichen && und || sind nur für den Vergleich einzelner Werte gedacht, wie im [Konzept Boolesche Werte][concept-boolean] erläutert.
v <- c(4, 7, 10)
v %% 2 == 0 & v > 5
#> [1] FALSE FALSE TRUE
Darauf werden wir in späteren Themen zurückkommen. Merke dir vorerst nur das Format der Ausgabe in der Konsole:
1:20
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#> [18] 18 19 20
Die Zeilen beginnen mit Zahlen in [ ], die den Index des ersten Elements angeben (nützlich bei langen Vektoren, die über mehrere Zeilen umbrechen).
Aber warum steht vor einzelnen Werten ein [1]?
Es gibt in R keine echten skalaren Werte!
Was wie eine einzelne Zahl oder ein einzelner Buchstabe aussieht, ist in Wirklichkeit ein Vektor der Länge 1.
Andeutungen davon haben wir bereits in den Konzepten Grundlagen und Boolesche Werte bei den numerischen und logischen Typen gesehen.
Die oben beschriebenen Vektoren heißen formaler auch atomic vectors. Der Grund ist, dass sie nur einfache, unteilbare (daher „atomare“) Werte wie numeric, character, boolean enthalten können. Komplexere Strukturen können recursive vectors bilden, die wir einführen werden, wenn wir lists besprechen.