3 – Vektoren

Statistische Datenanalyse mit R

Autor

Clemens Brunner

Veröffentlicht

20. Oktober 2022

Erstellen von Vektoren

Der grundlegende (atomare) Datentyp in R ist der Vektor. Ein Vektor ist eine Datenstruktur, welche aus einem oder mehreren Elementen besteht. Demnach ist also auch eine Zahl (ein Skalar) wie z.B. 5 ein Vektor (mit einem Element).

Ein Vektor wird mit der Funktion c() erzeugt (steht für combine oder concatenate). Im folgenden Beispiel erzeugen wir einen Vektor mit vier Elementen und weisen ihm den Namen y zu:

(y = c(1, 2, 3.1415, -100))
[1]    1.0000    2.0000    3.1415 -100.0000
Hinweis

Wenn man in R einen Befehl in Klammern setzt, dann wird der daraus resultierende Wert immer auch in der Console ausgegeben. Normalerweise ist das nämlich bei Zuweisungen nicht der Fall.

Das Beispiel von oben könnte man also auch in zwei Zeilen schreiben, was aber natürlich mehr Tipparbeit ist:

y = c(1, 2, 3.1415, -100)
y

Die Länge eines Vektors (also die Anzahl der Elemente des Vektors) kann mit der Funktion length() bestimmt werden:

length(y)
[1] 4

Im folgenden Beispiel erzeugen wir einen Vektor a mit einem einzigen Element – in diesem Fall muss man die Funktion c() also gar nicht verwenden:

a = 6
length(a)
[1] 1

Mit c() können also Vektoren beliebiger Längen miteinander kombiniert werden:

c(666, y, 666, c(23, 24))
[1]  666.0000    1.0000    2.0000    3.1415 -100.0000  666.0000   23.0000
[8]   24.0000

Typen von Vektoren

Ein Vektor besteht immer aus Elementen desselben Typs. Man nennt Vektoren daher homogene Datentypen. Bis jetzt haben wir numerische Vektoren kennengelernt, welche ausschließlich aus Zahlen bestehen. Es gibt aber auch Vektoren, die logische Elemente oder Zeichen/Buchstaben enthalten. Man unterscheidet in R daher grob zwischen folgenden Vektoren:

  • Numerische Vektoren
  • Logische Vektoren
  • Zeichenkettenvektoren

In einer der nächsten Einheiten werden wir dann noch Faktoren als vierten wichtigen Typ kennenlernen (grundsätzlich gibt es in R aber noch viele weitere Datentypen).

Numerische Vektoren

Numerische Vektoren sind vom Typ numeric und beinhalten ausschließlich Zahlen, zum Beispiel:

c(2, 13, 15, 17)
[1]  2 13 15 17

Mit der Funktion class() kann man den Typ (die Klasse) eines Objektes bestimmen. Beispiele:

class(2)
[1] "numeric"
z = c(1.11, 2.33)
class(z)
[1] "numeric"
class(c(3.1, 2.2, 10))
[1] "numeric"

Logische Vektoren

Logische Vektoren bestehen ausschließlich aus den Werten TRUE oder FALSE (bitte auf die korrekte Schreibweise dieser Werte achten). Sie sind vom Typ logical.

class(TRUE)
[1] "logical"
class(c(FALSE, FALSE, TRUE))
[1] "logical"
Hinweis

Es ist möglich, die Werte TRUE und FALSE mit T und F abzukürzen. In der Praxis sollte man auf diese Abkürzungen aufgrund der schlechteren Lesbarkeit aber verzichten.

Logische Vektoren entstehen unter anderem durch Vergleiche zweiter Vektoren:

x = 5
class(x)
[1] "numeric"
x < 1
[1] FALSE
class(x < 1)
[1] "logical"

In R gibt es folgende Vergleichsoperatoren: >, >=, <, <=, == und !=. Vergleiche (bzw. logische Vektoren) können mit | (oder) und & (und) verknüpft und mit ! negiert werden. Gruppierungen durch Klammersetzung sind ebenfalls möglich.

!TRUE
[1] FALSE
!FALSE
[1] TRUE
(3 > 5) & (4 == 4)
[1] FALSE
(TRUE == TRUE) | (TRUE == FALSE)
[1] TRUE
((111 >= 111) | !(TRUE)) & ((4 + 1) == 5)
[1] TRUE
Wichtig

Der Gleichheitsoperator lautet == (also zwei Gleichheitszeichen) und nicht = (ein einziges Gleichheitszeichen).

Zeichenkettenvektoren

Zeichenkettenvektoren (Typ character) bestehen aus Zeichen, welche innerhalb von Anführungszeichen eingegeben werden. Es können sowohl einfache ' als auch doppelte " Anführungszeichen verwendet werden. Eine Zeichenkette kann aus Buchstaben, Ziffern und Sonderzeichen bestehen.

"Hello!"
[1] "Hello!"
'Hello!'
[1] "Hello!"
class("Hello!")
[1] "character"
(s = c("What's", 'your', "name?"))
[1] "What's" "your"   "name?" 
class(s)
[1] "character"

Die Funktion length() gibt die Länge des Vektors (d.h. die Anzahl der Elemente) und nicht die Anzahl der Zeichen einer Zeichenkette zurück. Dafür kann man die Funktion nchar() verwenden:

s = c('Hello!', 'world')
length(s)
[1] 2
nchar(s)
[1] 6 5

Zwang (Coercion)

Vektoren sind homogene Datentypen, d.h. sie enthalten nur Elemente desselben Typs. Wenn man versucht, einen Vektor mit Elementen mit unterschiedlichen Typen zu erstellen, wird dieser automatisch in einen Typ “gezwungen”, welcher alle Elemente abbilden kann. Wenn man also Zahlen mit Zeichenketten mischt, werden alle Elemente in Zeichenketten umgewandelt (da Zeichenketten im allgemeinen nicht als Zahlen dargestellt werden können, umgekehrt können aber Zahlen als Zeichenketten sehr wohl dargestellt werden).

(x = c(1, 2.14, "5", 6))
[1] "1"    "2.14" "5"    "6"   
class(x)
[1] "character"

Rechnen kann man mit dem Vektor im obigen Beispiel nicht mehr, da die Elemente nun Zeichenketten und keine Zahlen mehr sind.

Man kann mit folgenden Funktionen auch explizit eine Umwandlung in einen gewünschten Typ durchführen:

  • as.numeric()
  • as.logical()
  • as.character()

Folgendes Beispiel wandelt einen Zeichenketten-Vektor in einen numerischen Vektor um (dies funktioniert, weil im Beispiel alle Zeichenketten als Zahlen interpretiert werden können):

as.numeric(c("1", "2.12", "66"))
[1]  1.00  2.12 66.00

Wenn das nicht geht, wird eine Warnung ausgegeben und NA (steht für “Not Available”, also ein fehlender Wert) für das Element, welches sich nicht umwandeln lässt, angenommen:

as.numeric(c("1", "2.12", "X"))
Warning: NAs introduced by coercion
[1] 1.00 2.12   NA

Rechnen mit Vektoren

Mit numerischen Vektoren kann man Rechenoperationen durchführen – diese werden stets elementweise angewendet:

(y = c(1, 2, 3, 4))
[1] 1 2 3 4
y * 100 + 2  # Berechnung wird für jedes der 4 Elemente separat durchgeführt
[1] 102 202 302 402

Wie wir bereits wissen, gibt es die üblichen Operatoren +, -, *, und / für die Addition, Subtraktion, Multiplikation und Division. Das Zeichen ^ oder ** steht für “hoch” (berechnet also die Potenz von einer Basis zum Exponenten). Der Operator %/% berechnet die ganzzahlige Division und %% berechnet den Rest. Weitere praktische Funktionen sind abs() für den Betrag und sqrt() für die Quadratwurzel einer Zahl. Die Funktionen log() bzw. exp() berechnen den (natürlichen) Logarithmus bzw. die Exponentialfunktion. Mit sin() bzw. cos() kann man den Sinus bzw. Cosinus berechnen.

Recycling

Wenn zwei Vektoren in einer Berechnung unterschiedlich lang sind, dann wiederholt R die Werte des kürzeren Vektors, sodass dieser dann gleich viele Elemente hat wie der längere Vektor. Man bezeichnet dies als Recycling. Dies ist z.B. auch schon der Fall, wenn man einen Vektor mit vier Elementen mit einem Skalar (Vektor mit einem Element) multipliziert, wie im folgenden Beispiel:

c(1, 2, 3, 4) * 2
[1] 2 4 6 8

Der skalare Vektor 2 wird automatisch auf den Vektor c(2, 2, 2, 2) erweitert, daher entspricht die obige Operation eigentlich folgender elementweisen Berechnung:

c(1, 2, 3, 4) * c(2, 2, 2, 2)
[1] 2 4 6 8

Weiteres Beispiel:

c(1, 2, 3, 4) + c(0, 10)
[1]  1 12  3 14

Der kürzere Vektor c(0, 10) wird verdoppelt und die Berechnung wird elementweise durchgeführt:

c(1, 2, 3, 4) + c(0, 10, 0, 10)
[1]  1 12  3 14

Wenn sich das Recycling nicht genau ausgeht, d.h. wenn die Länge des längeren Vektors kein ganzzahliges Vielfaches des kürzeren Vektors ist, dann funktioniert das Recycling zwar grundsätzlich trotzdem, aber es wird eine Warnung ausgegeben:

c(1, 2, 3, 4) + c(0, 10, 8)
Warning in c(1, 2, 3, 4) + c(0, 10, 8): longer object length is not a multiple
of shorter object length
[1]  1 12 11  4

Die Berechnung entspricht daher folgender Operation:

c(1, 2, 3, 4) + c(0, 10, 8, 0)
[1]  1 12 11  4

Erstellen von Zahlenfolgen

Vektoren mit definierten Zahlenfolgen erstellt man mit : oder mit seq(). Bei der ersten Option ist die Schrittweite immer 1, bei der zweiten Option kann diese beliebig angepasst werden.

1:20
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
pi:10
[1] 3.141593 4.141593 5.141593 6.141593 7.141593 8.141593 9.141593
9:2
[1] 9 8 7 6 5 4 3 2
seq(1, 20)  # äquivalent zu 1:20
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
seq(20, 1)  # äquivalent zu 20:1
 [1] 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1
seq(0, 5, by=0.5)  # Schrittweite 0.5
 [1] 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
seq(5, 0, by=-0.5)  # negative Schrittweite notwendig!
 [1] 5.0 4.5 4.0 3.5 3.0 2.5 2.0 1.5 1.0 0.5 0.0
seq(0, 20, 2)  # gerade Zahlen
 [1]  0  2  4  6  8 10 12 14 16 18 20
seq(1, 20, 2)  # ungerade Zahlen
 [1]  1  3  5  7  9 11 13 15 17 19
seq(1, 3, length.out=10)  # Gesamtlänge des Ergebnisses soll 10 sein
 [1] 1.000000 1.222222 1.444444 1.666667 1.888889 2.111111 2.333333 2.555556
 [9] 2.777778 3.000000

Mit seq() kann man also Zahlenfolgen mit bestimmter Schrittweite (Argument by) oder mit bestimmter Gesamtlänge (Argument length.out) erzeugen.

Die Funktion rep() wiederholt gegebene Werte:

rep(0, 90)  # erzeuge einen Vektor mit 90 Nullen
 [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[39] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[77] 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Hier kann man auch die Bedeutung der Werte in eckigen Klammern erkennen, die vor jeder Ausgabezeile stehen: sie geben den Index des ersten Elements der Zeile an (also im Beispiel [1] für die erste Zeile, [39] für die zweite Zeile und [77] für die dritte Zeile).

Beachten Sie auch die unterschiedlichen Ergebnisse durch Verwendung der Argumente times bzw. each:

rep(c(0, 1, 2), times=10)
 [1] 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2
rep(c(0, 1, 2), each=10)
 [1] 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2
rep(c(0, 1, 2), times=c(10, 10, 10))  # gleiches Ergebnis wie mit each
 [1] 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2

Indizieren

Vektoren können indiziert werden, d.h. einzelne Elemente können herausgegriffen werden. Im Gegensatz zu vielen anderen Programmiersprachen beginnt R mit 1 zu zählen (d.h. das erste Element entspricht dem Index 1). Man verwendet dazu eckige Klammern, innerhalb derer die gewünschten Elemente angegeben werden.

Betrachten wir in den folgenden Beispielen den Vektor x, welcher aus 11 Elementen besteht:

(x = seq(10, 110, 10))
 [1]  10  20  30  40  50  60  70  80  90 100 110
length(x)
[1] 11

Nun erzeugen wir durch Indizieren neue Untermengen des bestehenden Vektors:

x[1]  # 1. Element
[1] 10
x[4]  # 4. Element
[1] 40
x[1:5]  # Elemente 1-5
[1] 10 20 30 40 50
x[c(1, 4, 8)]  # Elemente 1, 4 und 8
[1] 10 40 80

Negative Indizes bedeuten “alle Elemente außer die angegebenen”:

x[c(-1, -10)]
[1]  20  30  40  50  60  70  80  90 110
x[-c(1, 10)]
[1]  20  30  40  50  60  70  80  90 110

Man kann auch mit logischen Vektoren indizieren. Dazu erstellt man zuerst einen logischen Vektor (z.B. durch einen Vergleich) und verwendet diesen dann als Index innerhalb der eckigen Klammern (dies kann direkt in einem Schritt gemacht werden). Dabei werden jene Elemente herausgegriffen, für die der Indexvektor TRUE ist.

x
 [1]  10  20  30  40  50  60  70  80  90 100 110
x[c(TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE)]
[1] 10 30 90

Das folgende Beispiel illustriert die Erstellung des logischen Indexvektors durch einen Vergleich:

x > 40
 [1] FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
x[x > 40]
[1]  50  60  70  80  90 100 110

Idealerweise ist der logische Indexvektor gleich lang wie der zu indizierende Vektor. Falls der Indexvektor kürzer ist, findet wieder Recycling statt:

x[c(FALSE, TRUE)]
[1]  20  40  60  80 100

Benannte Vektoren

Vektoren können auch Elemente mit Namen enthalten. So kann man auch mit den Elementnamen anstatt mit der Position indizieren.

(vect = c(a=11, b=2, c=NA))  # Argumentnamen werden als Elementnamen verwendet
 a  b  c 
11  2 NA 
vect[2]
b 
2 
vect["b"]
b 
2 

Die Funktion names() gibt die Namen der Elemente zurück:

names(vect)
[1] "a" "b" "c"

Mit dieser Funktion kann man die Elementnamen eines Vektors auch nachträglich setzen:

x = 1:3
names(x)
NULL
names(x) = c("test", "value", "x")
x
 test value     x 
    1     2     3 

Fehlende Werte

In R können fehlende Werte mit dem speziellen Wert NA (Not Available) codiert werden.

(vect = c(15, 1.12, NA, 12, NA, 33.22))
[1] 15.00  1.12    NA 12.00    NA 33.22

Mit der Funktion is.na() können die fehlenden Werte bestimmt werden. So kann man einfach alle Werte aus einem Vektor extrahieren, die nicht NA sind.

is.na(vect)  # die fehlenden Werte
[1] FALSE FALSE  TRUE FALSE  TRUE FALSE
!is.na(vect)  # ! invertiert einen logischen Vektor
[1]  TRUE  TRUE FALSE  TRUE FALSE  TRUE
vect[!is.na(vect)]
[1] 15.00  1.12 12.00 33.22

Übungen

Übung 1

Berechnen Sie die Oberfläche (Grundflächen plus Mantelfläche) sowie das Volumen eines Zylinders mit Radius 5 und Höhe 9. Erzeugen Sie dafür die Variablen r und h. Speichern Sie die Ergebnisse in den Variablen A (Fläche) bzw. V (Volumen) ab. Wie lauten die Ergebnisse (also die Werte beider Variablen)?

Übung 2

Erstellen Sie einen Vektor x mit den Elementen 4, 18, -7, 16, 4 und -44. Erstellen Sie danach einen Vektor y, welcher die quadrierten Elemente aus x enthält (nutzen Sie dazu die Eigenschaft, dass R Rechenoperationen elementweise durchführt). Zum Schluss erstellen Sie einen Vektor z, indem Sie x und y aneinanderhängen. Mit welcher Funktion können Sie die Anzahl der Elemente in z bestimmen?

Übung 3

Gegeben sei folgender Vektor:

x = c(44, 23, -56, 98, 99, 32, 45, 22)

Welche Elemente aus x sind gerade? Welche Elemente sind ungerade? Erstellen Sie zwei entsprechende logische Vektoren, welche Sie dann zum Indizieren der geraden bzw. ungeraden Elemente von x verwenden können.

Hinweis: Erstellen Sie die logischen Indexvektoren mit einem Vergleich und nicht händisch (d.h. für die geraden Zahlen in diesem Beispiel wäre der gesuchte logische Indexvektor c(TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE), dies sollen Sie aber nicht so eingeben). Verwenden Sie stattdessen die Eigenschaft, dass gerade Zahlen einen Rest von 0 ergeben wenn man sie durch 2 dividiert. Ungerade Zahlen ergeben hier einen Rest von 1. Verwenden Sie daher den Operator %% für den Rest einer Division. Erstellen Sie dann mit einem Vergleich jeweils einen logischen Indexvektor (für die geraden Zahlen vergleichen Sie ob der Rest 0 ist, für die ungeraden Zahlen ob der Rest 1 ist), welchen Sie dann zum Indizieren verwenden können.

Übung 4

Erstellen Sie folgende Vektoren und geben Sie sie am Bildschirm aus:

  • Einen Vektor mit den ganzen Zahlen von 15 bis 40.
  • Einen Vektor mit den absteigenden Zahlen von 75 bis 61 in Dreierschritten.
  • Einen Vektor bestehend aus genau 35 Zahlen zwischen 14 und 15.

Übung 5

Erstellen Sie einen Zeichenketten-Vektor mit folgenden Einträgen: zuerst 10 mal "Placebo", dann 10 mal "Group 1" und schließlich 10 mal "Group 2" (d.h. das Ergebnis soll 30 Elemente haben).

Übung 6

Erstellen Sie einen Vektor k mit den geraden Zahlen von 0 bis 20 (am besten mit der Funktion seq() und der entsprechenden Schrittweite). Geben Sie dann durch Indizieren die folgenden Elemente dieses Vektors am Bildschirm aus:

  • Alle Elemente bis auf das 3. und 7. Element
  • Die ersten fünf Elemente
  • Die Elemente 2, 5 und 16 (fällt Ihnen hier etwas auf?)
  • Alle Elemente, die größer als 11 sind

Übung 7

Erstellen Sie folgenden Vektor:

t = c(10, 20, NA, 30, 40)

Berechnen Sie dann mit der Funktion mean() den Mittelwert von t. Was bewirkt der fehlende Wert NA? Sehen Sie in der Hilfe zum Befehl mean() nach, wie Sie fehlende Werte bei der Berechnung ignorieren können (welches optionale Argument müssen Sie setzen?) und führen Sie diese Berechnung durch.

Alternativ könnten Sie mit is.na() alle fehlenden Werte aus t identifizieren und dann die Funktion mean() auf alle nicht fehlenden Werte aus t anwenden (so wie in den Unterlagen gezeigt).

Übung 8

Gegeben seien folgende Standardabweichungen von fünf Messgrößen in einem Vektor s:

s = c(1, 11.3, 7.8, 3.4, 6)

Wie können Sie daraus in einem Schritt die fünf Varianzen berechnen?