Vektoren in R: der Datentyp vector
Da es in R eigentlich keine fundamentalen Datentypen gibt (wie ganze Zahlen, Gleitkommazahlen, Zeichen, logische Werte), sondern diese Spezialfall eines Vektors der Länge 1 sind, ist dieses Kapitel entscheidend für das Verständnis von R. Vektoren bestehen aus Komponenten mit identischem Speichermodus und die Komponenten sind numeriert (oder wie man auch sagt: indiziert). Vorgestellt werden hier Funktionen zum Erzeugen von Vektoren, der Zugriff auf die Komponenten eines Vektors, Diagnose-Funktionen für Vektoren und das Attribut names. Wie man Vektoren verknüpft und welche weiteren Funktionen zur Weiterverarbeitung von Vektoren existieren, wird im nächsten Kapitel gezeigt (Vektoren in R: Anwendungen).
- Einordnung des Artikels
- Einführung
- Erzeugen von Vektoren
- Die Funktion vector()
- Die Funktion c() (combine)
- Die Funktion seq() (sequence)
- Die Funktion sequence()
- Die Funktion rep() (replicate)
- Erzeugen von Zufallszahlen
- Zugriff auf die Komponenten eines Vektors
- Der Index eines Vektors
- Auswahl von Indizes
- Aufbau eines Vektors aus Komponenten
- Abschneiden eines Vektors mit head() oder tail()
- Zugriff auf die Komponenten eines Vektors mit Hilfe der Namen der Komponenten
- Dokumentation: ?Extract
- Diagnosefunktionen für Vektoren
- Die Ausgabe eines Vektors mit print()
- Die Anzahl der Komponenten eines Vektors: length()
- Modus und Speichermodus: mode() und storage.mode()
- Die Struktur eines Vektors str()
- Die Funktion is.vector()
- Die Funktion summary()
- Attribute von Vektoren
- Überblick
- Das Attribut names eines Vektors
- Setzen von Namen
- Zugriff auf die Komponenten eines Vektors über die Namen
- Löschen der Namen mit der Funktion unname()
- Setzen und Abfragen von Attributen: die allgemeinen Funktionen attr() und attributes()
- Selbstdefinierte Attribute
- Zusammenfassung
- Erzeugen von Vektoren
- Eigenschaften von Vektoren und Diagnose-Funktionen für Vektoren
- Attribute von Vektoren
Einordnung des Artikels
- Einführung in die Informatik
- Einführung in die Programmiersprache R
- Zusammengesetzte Datentypen in R
- Vektoren in R: der Datentyp vector
- Vektoren in R: Anwendungen
- Zusammengesetzte Datentypen in R
- Einführung in die Programmiersprache R
Im nächsten Kapitel Vektoren in R: Anwendungen werden dann zahlreiche Operationen und Funktionen vorgestellt, mit denen Vektoren weiterverarbeitet werden können.
Einführung
Vektoren sind die grundlegende Datenstruktur zur Weiterverarbeitung von Daten. Ein Vektor besteht aus einer bestimmten Anzahl von Komponenten, die alle vom gleichen Datentyp sein müssen. Meist sind es Zahlen, es können aber auch Zeichen, Zeichenketten oder logische Werte sein. Mischungen unterschiedlicher Datentypen sind nicht erlaubt: Versucht man dennoch einen derartigen Vektor zu erzeugen, werden die Komponenten zu einem geeigneten, gemeinsamen Datentyp konvertiert.
In diesem Abschnitt wird vorgestellt,
- wie Vektoren erzeugt werden,
- wie man auf die Komponenten eines Vektors zugreift,
- welche Funktionen R bereitstellt, um Vektoren zu untersuchen und
- wie man Attribute einsetzt, um weitere Informationen über Vektoren zu speichern.
Dieser letzte Teil über Attribute kann im ersten Durchgang durch diesen Programmier-Kurs weggelassen werden: Für den Anfänger ist es viel wichtiger, den Umgang mit Vektoren einzuüben. Um die abstrakten Erläuterungen aus der Übersicht über Datentypen in R zu Attributen besser zu verstehen, wird aber empfohlen, diesen Teil gründlich durchzuarbeiten, da hier die Eigenschaften von Attributen ausführlich am konkreten Beispiel names erklärt werden (und spätestens wenn man mit Listen und Data Frames arbeitet, benötigt man sie).
Im nächsten Kapitel Vektoren in R: Anwendungen werden die Funktionen vorgestellt, um Vektoren auszuwerten, zu verknüpfen oder zu verändern.
Später werden dann noch Funktionen aus der Familie der apply()-Funktionen vorgestellt, von denen einige Vektoren verarbeiten oder erzeugen. Und im Zusammenhang mit Kontrollstrukturen wird gezeigt, wie man über die Komponenten eines Vektors iterieren kann — die häufigste Anwendung von Vektoren besteht ja gerade darin, seine Komponenten nacheinander einer Weiterverarbeitung zuzuführen.
Erzeugen von Vektoren
Die Funktion vector()
Die Funktion vector() ist nur dazu da, einen Vektor gegebener Länge von einem bestimmten Datentyp anzulegen; die Komponenten werden mit default-Werten gefüllt (siehe folgende Beispiele). Um die Komponenten zu verändern, muss man auf sie zugreifen können, was unter Zugriff auf die Komponenten eines Vektors erklärt wird.
Die Funktion vector(mode, length)
erhält zwei Eingabewerte:
- Den Datentyp, für seine Komponenten (wie gesagt, alle Komponenten müssen identischen Datentyp besitzen); der Datentyp wird durch den Modus, also ein String wie "logical", "numeric" oder "character", festgelegt.
- Die Anzahl length der Komponenten.
Das folgende Beispiel definiert einen Vektor v mit 5 Komponenten (Zeile 1), die Komponenten sind Zahlen ("numeric"), der Speichermodus ist "double" (default-Wert für Zahlen). An den folgenden Beispielen wird man sehen, dass es gar nicht so einfach ist, eine Regel zu formulieren, welche Funktion zum Erzeugen von Vektoren den Speichermodus "integer" beziehungsweise "double" erzeugt.
v <- vector(mode = "numeric", length = 5)
v
# [1] 0 0 0 0 0
storage.mode(v)
# [1] "double"
Lässt man sich den Vektor v anzeigen (Zeile 3), so enthält er 5 Komponenten, die alle gleich null sind: null ist der default-Wert für numerische Datentypen.
Benötigt man tatsächlich den Speichermodus "integer", so lässt sich dies mit dem Argument mode = "integer"
erzwingen:
v <- vector(mode = "integer", length = 5)
v
# [1] 0 0 0 0 0
storage.mode(v)
# [1] "integer"
Um zu bestimmen, welche default-Werte die Modi "character" und "logical" haben, kann man das Skript mit dem Argument mode = "character"
beziehungsweise mode = "logical"
testen:
vc <- vector(mode = "character", length = 5)
vc
# [1] "" "" "" "" ""
vl <- vector(mode = "logical", length = 5)
vl
# [1] FALSE FALSE FALSE FALSE FALSE
Man sieht: der default-Wert für "character" ist der leere String (Zeile 3) und für logische Werte FALSE (Zeile 7).
Um festzustellen, wieviele Komponenten ein Vektor hat, ist es natürlich nicht nötig, den Vektor vollständig auszugeben und die Komponenten abzuzählen — was bei großen Anzahlen auch sehr fehleranfällig wäre. Für diese Abfrage gibt es die Funktion length(), die als Eingabewert den zu untersuchenden Vektor x erhält und die Anzahl seiner Komponenten zurückgibt:
v <- vector(mode = "numeric", length = 5)
length(v) # 5
mode(length(v)) # [1] "numeric"
storage.mode(length(v)) # [1] "integer"
Der Rückgabewert der Funktion length() ist eine Zahl mit Speichermodus "integer".
Im weiteren Verlauf wird sich herausstellen, dass die Funktion length() vermutlich die am häufigsten benötigte Funktion ist, wenn mit zusammengesetzten Datentypen gearbeitet wird. Spätestens wenn der sogenannte Recycling-Mechanismus vorgestellt wird, sollte klar werden, wie wichtig es ist, bei jedem Vektor (oder generell: bei einem zusammengesetzten Objekt) zu wissen, aus wievielen Komponenten er besteht.
Die Funktion c() (combine)
Die einfachste Möglichkeit, einen Vektor zu erzeugen, bietet die Funktion c() (combine); dazu wird im Argument von c() eine Folge von Zahlen angegeben:
v <- c(1, 3, 5)
v
# [1] 1 3 5
Die Funktion c() sorgt also dafür, dass die Argumente aneinandergehängt werden (concatenation).
Im letzten Beispiel haben alle Eingabewerte der Funktion c() identischen Datentyp; dies ist im Einklang damit, dass ein Vektor eine atomare Datenstruktur ist — unterschiedliche Datentypen der Komponenten sind nicht erlaubt. Allerdings ist es möglich, der Funktion c() unterschiedliche Datentypen zu übergeben: Falls sie zu einem gemeinsamen Datentyp konvertiert werden können, wird ein Vektor mit dem Modus des gemeinsamen Datentyps erzeugt. Um dies besser zu verstehen, muss an die Rangfolge der Modi erinnert werden, die bei den Typumwandlungen diskutiert wurde (siehe Typumwandlungen (coercion) in Einführung in R: Zeichen):
- Ein logischer Wert kann immer in eine Zahl umgewandelt werden.
- Eine Zahl kann immer in ein Zeichen (oder eine Zeichenkette umgewandelt werden)
Die umgekehrten Umwandlungen sind nicht immer möglich (Paradebeispiel: 'f'
kann nicht in eine Zahl verwandelt werden).
Berücksichtigt man zusätzlich die Speichermodi "integer" und "double" von Zahlen, so lautet die Rangfolge:
logical < integer < double < character
Damit ist eine Hierarchie festgelegt, womit der gemeinsame Modus gefunden wird, wenn die Funktion c() Eingabewerte mit unterschiedlichen Datentyp erhält: Aus der Liste wird der größte Modus ausgewählt, in den die anderen Komponenten konvertiert werden.
Das folgende Beispiel demonstriert dies mit einer Zahl und einem Zeichen:
w <- c(1, "2")
w
# [1] "1" "2"
mode(w)
[1] "character"
Zur Erklärung:
Zeile 1: Die Funktion erhält als Eingabewerte eine Zahl und ein Zeichen. Da das Zeichen so gewählt wurde, dass man es in eine Zahl verwandeln könnte, ist zunächst nicht klar, welches der gemeinsame Datentyp des hier definierten Vektors w ist: Zahl oder Zeichen?
Zeile 3: An der Ausgabe von w erkennt man: beide Komponenten von w sind Zeichen; der gemeinsame Datentyp ist also "character" — so wie es in obiger Hierarchie festgelegt wurde.
Zeile 6: Die Ausgabe des Modus von w (der mit dem Modus seiner Komponenten übereinstimmt) bestätigt dies.
Entsprechend obiger Hierarchie wird der größte Datentyp ausgewählt, auch wenn eine Typumwandlung zum kleineren Datentyp möglich wäre.
Das folgende Beispiel zeigt, dass die Umwandlung zum kleineren Datentyp nicht immer möglich ist:
w <- c(1, "f")
w
# [1] "1" "f"
mode(w)
[1] "character"
Daran sieht man sofort, warum immer die Umwandlung zum größeren Datentyp ausgeführt wird.
Auch logische Werte können Komponenten eines Vektors sein und werden konvertiert, falls sie mit einem anderen Modus kombiniert werden:
x <- c(TRUE, FALSE, 1)
x
# [1] 1 0 1
mode(x)
[1] "numeric"
y <- c(TRUE, "1")
y
# [1] "TRUE" "1"
mode(y)
# [1] "character"
z <- c(TRUE, "1", 1)
z
# [1] "TRUE" "1" "1"
mode(z)
# [1] "character"
Die Argumente von c() können selbst Vektoren sein. Im folgenden Beispiel wird zuerst der Vektor v wie oben erzeugt und anschließend wird v als Argument von c() verwendet:
v <- c(1, 3, 5)
u <- c(v, 7, 9, 11)
u
# [1] 1 3 5 7 9 11
length(u)
# [1] 6
Die Definition von u (Zeile 3) lässt zwei Interpretationen zu:
- u ist ein Vektor mit vier Komponenten, wobei die erste Komponente ein Vektor ist, die anderen drei Komponenten sind Zahlen.
- u ist ein Vektor mit 6 Komponenten.
Die Ausgabe von u zeigt, dass die zweite Interpretation richtig ist. Von einem etwas abstrakteren Standpunkt aus gesehen, würde die erste Interpretation bedeuten, dass das Objekt u eine rekursive Struktur besitzt. Wie in der Übersicht über Datentypen in R aber gezeigt wurde, haben Vektoren atomare Struktur.
Die Funktion c() scheint gegenüber der Funktion vector() nur Vorteile zu haben; denn sie erzeugt einen Vektor und erlaubt es, seine Komponenten sofort mit sinnvollen Werten zu belegen. Bei der Funktion vector() sind die Aufgaben getrennt: vorerst wird nur ein Vektor erzeugt und mit default-Werten gefüllt, anschließend müssen die Werte passend gesetzt werden.
Aus Bequemlichkeitsgründen ist tatsächlich die Funktion c() in den meisten Anwendungen vorzuziehen. Man sollte sich aber auch klar darüber sein, dass sie große Nachteile haben kann. Denn es ist eine sehr aufwendige Operation, einen Vektor im Speicher anzulegen: je nach Länge des Vektors und Datentyp seiner Komponenten muss der nötige Speicherplatz berechnet und reserviert werden.
Die Funktion vector() führt diese Reservierung des Speicherplatz nur einmal aus; die anschließenden Veränderungen der Komponenten sind wenig aufwendige Operationen. Wird dagegen die Funktion c() im folgenden Sinn missbraucht, kann sie sehr viel Rechenzeit beanspruchen: Man kann einen Vektor der Länge n auch dadurch erzeugen, dass man zuerst einen Vektor der Länge 1 erzeugt, dann die zweite Komponente mit c() anhängt, dann die dritte Komponente, und so weiter bis die gewünschte Länge erreicht ist. Hier wird bei jedem Schritt neuer Speicherplatz reserviert, was zu sehr langen Rechenzeiten führen kann.
Man sollte daher jeden Gebrauch der Funktion c() — insbesondere in Schleifen — gut überdenken und besser durch den Einsatz von vector() ersetzen.
Wenn später Attribute besprochen werden, wird eine Version der Funktion c() gezeigt, mit der sich zwei Aufgaben gleichzeitig erledigen lassen:
- ein Vektor wird initialisiert und
- das Attribut names wird gesetzt.
An dieser Stelle kann diese Version von c() noch nicht besprochen werden, da man zu ihrem Verständnis mehr Wissen über Attribute benötigt.
Die Funktion seq() (sequence)
Im Beispiel oben wurde der Vektor u als die Folge der ungeraden Zahlen von 1 bis 9 erzeugt. Für ein derart einfaches Bildungsgesetz einer Folge gibt es eine angemessene Funktion, nämlich seq(). Im folgenden Beispiel wird u mit Hilfe von seq() erzeugt:
u <- seq(from = 1, to = 9, by = 2)
u
# 1 3 5 7 9 11
Die drei Argumente von seq() sind selbsterklärend:
- Die Folge beginnt bei from; hier sind selbstverständlich nur Zahlen erlaubt — also keine Zeichen oder Vektoren.
- Sie endet bei to (was wie from eine Zahl sein muss).
- Der Zuwachs von einem Folgenglied zum nächsten wird durch by beschrieben, was natürlich auch negativ sein kann.
Wird by nicht angegeben, wird es auf 1 gesetzt:
v <- seq(from = 1, to = 9)
v
# 1 2 3 4 5 6 7 8 9
Da Folgen mit einem Zuwachs von 1 sehr häufig sind, gibt es dafür eine Kurzform:
v <- (1:9)
v
# 1 2 3 4 5 6 7 8 9
Die Klammern auf der rechten Seite in v <- (1:9)
können auch weggelassen werden; es ist also syntaktisch korrekt zu schreiben: v <- 1:9
. Dies führt aber oft zu schwer lesbaren Quelltexten.
Obige Verwendung von seq() mit den drei Argumenten kann womöglich schiefgehen: was passiert, wenn by so gewählt wird, dass to nicht getroffen wird, wie im folgenden Beispiel:
w <- seq(from = 1, to = 10, by = 2)
w
# [1] 1 3 5 7 9
Die Zahl, die 10 überschreiten würde, wird nicht in die Folge aufgenommen; daher endet die Folge bei 9.
Die Funktion seq() hat noch ein weiteres Argument, das häufig eingesetzt werden kann: length.out. Damit kann angegeben werden, wie viele Komponenten der zu erzeugende Vektor hat. Die Folge der ungeraden Zahlen von 1 bis 9 kann auch folgendermaßen erzeugt werden:
v <- seq(from = 1, to = 9, length.out = 5)
v
# [1] 1 3 5 7 9
Die Wirkugsweise ist jetzt die, dass das Intervall von 1 bis 9 in äquidistante Teile zerlegt wird, wobei genau length.out Komponenten erzeugt werden. Man muss hier berücksichtigen, dass length.out nicht die Anzahl der Zwischenräume ist (hier nur 4).
Weiter sollte man beachten, dass Rundungsfehler eine Rolle spielen können:
u <- seq(from = 1, to = 9, length.out = 10)
u
# [1] 1.000000 1.888889 2.777778 3.666667 4.555556 5.444444 6.333333 7.222222 8.111111 9.000000
In der Dokumentation sind noch weitere Versionen der Funktion seq() aufgeführt, die kurz besprochen werden sollen:
- seq(along.with)
- seq_along(along.with)
- seq_len(length.out)
Oben wurde gezeigt, dass etwa (1:10)
als Kurzform für seq(from = 1, to = 10)
verwendet werden kann. Manchmal benötigt man derartige Vektoren, aber das Problem stellt sich in einer anderen Form: Gegeben ist ein Vektor v und man benötigt einen Vektor (1:n)
, wobei n die Länge von v ist.
Klar, dass man sich diesen gesuchten Vektor mit
# Vektor v ist gegeben
u <- (1:length(v))
erzeugen kann.
Die Funktion seq() bietet aber zwei Varianten, die weniger Rechenzeit benötigen:
v <- c(1, 5, 2, 4, 1, 6, 3, 3, 6, 2)
length(v)
# [1] 10
u <- seq(along.with = v)
u
# [1] 1 2 3 4 5 6 7 8 9 10
w <- seq_along(v)
w
# [1] 1 2 3 4 5 6 7 8 9 10
Dabei ist die letzte Version (Zeile 9), also w <- seq_along(v)
, die Version, die am schnellsten sein sollte.
Die letzte Version von seq() dient wieder dazu, den Vektor (1:length.out)
zu erzeugen:
v <- seq_len(length.out = 10)
v
# [1] 1 2 3 4 5 6 7 8 9 10
Auch diese Funktion sollte schneller sein als alle entsprechenden Realisierungen. Diese letzte Version ist gleichwertig mit dem Aufruf von seq(), wenn nur das Argument length.out gesetzt ist.
Die Funktion sequence()
Die Funktion sequence() kann als Verallgemeinerung von seq_len() aufgefasst werden. Als Eingabewert erhält sie einen Vektor nvec im Speichermodus "integer"; gibt man stattdessen einen Vektor im Speichermodus "double" ein, wird automatisch zu "integer" konvertiert.
Gibt man nur eine einzige ganze Zahl n ein, so erzeugt sequence(n)
die Folge (1:n)
, liefert also dasselbe Ergebnis wie seq_len(length.out = n)
. Bei der Eingabe eines echten Vektors nvec wird zu jeder Komponente nvec[i]
die Folge (1:nvec[i])
erzeugt und diese Folgen werden anschließend aneinandergehängt und somit zu einem Vektor zusammengefasst. Das folgende Skript zeigt einige Beispiele für die Verwendung von sequence():
# Eingabe einer Zahl:
sequence(2)
# [1] 1 2
# automatische Konversion bei Eingabe als double:
sequence(2.5)
# [1] 1 2
# Eingabe eines Vektors:
sequence(c(4,2))
# [1] 1 2 3 4 1 2
sequence(c(4,2,1))
# [1] 1 2 3 4 1 2 1
Im letzten Beispiel wird der Vektor (4, 2, 1) als Eingabewert für sequence() verwendet. Diese drei Zahlen werden in die drei Vektoren (1:4), (1:2), (1) verwandelt und anschließend aneinandergehängt.
Die Funktion rep() (replicate)
Eine andere Folge, die man sehr häufig braucht, ist eine konstante Folge — also eine Folge, in der sich ein Wert x mehrfach wiederholt. Mit Hilfe der Funktion rep() (replicate) kann sie erzeugt werden:
v <- rep(x = 17, times = 5)
v
# 17 17 17 17 17
Der Wert x, der mehrfach wiederholt werden soll, muss keine Zahl sein. Es kann wiederum ein Vektor eingesetzt werden:
v <- (1:3)
w <- rep(x = v, times = 5)
w
# 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
Wird das Argument times nicht gesetzt, wird der default-Wert 1 verwendet.
Im letzten Beispiel wurde der Vektor (1:3)
fünfmal wiederholt; manchmal benötigt man auch die Wiederholung jeder Komponente eines Vektors, wobei man die Anzahl der Wiederholungen vorgeben möchte. Dies geschieht durch das Argument each von rep(). Im folgenden Beispiel werden die Komponenten von (1:3)
einmal, zweimal beziehungsweise dreimal wiederholt:
v <- (1:3)
v1 <- rep(x = v, each = 1)
v1
# [1] 1 2 3
v2 <- rep(x = v, each = 2)
v2
# [1] 1 1 2 2 3 3
v3 <- rep(x = v, each = 3)
v3
[1] 1 1 1 2 2 2 3 3 3
Es ist klar, dass v1 == v
(Zeile 1 und Zeile 5) und dass length( rep(x = v, each = n) ) == length(v) * each
.
Die Länge kann aber auch durch das weitere Argument length.out gesetzt werden, wie im folgenden Beispiel zu sehen ist (der Vektor v aus dem letzten Beispiel wird hier wiederverwendet):
v <- (1:3)
v4 <- rep(v, each = 3, length.out = 7)
v4
# [1] 1 1 1 2 2 2 3
v5 <- rep(v, each = 3, length.out = 13)
v5
# [1] 1 1 1 2 2 2 3 3 3 1 1 1 2
Im ersten Fall bei v4 wird der eigentlich zu erwartende Vektor (mit 9 Komponenten) auf 7 Komponenten abgeschnitten; im zweiten Fall bei v5 ist length.out = 13 größer als 9: jetzt wird der Vektor solange wiederholt bis die 13 Komponenten erreicht sind (dies wird später als recycling-Mechanismus genauer erklärt).
Die beiden Argumente times und each können auch gleichzeitig gesetzt werden:
v <- (1:3)
w <- rep(x = v, times = 5, each = 2)
w
# [1] 1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3
Ohne das Argument times = 5
würde die Folge 1 1 2 2 3 3
entstehen; times = 5
sorgt dafür, dass diese Folge fünf Mal wiederholt wird.
Erzeugen von Zufallszahlen
Gerade um Testdaten zu erzeugen (um damit etwa Funktionen zu testen), benötigt man häufig Folgen von Zufallszahlen. In R sind zahlreiche Funktionen vorbereitet, um zu den wichtigen Wahrscheinlichkeitsverteilungen Folgen von Zufallszahlen zu erzeugen. Diese werden hier nicht vorgestellt. Es wird nur ein Beispiel vorgestellt: Erzeugen von gleichverteilten Zufallszahlen in einem Intervall (das Skript ist natürlich nur im Sinne eines Zufallsgenerators reproduzierbar):
v <- runif(n = 10, min = 1, max = 7)
v
# [1] 6.071646 6.233566 2.124287 4.630006 1.341263 4.159638 6.837287 5.951352 1.800106 3.034529
w <- as.integer(v)
w
[1] 6 6 2 4 1 4 6 5 1 3
Zur Erklärung:
Zeile 1: Die Funktion runif() erzeugt die Folge von Zufallszahlen; dabei steht runif als Abkürzung für random uniform. Die Funktion runif() besitzt drei Eingabewerte:
- Die Länge n der Folge.
- Das Minimum min für den Wertebereich, aus dem die Zahlen gewählt werden (der default-Wert ist 0).
- Das Maximum max für den Wertebereich, aus dem die Zahlen gewählt werden (der default-Wert ist 1).
Hier werden 10 Zahlen zwischen 1 und 7 erzeugt. Da keine Anweisung gegeben ist, dass es sich um ganze Zahlen handeln soll, werden Gleitkommazahlen erzeugt.
Zeile 3 und 4: Die Zufallszahlen werden ausgegeben.
Zeile 6: Die Zahlen werden in ganze Zahlen verwandelt; da sie dabei einfach abgeschnitten werden, sind es ganze Zahlen von 1 bis 6 (genauer: befindet sich die Zahl 7.000000 in der Folge v, so enthält w die Zahl 7).
Zeile 7 und 8: die Folge sieht jetzt aus wie das Ergebnis beim 10-maligen Würfeln.
Aus der Gleichverteilung lässt sich durch geeignete Transformation jede beliebige Wahrscheinlichkeitsverteilung erzeugen. Die vordefinierten Funktionen zum Erzeugen von Zufallszahlen findet man im Paket stats unter Uniform, Normal, Geometric und so weiter.
Zugriff auf die Komponenten eines Vektors
Der Index eines Vektors
In der Übersicht über Datentypen in R wurden die Eigenschaften eines Vektors beschrieben:
- er kann beliebig viele Komponenten haben,
- die Komponenten müssen identischen Datentyp besitzen,
- die Komponenten sind indiziert (durchnumeriert).
Der Zugriff auf die Komponenten eines Vektors kann mit Hilfe des Index erfolgen. Der Index wird dazu in eckige Klammern geschrieben.
Im folgendem Beispiel wird ein Vektor v mit 9 Komponenten erzeugt; dadurch ist implizit der Index definiert, der von 1 bis 9 läuft. Um etwa auf die fünfte Komponente zuzugreifen, muss lediglich v[5]
aufgerufen werden:
v <- (1:9)
v
# 1 2 3 4 5 6 7 8 9
v[5]
# 5
Man kann dies auch einsetzen, um die Komponenten zu manipulieren:
v[5] <- 0
v
# 1 2 3 4 0 6 7 8 9
Man beachte, dass der Index der ersten Komponente eines Vektors immer 1 ist; in vielen Programmiersprachen beginnt der Index bei 0 (und bei einem Vektor mit n Komponenten hat dann die letzte Komponente den Index n-1).
Es stellt sich sofort die Frage, was bei einem Zugriff auf einen ungültigen Index passiert:
v <- (1:9)
v
# 1 2 3 4 5 6 7 8 9
v[0]
# integer(0)
v[10]
# NA
v[-1]
# 2 3 4 5 6 7 8 9
Zur Erklärung:
Zeile 1: Der Vektor v wird wie oben mit den natürlichen Zahlen von 1 bis 9 initialisiert; v hat somit 9 Komponenten (der Index läuft von 1 bis 9).
Zeile 6: Zugriff auf die nullte Komponente von v mit v[0]
. Mit integer(0) wird gesagt, dass es sich um einen Vektor vom Speichermodus "integer" handelt, dessen Länge null ist.
Zeile 9: Der Index 10 ist nicht verfügbar, man erhält als Ausgabe NA (not available).
Zeile 12: Das Minuszeichen vor der 1 bewirkt, dass die erste Komponente aus dem Vektor v entfernt wird. Man sollte v[-1]
besser als eine zusammengesetzte Anweisung lesen:
- aus dem Vektor v wird die erste Komponente entfernt,
- der dadurch entstehende Vektor wird ausgegeben.
Auswahl von Indizes
Wie oben gezeigt, kann auf die Komponenten eines Vektors direkt mit der Angabe des Index zugegriffen werden. Allerdings ist in R eine Zahl immer nur der Spezialfall eines Vektors: kann man dann auch auf eine Menge von Indizes zugreifen? Ja, der Zugriff kann
- entweder direkt durch die Angabe eines Vektors von Indizes erfolgen
- oder indirekt, indem in den eckigen Klammern ein logischer Ausdruck geschrieben wird, der einen oder mehrere Indizes auswählt.
Zwei direkte Zugriffe sind im folgenden Beispiel gezeigt:
v <- (1:9) # 1 2 3 4 5 6 7 8 9
v[(2:8)]
# 2 3 4 5 6 7 8
v[c(1, 5, 9)]
# 1 5 9
Dieser direkte Zugriff kann auch verwendet werden, um Komponenten aus einem Vektor zu entfernen (wie oben beschrieben durch negative Indizes):
v <- (1:9) # 1 2 3 4 5 6 7 8 9
w <- v[-(2:8)] # die Komponenten 2 3 4 5 6 7 8 werden entfernt
w
# 1 9
Im folgenden Beispiel wird der indirekte Zugriff gezeigt: obiger Vektor v wird in zwei neue Vektoren zu zerlegt, nämlich:
- in einen Vektor v1, der diejenigen Komponenten enthält, die kleiner sind als 5 (Zeile 3)
- in einen Vektor v2, der die Komponenten größer oder gleich 5 enthält (Zeile 8).
v <- (1:9)
v1 <- v[v < 5]
v1
# 1 2 3 4
v2 <- v[v >= 5]
v2
# 5 6 7 8 9
Man kann sich leicht vorstellen, wie der indirekte Zugriff arbeitet: für jeden Index wird die Bedingung (in den eckigen Klammern) überprüft. Falls sie zutrifft, wird die Komponente im Vektor belassen, falls sie nicht zutrifft, wird die Komponente aus dem Vektor entfernt. Eine weitere Sortierung findet nicht statt.
In den bisherigen Beispielen wurde auf die Komponenten eines gegebenen Vektors zugegriffen und damit eventuell ein neuer Vektor initialisiert. Das folgende Beispiel zeigt, wie man den Zugriff auf Komponenten mit einer Veränderung dieser Komponenten verbinden kann:
v <- (1:9)
v[(v < 3) | (v > 8)] <- NA
v
# [1] NA NA 3 4 5 6 7 8 NA
In Zeile 2 sorgt der logische Ausdruck dafür, dass auf bestimmte Komponenten von v zugegriffen wird; dadurch dass auf der rechten Seite des Zuweisungs-Operators ein sinnvoller Ausdruck steht, wird den soeben ausgewählten Komponenten ein neuer Wert (hier NA) zugewiesen.
Es gibt sogar eine einfache Möglichkeit, wie man auf alle Komponenten eines Vektors gleichzeitig zugreifen kann: indem man die eckigen Klammern leer lässt. Das folgende Skript zeigt, wie man das zum Erzeugen eines Vektors einsetzen kann:
v <- vector(mode = "numeric", length = 5)
v
# [1] 0 0 0 0 0
v[] <- 17
v
# [1] 17 17 17 17 17
v[]
# [1] 17 17 17 17 17
In Zeile 1 wird ein Vektor der Länge 5 erzeugt. Der Aufruf von vector() füllt die Komponenten mit den default-Werten 0.
In Zeile 5 wird auf alle Komponenten von v gleichzeitig zugegriffen: alle Komponenten werden gleich 17 gesetzt. Man hätte dies auch mit der Funktion rep() erledigen können, aber dann muss der Vektor neu erzeugt werden, was eventuell mehr Rechenzeit beanspruchen kann als der Zugriff mit v[]
.
Zeile 9 und 10 zeigen, dass v[]
auch zur Ausgabe aller Komponenten verwendet werden kann.
Aufbau eines Vektors aus Komponenten
Wie in den Beispielen im Unterabschnitt Die Funktion vector() gezeigt wurde, kann ein Vektor gewünschter Länge mit Hilfe der Funktion vector() erzeugt werden; er wird zuerst mit default-Werten belegt, die später abgeändert werden können.
Hier stellt sich die Frage, ob man diesen Vorgang nicht vereinfachen kann. Um das Ergebnis vorwegzunehmen: wie so oft gibt es zahlreiche Lösungen für ein Problem und die im Anschluss vorgestellte Variante erscheint einfacher, sollte aber nicht angewendet werden — vor allem bei langen Vektoren beansprucht sie sehr viel Rechenzeit. Es gilt hier alles, was über das Erzeugen von Vektoren mit der Funktion c() oben gesagt wurde.
Die bequeme Methode, um Vektoren zu erzeugen ist, dass man von einer Zahl ausgeht, diese als erste Komponente eines Vektors auffasst und weitere Komponenten anhängt. Da in R Zahlen generell Vektoren der Länge 1 sind, ist dies möglich — in vielen anderen Programmiersprachen nicht, da Zahlen und Vektoren unterschiedlich behandelt werden.
# NICHT nachahmen - insbesondere für lange Vektoren
x <- 5
x[1]
# [1] 5
x[2] <- 17
x
# [1] 5 17
Man sieht, dass R problemlos eine Zahl zu einem Vektor erweitert. Gerade bei langen Vektoren ist es aber vorzuziehen, den Vektor erst mit vector() zu erzeugen und dann die Werte der Komponenten zu setzen.
Eine andere Methode, um an einen gegebenen Vektor x weitere Komponenten anzuhängen, erlaubt die Methode append(). Ihr Vorteil ist, dass sie flexibler eingesetzt werden kann als ihr Name vermuten lässt: Mit Hilfe des Argumentes after kann bestimmt werden, nach welcher Stelle die zusätzlichen Komponenten in x eingefügt werden; der Vektor dieser zusätzlichen Komponenten wird durch das Argument values gesetzt. Der default-Wert von after ist length(x)
, das heißt die zusätzlichen Komponenten werden hinten angehängt. Das folgende Skript zeigt das Verhalten von append():
v <- (1:5)
w <- append(x = v, values = (6:9))
w
# [1] 1 2 3 4 5 6 7 8 9
w <- append(x = v, values = (6:9), after = 1)
w
# [1] 1 6 7 8 9 2 3 4 5
Abschneiden eines Vektors mit head() oder tail()
Oftmals wird von einem Vektor v nur ein Teil benötigt. Ist es der vordere oder der hintere Teil, muss man nicht auf die Komponenten direkt zugreifen wie es in den letzten Unterabschnitten gezeigt wurde; sondern man kann einen gegebenen Vektor v mit head() beziehungsweise tail() abschneiden und in einen Vektor mit gegebener Länge n verwandeln:
v <- (1:9)
v1 <- head(x = v, n = 4)
v1
# [1] 1 2 3 4
v2 <- tail(x = v, n = 4)
v2
# [1] 6 7 8 9
Zugriff auf die Komponenten eines Vektors mit Hilfe der Namen der Komponenten
Bisher wurde immer mit Hilfe des Index auf die Komponenten eines Vektors zugegriffen — man verwendet also gerade die grundlegende Eigenschaft eines Vektors, nämlich dass er aus mehreren Elementen von identischem Datentyp besteht, wobei jedes Element eindeutig durch einen Index identifiziert werden kann.
Da die Indizes immer nichtssagende Zahlen sind, kann in manchen Anwendungen die Verwendung von Indizes eher Verwirrung stiften. So wurde oben mehrmals das Beispiel des Vektors
v <- (1:9)
verwendet, um den Zugriff auf die Komponenten zu erklären. Dieses Beispiel hat den Nachteil, dass der Index i mit dem Wert der i-ten Komponente vi des Vektors v übereinstimmt. Ist etwa von der 5 die Rede, ist zunächst nicht klar, ob damit i = 5 oder v5 gemeint ist.
Um diese Verwirrung zu vermeiden, kann man den Komponenten eines Vektors Namen geben und dann auf die Komponenten über die Namen zugreifen. Im Beispiel unten wird:
- Ein Vektor mit drei Komponenten erzeugt (hier: der Einheitsvektor in x-Richtung).
- Die Komponenten des Vektors erhalten Namen (hier "x", "y" und "z").
- Der Zugriff auf die Komponenten erfolgt über die Namen.
Allerdings erfordert dieses Beispiel die Kenntnis der Attribute eines Vektors, hier speziell des Attributes names. Attribute werden weiter unten erklärt; das Beispiel wird dennoch hier schon aufgeführt, da diese Zugriffsart sehr wichtig ist (insbesondere werden die Quelltexte besser verständlich, wenn die Komponenten eine inhaltliche Bedeutung haben, die sich durch die Namen gut ausdrücken lassen) und es systematisch hierher gehört.
# Vektor erzeugen: Einheitsvektor in x-Richtung
v <- vector(mode = "numeric", length = 3)
v[1] <- 1 # v = (1, 0, 0)
# Namen für die Koordinaten setzen
coord <- c("x", "y", "z")
attr(x = v, which = "names") <- coord
# Attribute abfragen
attributes(v)
# $names
# [1] "x" "y" "z"
# Zugriff auf Komponenten über Namen (mit doppelten Klammern)
v[["x"]]
# [1] 1
v[["y"]]
# [1] 0
v[["z"]]
# [1] 0
Zeile 7 und 10: Unverständlich sind hier noch:
- wie das Attribut names gesetzt wird (mit Hilfe der Funktion attr()) und
- wie man die Attribute eines Objektes abfragt (mit Hilfe der Funktion attributes()).
Zeile 11 und 12: Auch die Ausgabe der Attribute ist hier noch unverständlich. Das Dollar-Zeichen wird bei den Attributen unten noch erklärt; es spielt vor allem bei Listen eine große Rolle. Die Ausgabe sollte man zunächst so lesen: Der Vektor v besitzt ein Attribut, nämlich names, und dieses ist ein Vektor mit drei Komponenten (sie wurden ja in Zeile 7 durch coord gesetzt).
Zeile 15 bis 20: Man kann jetzt auf die Komponenten von v über die Namen zugreifen, allerdings muss man den Namen in doppelte eckige Klammern schreiben (und nicht in einfache eckige Klammern wie den Index). Und man darf nicht vergessen, dass die Namen Zeichen (im Allgemeinen: Zeichenketten) sind, also in Anführungsstriche geschrieben werden müssen.
Dokumentation: ?Extract
Im Paket base unter ?Extract finden sich ausführliche Informationen über
- den Zugriff auf die Komponenten eines Vektors und
- wie Komponenten verändert werden können.
Es sind auch die entsprechenden Beschreibungen für andere Datentypen enthalten (wie Matrizen, Felder, Listen), die hier noch nicht verständlich sind.
Diagnosefunktionen für Vektoren
Wie bereits unter der Übersicht über Datentypen in R beschrieben, gibt es in R eine Vielzahl von Diagnose-Funktionen, die wertvolle Informationen über ein Objekt liefern. Für Vektoren werden hier folgende Funktionen besprochen:
- print()
- length()
- mode() und storage.mode()
- str()
- is.vector()
- summary().
Die Ausgabe eines Vektors mit print()
Wie jedes Objekt kann auch ein Vektor mit Hilfe der Funktion print() ausgegeben werden. Dabei ist print() so implementiert, dass einfach die Komponenten des Vektors ausgegeben werden, wobei Leerzeichen als Trennungszeichen zwischen den Komponenten verwendet werden.
Da print() sehr oft eingesetzt wird, reicht es den Namen eines Objektes x in eine Programmzeile zu schreiben, dies ist in R die Abkürzung für print(x).
v <- (1:9)
print(v)
# [1] 1 2 3 4 5 6 7 8 9
v
# [1] 1 2 3 4 5 6 7 8 9
Die Funktion print() besitzt ein weiteres Argument digits, das beim Umgang mit Gleitkommazahlen sehr wichtig ist: damit kann die Anzahl der Nachkommastellen beschränkt werden:
x1 <- 1/3
x2 <- 10
x3 <- 1.99
x4 <- 1.94
x5 <- 1.95
x6 <- 1.96
v <- c(x1, x2, x3, x4, x5, x6)
print(x = v, digits = 1)
# [1] 0.3 10.0 2.0 1.9 1.9 2.0
print(x = v, digits = 2)
# [1] 0.33 10.00 1.99 1.94 1.95 1.96
print(x = v, digits = 3)
# [1] 0.333 10.000 1.990 1.940 1.950 1.960
print(x = v)
# [1] 0.3333333 10.0000000 1.9900000 1.9400000 1.9500000 1.9600000
Nach welcher Strategie gerundet wird, ist insbesondere in Zeile 9 und 10 zu erkennen. Ohne eine Angabe von digits wird dessen default-Wert verwendet (Zeile 18 und 19).
Nachdem geklärt ist, wie man auf die Komponenten eines Vektors zugreift, ist auch verständlich, warum jede Ausgabe mit einem print()-Befehl mit 1 startet: Dies soll anzeigen, dass die Ausgabe mit der ersten Komponente des Vektors beginnt. Und gibt man nur eine Zahl aus, beginnt die Ausgabe ebenfalls mit 1: denn eine Zahl wird intern als Vektor der Länge 1 gespeichert (siehe Zeile 3 unten).
Erwähnenswert ist auch das Verhalten, wenn die Ausgabe eines Vektors einen Zeilenumbruch enthält: in der jeweils neuen Zeile wird in eckigen Klammern angegeben, welche Komponente zu Beginn der Zeile gezeigt wird (siehe Zeile 8 unten). Wieviele Komponenten pro Zeile ausgegeben werden, hängt natürlich von der Breite des Konsolenfensters ab.
Das folgende Skript zeigt nochmals die wichtigsten Fälle:
x <- 5
print(x)
# [1] 5
v <- (1:50)
print(v)
# [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
# [33] 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
Die Funktionen toString() und format() bieten weitere Möglichkeiten, wie sich die Ausgabe eines Vektors (oder allgemeiner: eines Objektes) anpassen lässt. Sie werden hier aber nicht besprochen.
Die Anzahl der Komponenten eines Vektors: length()
Ganz zu Beginn dieses Abschnittes wurde bereits die Funktion length() vorgestellt: sie hat als Eingabewert einen Vektor x und gibt die Anzahl seiner Komponenten an. Da R bei Operationen mit Vektoren den sogenannten recycling-Mechanismus verwendet, muss man bei nahezu allen Anwendungen von Vektor-Operationen die Länge der beteiligten Objekte kennen — andernfalls kann der recycling-Mechanismus unerwünschte Nebeneffekte erzeugen; die Funktion length() ist daher die vermutlich am häufigsten eingesetzte Diagnose-Funktion für Vektoren.
Modus und Speichermodus: mode() und storage.mode()
Da Vektoren in R nicht prinzipiell von atomaren Datentypen zu unterscheiden sind, gilt für Vektoren bezüglich des Modus und des Speichermodus alles, was dazu bereits über atomare Datentypen gesagt wurden.
Der Modus eines Vektors kann sein:
- "logical",
- "numeric" oder
- "character".
Der Speichermodus ist nur bei "numeric" vom Modus verschieden, da er genauer beschreibt, wie die Zahlen intern gespeichert werden:
- "integer" oder
- "double".
Per default ist bei Zahlen der Speichermodus immer double, das folgende Beispiel zeigt aber, wie schwer es vorauszusagen ist, welcher Speichermodus beim Erzeugen eines Vektors tatsächlich verwendet wird:
v <- (1:9)
mode(v) # "numeric"
storage.mode(v) # "integer"
w <- c(1, 2)
mode(w) # "numeric"
storage.mode(w) # "double"
v1 <- seq(from = 1, to = 9, by = 2)
v1
# [1] 1 3 5 7 9
storage.mode(v1) # "double"
v2 <- seq(from = 1, to = 9)
v2
# [1] 1 2 3 4 5 6 7 8 9
storage.mode(v2) # "integer"
Sowohl für mode() als auch für storage.mode() gibt es replacement-Versionen: sie können verwendet werden, um den Modus oder Speichermodus eines Vektors selbst zu setzen.
Im folgenden Beispiel wird ein numerischer Vektor ("numeric") erzeugt und in einen Vektor von Zeichen ("character") verwandelt:
w <- c(1, 2)
mode(w)
# [1] "numeric"
storage.mode(w)
# [1] "double"
mode(w) <- "character"
w
# [1] "1" "2"
storage.mode(w)
# "character"
Mit dem Speichermodus kann man genau so vorgehen.
Die Struktur eines Vektors str()
Es gibt in R eine Funktion, die auf jedes Objekt angewendet werden kann und die in sehr kompakter Weise die wichtigsten Eigenschaften des Objektes ausgibt: str(), wobei str als Abkürzung für structure steht.
Insbesondere wenn es schwer fällt, die Eigenschaften eines Objektes anhand des Quelltextes zu erraten, kann man sich mit dieser Funktion schnell behelfen. (Typisches Beispiel: man setzt eine Funktion ein, an deren Namen zwar erraten kann, welche Aufgabe sie erfüllt, aber der Datentyp des Rückgabewertes erschließt sich nicht aus ihrem Namen. Mit Hilfe von str() kann man schnell das Rückgabe-Objekt untersuchen.)
Es folgen zwei Beispiele, an denen erkennbar ist, welche Informationen durch str() angezeigt werden:
v <- c(1, 3, 5)
str(v)
# num [1:3] 1 3 5
v.log <- c(TRUE, FALSE)
str(v.log)
# logi [1:2] TRUE FALSE
Ausgegeben werden also:
- der Modus des Vektors,
- der Vektor der Indizes (in der Kurzform
1:n
), - die Werte der Komponenten (bei langen Vektoren bricht die Folge ab; um sie anzuzeigen ist es besser, die Funktion print() einzusetzen).
Die Funktion is.vector()
Mit der Funktion is.vector(x) kann getestet werden, ob ein Objekt x (der Eingabewert der Funktion) ein Vektor ist oder nicht. Gerade wenn Vektoren und andere zusammengesetzte Datentypen (wie Listen, Faktoren, Data Frames) gleichzeitig eingesetzt werden, verliert man leicht den Überblick. Bei der Anwendung von is.vector() muss man aber beachten, dass es in R eigentlich keine atomare Datentypen gibt; also ist zum Beispiel eine Zahl ein Vektor der Länge 1 und wendet man die Funktion is.vector() auf eine Zahl an (Zeile 2 im folgenden Beispiel), erhält man TRUE.
x <- 5
is.vector(x) # TRUE
bool <- TRUE
is.vector(bool) # TRUE
v <- (1:5)
is.vector(v) # TRUE
is.vector(v[1]) # TRUE
Dies gilt auch für Boolesche Variablen und für Komponenten eines Vektors (Zeile 5 und 9).
Die Funktion summary()
Mit der Funktion summary() kann eine einfache statistische Auswertung eines Vektors angezeigt werden. Der Rückgabewert ist eine Tabelle (table) mit folgenden Informationen:
- Minimum
- erstes Quantil
- Median
- Mittelwert
- drittes Quantil
- Maximum.
Die Bedeutung des Datentyps Tabelle und speziell wie man auf die in ihr enthaltenen Werte zugreifen kann, wird in einem eigenen Abschnitt erklärt.
Das folgende Beispiel zeigt eine einfache Anwendung von summary():
v <- (1:9)
summary(v)
# Min. 1st Qu. Median Mean 3rd Qu. Max.
# 1 3 5 5 7 9
Zusätzlich kann man die Anzahl der Nachkommastellen durch das weitere Argument digits setzen:
v <- c(0, 1, 1)
summary(v, digits = 3)
# Min. 1st Qu. Median Mean 3rd Qu. Max.
# 0.000 0.500 1.000 0.667 1.000 1.000
Attribute von Vektoren
Überblick
Im Kapitel Übersicht über Datentypen in R wurde allgemein beschrieben, wie Attribute eingesetzt werden können, nämlich um Zusatzinformationen in einem Objekt zu speichern. Dort wurde schon die wichtigsten Eigenschaften von Attributen genannt:
- Attribute sollten immer nur Zusatzinformationen über die Objekte speichern.
- Jedes Attribut hat die Gestalt
name = value
. - Man kann jedem Objekt im Prinzip beliebig viele Attribute zuordnen.
- Grundsätzlich unterscheidet man zwei Arten von Attributen:
- Die vordefinierten Attribute, die speziell behandelt werden und die man nur so einsetzen sollte, wie es in der Dokumentation beschrieben wird; Beispiele sind names (für Vektoren), dim und dimnames (für Felder).
- Selbstdefinierte Attribute, die man beliebig einsetzen kann. Man sollte nur darauf achten, die Objekte nicht zu kompliziert zu strukturieren (oft ist ein bereits bestehender Datentyp besser geeignet als ein mit vielen Attributen aufgeblähter Datentyp).
- Zum Setzen und Abfragen der vordefinierten Attribute gibt es geeignete Funktionen, die man einsetzen sollte. Man könnte diese Aufgaben auch mit den allgemeinen Funktionen für Attribute erledigen, aber dann werden die Quelltexte nur unübersichtlicher.
Für den Einsteiger in R ist es zunächst wichtig, die vordefinierten Attribute für die Datentypen vector, matrix, array, factor, ordered, table, list, data frame kennenzulernen. Später wird man sehen, dass Attribute eingesetzt werden, um eigene Klassen zu definieren, also um objekt-orientierte Programmierung zu verwirklichen.
Am Beispiel des Datentyps Vektor (vector) sollen diese etwas abstrakt formulierten Eigenschaften von Attributen veranschaulicht werden. Dazu wird das Beispiel von oben aufgegriffen, in dem mit dreidimensionalen Vektoren gearbeitet werden soll; das vordefinierte Attribut names wird dabei eingesetzt, um nicht über den Index sondern über den Namen auf die Komponenten des Vektors zuzugreifen. Zum Schluss wird dann gezeigt, wie man selber Attribute definieren kann.
Das Attribut names eines Vektors
Setzen von Namen
Im folgenden Beispiel wird ein dreidimensionaler Vektor erzeugt. Anschließend wird das Attribut names gesetzt: es soll dazu verwendet werden, die drei Koordinaten des Vektors mit x, y, z zu bezeichnen. Dazu müssen die Namen als Zeichenketten eingegeben werden.
Die Anzahl der Namen muss natürlich der Anzahl der Komponenten des Vektors entsprechen; was passiert, wenn dies nicht der Fall ist, wird weiter unten gezeigt.
Zum Setzen und Abfragen der Namen wird jeweils die Funktion names() eingesetzt:
- Zum Setzen in der replacement-Version,
- Zum Abfragen in der einfachen Version.
Am Ende werden die Namen wieder gelöscht; die Werte der Komponenten sind davon nicht betroffen.
v <- c(1, 0, 0) # Einheitsvektor in x-Richtung
v
# [1] 1 0 0
str(v)
# num [1:3] 1 0 0
names(v)
# NULL
# Namen für die Koordinaten vereinbaren und als Attribut names setzen
coord <- c("x", "y", "z")
names(v) <- coord
names(v)
# [1] "x" "y" "z"
# Die Ausgabe erfolgt MIT Namen:
v
# x y z
# 1 0 0
# Ebenso wird in der Struktur das Attribut names angezeigt:
str(v)
# Named num [1:3] 1 0 0
# - attr(*, "names")= chr [1:3] "x" "y" "z"
v[["x"]]
# [1] 1
# Löschen der Namen
names(v) <- NULL
str(v)
# num [1:3] 1 0 0
Zur Erklärung:
Zeile 1: Der Vektor v wird mit Hilfe der Funktion c() definiert; es handelt sich um den Einheitsvektor in x-Richtung — wobei der Zugriff vorerst nur über den Index erfolgen kann, da noch nicht definiert ist, dass die erste Komponente die x-Komponente ist.
Zeile 3 bis 7: Die Ausgabe von v beziehungsweise dessen Struktur ist wie erwartet; denn es werden die 3 Komponenten angezeigt beziehungsweise zusätzlich, dass v von numerischem Typ mit 3 Komponenten ist.
Zeile 9 und 10: Neu ist Zeile 9, in der die Namen der Komponenten von v mit Hilfe der Funktion names() abgefragt werden. Die Ausgabe NULL bedeutet, dass keine Namen existieren; die genaue Bedeutung von Ausnahme-Erscheinungen wie NULL wurde in einem eigenen Abschnitt besprochen Zahlenbereiche und spezielle Werte in R (Inf, NaN, NA und NULL).
Zeile 13: Die Namen (als Zeichenketten) für die drei Komponenten werden in einem Vektor coord abgespeichert; man beachte, dass die Länge von coord mit der Länge von v übereinstimmt.
Zeile 14: Mit Hilfe der replacement-Version von names() werden im Vektor v die Namen für die drei Komponenten gesetzt. Der Aufruf von names() in der replacement-Version führt zu keiner Ausgabe.
Zeile 16 und 17: Lässt man jetzt die Namen von v ausgegeben, erhält man gerade die drei Zeichenketten (erkennbar an den Anführungsstrichen), die man zuvor in coord abgelegt hat.
Zeile 20 bis 22: Die Ausgabe von v zeigt jetzt — in tabellarischer Anordnung — die Namen und die Werte der Komponenten.
Zeile 25 bis 27: Ebenso ist an der Struktur erkennbar, dass das Attribut names gesetzt ist und welche Werte die Namen haben.
Zeile 29: Der Zugriff auf eine Vektor-Komponente kann mit Hilfe des Namens der Komponente erfolgen.
Zeile 33 bis 36: Zum Löschen der Namen wird die replacement-Version von names() verwendet, wobei auf der rechten Seite NULL gesetzt wird.
Das letzte Skript, in dem die Namen der Komponenten gesetzt werden, erscheint etwas umständlich: Zuerst wird der Vektor initialisiert, dann wird ein Vektor mit den Komponenten-Namen vorbereitet, dann erst werden die Komponenten-Namen gesetzt. Zumindest trennt das Skript klar zwischen den beiden Aufgaben:
- Initialisierung des Vektors und
- Zuweisung der Namen an die Komponenten.
Um sich — wenn man das Attribut names benötigt — etwas Arbeit zu sparen, kann die Funktion c() auch so eingesetzt werden, dass diese beiden Aufgaben gleichzeitig erledigt werden; das folgende Skript zeigt wie.
v <- c(x = 1, y = 0, z = 0)
v
# x y z
# 1 0 0
str(v)
# Named num [1:3] 1 0 0
# - attr(*, "names")= chr [1:3] "x" "y" "z"
Zur Erklärung:
Zeile 1: Der Vektor v — es ist wieder der Einheitsvektor in x-Richtung — wird mit Hilfe der Funktion c() definiert. Allerdings wird c() jetzt in der Version eingesetzt, die sofort das Attribut names setzt: Die drei Argumente von c() besitzen jeweils die Form name = value
, wobei name
jeweils für den Attribut-Namen der Komponente steht und value
für den Wert der Komponente. Aber man sieht ganz klar, dass jetzt die beiden Aufgaben (Vektor initialisieren und Namen setzen) vermischt sind.
Man beachte, dass die Namen der Attribute nicht als Zeichen eingegeben werden müssen, es heißt also nicht v <- c("x" = 1, "y" = 0, "z" = 0)
. Die Namen müssen ja Zeichen (Zeichenketten) sein und daher werden sie intern als Zeichenketten behandelt.
Zeile 3 bis 5: Die Ausgabe des Vektors v zeigt die bekannte tabellarische Form mit Namen und Werten.
Zeile 7 bis 9: Die Ausgabe der Struktur von v zeigt ebenso die Werte des Vektors und das gesetzte Attribut.
Die hier besprochene Version der Funktion c() ist somit zugleich eine Veranschaulichung für die oben getroffene Feststellung, dass die vordefinierten Attribute:
- wenn möglich eingesetzt werden sollen (man also nicht versuchen soll, gleichwertige Attribute selbst zu definieren) und
- dass sie so eingesetzt werden sollen, wie es in der Dokumentation beschrieben wird.
Oder anders formuliert: Welchen Aufwand müsste man betreiben, um eine Funktionalität wie in v <- c(x = 1, y = 0, z = 0)
selber bereitzustellen?
Oben wurde betont, dass die Länge von v und die Länge des Vektors mit den Namen für die Komponenten von v übereinstimmen sollen. Das folgende Skript zeigt, was passiert, wenn dies nicht der Fall ist:
- Zuerst, wenn zu wenige Namen gesetzt werden,
- dann, wenn zu viele Namen gesetzt werden.
rm(v)
v <- c(1, 0, 0)
# Namen für die Koordinaten setzen: nur 2 Namen für den dreidimensionalen Vektor
coord <- c("x", "y")
names(v) <- coord
v
# x y <NA>
# 1 0 0
rm(v)
v <- c(1, 0, 0)
# Namen für die Koordinaten setzen: jetzt 4 Namen für den dreidimensionalen Vektor
coord <- c("x", "y", "z", "a")
names(v) <- coord
# Error in names(v) <- coord :
# 'names' attribute [4] must be the same length as the vector [3]
v
# [1] 1 0 0
Zur Erklärung:
Zeile 1 und 12: Das Objekt v wird jeweils gelöscht, damit nicht mit einem älteren Objekt (und dessen Attribut names) gearbeitet wird.
Zeile 5 und 6: Obwohl v drei Komponenten hat, werden nur zwei Namen vereinbart.
Zeile 8 bis 10: Die Ausgabe von v zeigt die tabellarische Ansicht von Namen und Werten der Komponenten. Allerdings hat die dritte Komponente keinen Namen und daher wird NA gezeigt; NA steht für not available und signalisiert, dass der Name nicht zugänglich ist. Es tritt also kein Fehler ein, man muss nur bei der Weiterverarbeitung des Vektors v bedenken, dass jetzt eine Name mit NA belegt ist (siehe Zahlenbereiche und spezielle Werte in R (Inf, NaN, NA und NULL)).
Zeile 16: Versucht man für den dreidimensionalen Vektor vier Namen zu setzen, erhält man eine Fehlermeldung.
Zeile 21: Der Fehler bezieht sich nur auf den Versuch, die Namen zu setzen; man kann dennoch mit dem Vektor v weiterarbeiten — er besitzt eben kein Attribut names.
Man kann sich auch fragen, wie dies aussieht, wenn die Kurzform von c() verwendet wird, die Werte und Namen der Komponenten in einem setzt. Im folgenden Beispiel werden in c() nur zwei Namen vergeben, aber drei Komponenten gesetzt:
rm(v)
v <- c(x = 1, y = 0, 0)
v
# x y
# 1 0 0
str(v)
# Named num [1:3] 1 0 0
# - attr(*, "names")= chr [1:3] "x" "y" ""
attributes(v)
# $names
# [1] "x" "y" ""
v[[""]]
# Error in v[[""]] : subscript out of bounds
v[["x"]]
# [1] 1
Zur Erklärung:
Zeile 1 und 2: Das Objekt v wird zunächst wieder gelöscht und anschließend neu initialisiert. In der Funktion c() werden nur die ersten beiden Komponenten mit Namen versehen.
Zeile 4 bis 6: Die Ausgabe von v zeigt die bekannte tabellarische Anordnung, wobei die dritte Komponente nicht mit NA bezeichnet wird, sondern der Name einfach leer bleibt.
Zeile 8 bis 10: Die Struktur von v zeigt, dass der Name der dritten Komponente ein leerer String ist: ""
.
Zeile 12 bis 14: Auch die Ausgabe der Attribute von v zeigt, dass drei Namen gesetzt sind (x, y und ein leerer String).
Zeile 16 und 17: Da aber ein leerer String nicht als Name erlaubt ist, lässt sich damit nicht auf die dritte Komponente zugreifen: Zeile 16 ist einen Syntax-Fehler.
Zeile 19 und 20: Der Zugriff mit "x" ist dagegen möglich.
Zugriff auf die Komponenten eines Vektors über die Namen
Oben wurde erklärt: Die wesentliche Eigenschaft eines Vektors darin besteht, dass seine Komponenten indiziert sind und dass man über den Index auf die Komponenten zugreifen kann; dazu werden die einfachen eckigen Klammern verwendet, wie das folgende Beispiel nochmals zeigt:
v <- c(1, 0, 0)
v[1]
# [1] 1
Man kann auch über die Namen auf die Komponenten des Vektors zugreifen — natürlich nur, wenn sie zuvor gesetzt wurden. Jetzt werden die doppelten eckigen Klammern verwendet und man muss beachten, dass die Namen Zeichenketten sind, also in Anführungsstriche (oder Hochkommas) geschrieben werden müssen:
v <- c(1, 0, 0) # Einheitsvektor in x-Richtung
# Namen für die Koordinaten setzen
coord <- c("x", "y", "z")
names(v) <- coord
# Zugriff auf die Komponenten
v[["x"]]
# [1] 1
v[["y"]]
# [1] 0
v[[x]]
# Error: object 'x' not found
Ohne die Anführungsstriche erhält man eine Fehlermeldung (Zeile 15 und 16).
Man kann sich die Wirkugsweise der doppelten eckigen Klammern etwa folgendermaßen vorstellen:
- die innere eckige Klammer verwandelt den Namen in einen Index,
- die äußere eckige Klammer realisiert den Zugriff auf die Komponente des Vektors über diesen Index.
Im Abschnitt über Listen wird gezeigt, in welchem Sinn Listen eine Verallgemeinerung von Vektoren sind. Auch bei Listen kann man auf ihre Komponenten über einfache und doppelte eckige Klammern zugreifen — ersteres geschieht mit dem Index der Komponente, letzteres mit dem Namen der Komponente.
Löschen der Namen mit der Funktion unname()
Oben wurde gezeigt, wie man das Attribut names setzt und wie man die Namen wieder löschen kann (oben wurde dazu die replacement-Version von names() verwendet, um mit names(v) <- NULL
die Namen der Komponenten von v zu löschen). Es gibt sogar eine eigene Funktion, um das Attribut names zu löschen, nämlich unname(). Diese Funktion kann auch eingesetzt werden, um bei Matrizen (matrix) und Feldern (array) das Attribut dimnames zu löschen.
Das folgende Skript zeigt ein Beispiel für die Verwendung von unname():
v <- c(x = 1, y = 3, z = 5)
str(v)
# Named num [1:3] 1 3 5
# - attr(*, "names")= chr [1:3] "x" "y" "z"
w <- unname(obj = v)
str(w)
# num [1:3] 1 3 5
# Beachte: v bleibt unverändert:
str(v)
# Named num [1:3] 1 3 5
# - attr(*, "names")= chr [1:3] "x" "y" "z"
Die Funktion c() wird in der Version verwendet, in der sie sofort die Namen der Komponenten setzt (siehe Ausgabe in Zeile 4 und 5).
Der Vektor w hat identische Komponenten wie v, aber durch den Aufruf von unname() (in Zeile 7) sind die Namen beseitigt (Zeile 9). Man beachte aber, dass durch den Aufruf von unname(obj = v)
das Objekt v unverändert bleibt (es behält also die Namen der Komponenten, siehe Zeile 12 bis 14). Vielmehr wird durch unname(obj = v)
ein neues Objekt erzeugt, das in allen Eigenschaften mit v übereinstimmt, nur das Attribut names ist gelöscht.
Man wird sich an der Stelle vielleicht fragen, warum es wichtig sein kann, das Attribut names zu beseitigen. Dazu muss man sich vergegenwärtigen, dass Vektoren meist mit Zahlen gebildet werden, Namen der Komponenten aber Zeichen (oder Zeichenketten) sind und daher sehr viel Speicherplatz belegen. Gerade bei der Verarbeitung von sehr langen Vektoren und wenn die Namen auf andere Objekte übertragen werden, kann sehr viel Speicherplatz verschwendet werden. Es ist dann eventuell besser, die Namen nur zur Aufbereitung der Daten zu verwenden (vor allem um leicht lesbare Quelltexte und übersichtliche Datenstrukturen zu erzeugen), sie aber vor der eigentlichen Weiterverarbeitung zu löschen.
Setzen und Abfragen von Attributen: die allgemeinen Funktionen attr() und attributes()
Das Attribut names ist eines der bevorzugt behandelten Attribute in R; insbesondere gibt es dafür die Funktionen names(x)
und names(x) <- value
, mit denen die Namen der Komponenten eines Vektors abgefragt und gesetzt werden können. Damit man auch auf beliebige Attribute zugreifen und sie setzen kann, gibt es die Funktionen attr() und attributes(), und zwar:
- in der Version zum Abfragen von Attributen und
- in der Version zum Setzen von Attributen (replacement-Version).
Mit attr() wird eine ausgewählte Menge von Attributen angesprochen (es kann natürlich auch nur ein einziges Attribut ausgewählt werden), mit attributes() werden sämtliche Attribute angesprochen.
Das folgende Skript zeigt, wie mit Hilfe der beiden Versionen von attr() die Namen für einen Vektor gesetzt, abgefragt und wieder gelöscht werden (das Skript ahmt die Operationen von oben nach — verzichtet aber auf die Verwendung von names()):
v <- c(1, 0, 0) # Einheitsvektor in x-Richtung
v
# [1] 1 0 0
str(v)
# num [1:3] 1 0 0
attr(x = v, which = "names")
# NULL
# Namen für die Koordinaten setzen
coord <- c("x", "y", "z")
attr(x = v, which = "names") <- coord
attr(x = v, which = "names")
# [1] "x" "y" "z"
# Die Ausgabe erfolgt MIT Namen:
v
# x y z
# 1 0 0
# Ebenso wird in der Struktur das Attribut names angezeigt:
str(v)
# Named num [1:3] 1 0 0
# - attr(*, "names")= chr [1:3] "x" "y" "z"
# Löschen der Namen
attr(x = v, which = "names") <- NULL
str(v)
# num [1:3] 1 0 0
Zur Erklärung:
Zeile 1: Der Vektor v wird wie oben mit Hilfe der Funktion c() definiert; es handelt sich um den Einheitsvektor in x-Richtung — wobei der Zugriff vorerst nur über den Index erfolgen kann, da noch nicht definiert ist, dass die erste Komponente die x-Komponente ist.
Zeile 3 bis 7: Die Ausgabe von v beziehungsweise dessen Struktur ist wie erwartet; denn es werden die 3 Komponenten angezeigt beziehungsweise zusätzlich, dass v von numerischem Typ mit 3 Komponenten ist.
Zeile 9 und 10: Neu ist Zeile 9, in der die Namen der Komponenten von v mit Hilfe der Funktion attr() abgefragt werden. Untersucht wird das Objekt x = v
und speziell die Komponente which = "names"
. Die Ausgabe NULL bedeutet wieder, dass keine Namen existieren.
Zeile 13: Die Namen (als Zeichenketten) für die drei Komponenten werden in einem Vektor coord abgespeichert; man beachte, dass die Länge von coord mit der Länge von v übereinstimmt.
Zeile 14: Mit Hilfe der replacement-Version von attr() werden im Vektor v die Namen für die drei Komponenten gesetzt. Die Argumente sind wie bei der Abfrage in Zeile 9: x = v
und which = "names"
. Der Aufruf von attr() in der replacement-Version führt zu keiner Ausgabe.
Zeile 16 und 17: Lässt man jetzt den Wert des Attributes "names" von v ausgeben, erhält man gerade die drei Zeichenketten (erkennbar an den Anführungsstrichen), die man zuvor in coord abgelegt hat.
Zeile 20 bis 22: Die Ausgabe von v zeigt jetzt — in tabellarischer Anordnung — die Namen und die Werte der Komponenten.
Zeile 26 bis 28: Ebenso ist an der Struktur erkennbar, dass das Attribut names gesetzt ist und welche Werte die Namen haben.
Zeile 30 bis 33: Zum Löschen der Namen wird die replacement-Version von attr() verwendet, wobei auf der rechten Seite NULL gesetzt wird.
Am Beispiel oben ist insbesondere zu erkennen, dass das Attribut "names" von v selber ein Vektor ist, der gerade die drei "character"-Komponenten besitzt, die im Vektor coord gesetzt wurden. Man kann auch ausdrücklich abfragen, welche Struktur die Attribute haben:
# Das Attribut names wird wie im Beispiel oben gesetzt
str(attr(x = v, which = "names"))
# chr [1:3] "x" "y" "z"
Für den Fall, dass ein Objekt mehrere Attribute besitzt oder man nicht weiß, welche Attribute für ein Objekt gesetzt sind, lassen sich alle Attribute mit Hilfe der Funktion attributes() abfragen. Es ist dann aber nicht klar, welchen Rückgabewert die Funktion attributes() besitzen soll: sie muss ja für jedes Attribut einen Vektor anzeigen und diese Vektoren müssen zu einem Objekt verschmolzen werden. Der hierfür verwendete Datentyp ist der einer Liste (list), der bisher allerdings noch nicht besprochen wurde.
Das folgende Skript erzeugt nochmals den Einheitsvektor in x-Richtung und lässt dann sämtliche Attribute mit Hilfe der Funktion attributes() ausgeben:
v <- c(1, 0, 0) # Einheitsvektor in x-Richtung
v
# [1] 1 0 0
# Namen für die Koordinaten setzen
coord <- c("x", "y", "z")
attr(x = v, which = "names") <- coord
attributes(v)
# $names
# [1] "x" "y" "z"
str(attributes(v))
# List of 1
# $ names: chr [1:3] "x" "y" "z"
Zur Erklärung:
Zeile 1 bis 8: wurde schon mehrmals verwendet.
Zeile 10 bis 12: Es sollen alle Attribute von v angezeigt werden. Da nur ein Attribut gesetzt wurde, wird ein Vektor angezeigt (Zeile 12). An der Ausgabe mit dem Dollar-Zeichen ist erkennbar, dass die Attribute immer zu einer Liste verschmolzen werden, wobei jede Komponente der Liste eine Bezeichnung und einen Wert besitzt. Die Bezeichnung ist hier der Name des Attributes, also names; der Wert ist der character-Vektor der drei Namen "x", "y" und "z".
Zeile 14 bis 16: Lässt man sich die Struktur von attributes(v) ausgeben, so sieht man ausdrücklich, dass es sich um eine Liste mit einer Komponente handelt.
Für die Funktion attributes() gibt es we für attr() wieder eine replacement-Version; diese wird hier allerdings noch nicht besprochen, da noch nicht erklärt wurde, wie man eine Liste erzeugt. Aber es sollte klar sein, wie die replacement-Version von attributes() arbeitet:
- Man bereitet sich in einer Liste value alle Attribute vor; dabei ist jede Komponente der Liste ein Attribut (mit einem Namen und Werten).
- Beim Aufruf der replacement-Version von attributes(v) <- value werden zunächst alle Attribute von v gelöscht und anschließend werden die Attribute aus value gesetzt.
Es sollte durch die Diskussion der Funktionen attr() und attributes() klar geworden sein, dass man für vordefinierte Attribute auch die entsprechenden Funktionen verwenden soll (also etwa names() um das Attribut names zu setzen oder abzufragen) — die Quelltexte sind einfacher und leichter lesbar. Für selbstdefinierte Attribute ist man dagegen auf die allgemeinen Funktionen attr() und attributes() angewiesen; selbstdefinierte Attribute werden im folgenden Unterabschnitt besprochen.
Zunächst sollte klar geworden sein, dass es bei den Funktionen zum Abfragen oder Setzen von Attributen eine Hierarchie gibt:
- Für vordefinierte Attribute gibt es die spezifischen Funktionen, die nach Möglichkeit eingesetzt werden sollen (Paradebeispiel ist die Funktion names(), die oben ausführlich vorgestellt wurde).
- Besitzt ein Objekt x mehrere Attribute, so kann mit
attr(x, which)
auf ein (oder mehrere) spezielles Attribut zugegriffen werden; dies ist bei selbstdefinierten Attributen nicht zu vermeiden, bei vordefinierten Attributen aber nicht nötig. - Nur wenn man nicht weiß, welche Attribute ein Objekt obj besitzt, soll man die unspezifische Funktion
attributes(obj)
einsetzen.
Selbstdefinierte Attribute
Das Beispiel, in dem für dreidimensionale Vektoren das Attribut names gesetzt wird, soll nun erweitert werden: es soll ein zusätzliches Attribut definiert werden.
Manchmal werden Objekte zu Vektoren zusammengefasst, die inhaltlich sehr verschieden sind — bei dem hier vorgestellten Beispiel ist das nicht der Fall, da keine der drei Raumrichtungen vor den anderen irgendwie ausgezeichnet ist. Bei unterschiedlichen Objekten kann es aber sinnvoll sein, dass sie mit geeigneter Anzahl an signifikanten Stellen dargestellt werden — und diese Anzahl möchte man irgendwo festhalten. Warum soll man sie nicht als Attribut definieren?
Das folgende Beispiel zeigt nun folgende Eigenschaften von Attributen:
- Wie werden Attribute selbst definiert?
- Wie lautet die Ausgabe der Attribute, wenn ein Objekt mehrere Attribute besitzt?
- Die Werte von Attribute können von beliebigem Datentyp sein; daher wird man hier Zahlen als Werte einsetzen und einen geeigneten Vektor definieren, der die Anzahl der signifikanten Stellen für die drei Komponenten festgelegt. (Später wird man eine Funktion schreiben, die das Attribut liest und automatisch die Ausgabe mit der richtigen Stellenzahl erzeugt.)
- Das Beispiel wirkt etwas gekünstelt und zeigt, dass man die Attribute nicht missbrauchen soll — oft lassen sich einfachere Lösungen finden. Und meist reichen die vordefinierten Attribute aus.
rm(v)
v <- c(1, 0, 0)
coord <- c("x", "y", "z")
names(v) <- coord
attributes(v)
# $names
# [1] "x" "y" "z"
digs <- c(5, 5, 3)
attr(x = v, which = "digits") <- digs
attributes(v)
# $names
# [1] "x" "y" "z"
#
# $digits
# [1] 5 5 3
Zur Erklärung:
Zeile 1 und 2: Der Vektor v wird zunächst gelöscht und anschließend wieder mit dem Einheitsvektor in x-Richtung initialisiert.
Zeile 4 und 5: Wie schon mehrmals wird das Attribut names gesetzt.
Zeile 7 bis 9: Sämtliche Attribute werden angezeigt; da bisher nur names gesetzt wurde, enthält die Liste nur eine Komponente (der Gestalt name = value).
Zeile 11: Die Zahlen 5, 5, 3 sollen die Anzahl der signifikanten Stellen für die x-, y-, z-Komponente sein; diese drei Zahlen werden zu einem Vektor digs (kurz für digits) zusammengefasst.
Zeile 12: Mit Hilfe der Funktion attr() wird das selbstdefinierte Attribut digits gesetzt.
Zeile 14 bis 19: Die Ausgabe aller Attribute von v zeigt jetzt eine Liste mit 2 Komponenten (die Namen der Attribute sind names und digits; names ist ein "character-Vektor", digits ein "numeric"-Vektor).
Zusammenfassung
Die folgenden Tabellen zeigen eine Kurzbeschreibung der in diesem Kapitel vorgestellten Funktionen. Man beachte dabei aber, dass die gezeigten Argumente meist nicht die komplette Liste der Eingabewerte darstellt. Es werden immer nur diejenigen Eingabewerte gezeigt, die hier auch besprochen wurden. Für die allgemeine Verwendung der Funktionen ist es erforderlich, die Dokumentation zu Rate zu ziehen.
Erzeugen von Vektoren
Funktion | Beschreibung |
vector(mode, length)
| Erzeugen eines Vektors mit gegebenem Modus mode und length als Anzahl der Komponenten; die Werte der Komponenten sind default-Werte (FALSE für "logical", 0 für "numeric", leerer String ""
für "character") |
c(...)
| Erzeugen eines Vektors durch Aneinanderhängen (concatenation) gegebener Werte |
seq(from, to, by, length.out)
| Erzeugen einer Zahlenfolge, wobei Anfangswert from, Endwert to, Zuwachs by und Länge length.out der Folge vorgegeben werden können; default-Wert für by = 1
(from, to, by müssen nicht ganzzahlig sein, man muss dann aber auf Rundungsfehler achten) |
(k:n)
| Kurzform für seq(from = k, to = n)
(default-Wert für by = 1
) |
seq_along(along.with)
| Erzeugt den Vektor (1:n)
, wobei n die Länge von along.with ist |
seq_len(length.out = 10)
| Erzeugt den Vektor (1:length.out)
, wobei length.out eine positive Zahl im Speichermodus "integer" ist |
rep(x, times, each, length.out)
| das Objekt x wird wiederholt; times: Anzahl der Wiederholungen; each: Anzahl der Wiederholungen pro Komponente von x; length.out: Anzahl der Komponenten des erzeugten Vektors |
runif(n, min = 0, max = 1)
| erzeugt eine Folge von n Zufallszahlen, die im Intervall min; max gleichverteilt sind; default-Werte sind min = 0 und max = 1 |
append(x, values, after = length(x)
| an den Vektor x wird der Vektor values angehängt; eingefügt wird er nach dem Index after (dessen default-Wert ist length(x)) |
Die folgende Tabelle beschreibt die Rückgabewerte der Funktionen und ihre Datentypen:
Funktion | Rückgabewert | Datentyp |
vector(mode, length)
| Vektor mit gegebenem Modus und gegebener Länge, der mit default-Werten gefüllt wird | Vektor |
c(...)
| Vektor, dessen Komponenten die Eingabewerte von c() sind; bei inkompatiblen Typen werden Konversionen zum höheren Speichermodus vorgenommen (logical < integer < double < character) | Vektor |
seq(from, to, by, length.out)
| Vektor, dessen Komponenten gleiche Abstände besitzen | Vektor |
(k:n)
| Vektor mit n - k + 1 Komponenten (k, k+1,..., n-1, n) | Vektor |
seq_along(along.with)
| Vektor (1:n)
, wobei n die Länge des Vektors along.with ist | Vektor |
seq_len(length.out = 10)
| Erzeugt den Vektor (1:length.out)
, wobei length.out eine positive Zahl im Speichermodus "integer" ist | Vektor |
rep(x, times, each, length.out)
| Vektor, der aus Wiederholungen von x aufgebaut wird | Vektor |
runif(n, min = 0, max = 1)
| Vektor der Länge n mit gleichverteilten Zufallszahlen zwischen min und max | Vektor |
append(x, values, after = length(x)
| Vektor x, der um den Vektor values ergänzt wird; eingefügt wird values nach dem Index after | Vektor der Länge length(x) + length(values)
|
Eigenschaften von Vektoren und Diagnose-Funktionen für Vektoren
Funktion | Beschreibung |
length(x)
| Bestimmen der Anzahl der Komponenten des Vektors x |
head(x, n)
| von dem Vektor x werden nur die ersten n Komponenten verwendet |
tail(x, n)
| von dem Vektor x werden nur die letzten n Komponenten verwendet |
print(x, digits)
| Ausgabe des Vektors x mit digits Nachkommastellen |
mode(x)
| Abfrage des Modus eines Vektors x |
mode(x) <- value
| replacement-Version von mode(): Setzen des Modus eines Vektors x |
storage.mode(x)
| Abfrage des Speichermodus eines Vektors x |
storage.mode(x) <- value
| replacement-Version von storage.mode(): Setzen des Speichermodus eines Vektors x |
str(object)
| Ausgabe der Struktur eines Vektors object (Modus, Vektor der Indizes, Werte) |
is.vector(x)
| Feststellen, ob x ein Vektor ist |
summary(object, digits)
| Ausgabe einer einfachen statistischen Auswertung des Vektors object; Zahlenwerte werden mit digits Nachkommastellen angegeben |
?head
| Weitere Informationen zu head() und tail() in der Dokumentation im package utils unter head. |
Die folgende Tabelle beschreibt die Rückgabewerte der Funktionen und ihre Datentypen:
Funktion | Rückgabewert | Datentyp |
length(x)
| Anzahl der Komponenten des Vektors x | "integer" |
head(x, n)
| Vektor der Länge n (vorderer Teil von x) | Vektor |
tail(x, n)
| Vektor der Länge n (hinterer Teil von x) | Vektor |
print(x, digits)
| Ausgabe und Rückgabe des Vektors x mit digits Nachkommastellen | Vektor |
mode(x)
| Modus des Vektors x | Zeichenkette |
mode(x) <- value
| kein Rückgabewert, dient zum Setzen des Modus des Vektors x | kein Rückgabewert (replacement form von mode()) |
storage.mode(x)
| Speichermodus des Vektors x | Zeichenkette |
storage.mode(x, digits) <- value
| kein Rückgabewert, dient zum Setzen des Speichermodus des Vektors x | kein Rückgabewert (replacement form von storage.mode()) |
str(object)
| Kein Rückgabewert, nur Ausgabe der Struktur eines Objektes. | "NULL": kein Rückgabewert |
is.vector(x)
| TRUE oder FALSE | "logical" |
summary(object, digits)
| Tabelle mit Namen (zur Bezeichnung der statistischen Größen) und deren Zahlenwerte | Tabelle (table), genauer: Klasse "summaryDefault" "table" |
Attribute von Vektoren
Funktion | Beschreibung |
names(x)
| Abfragen der Namen des Vektors x |
names(x) <- value
| replacement-Version von names() zum Setzen der Namen für die Komponenten des Vektors x; der character-Vektor value sollte die selbe Länge haben wie x (ist value zu kurz, wird mit NA aufgefüllt; ist value zu lang: Fehlermeldung). Ist value gleich NULL, wird das Attribut names gelöscht. |
attr(x, which)
| Abfragen des Attributes which (Zeichenkette) des Vektors x. |
attr(x, which) <- value
| replacement-Version von attr(): Setzen des Attributes which (Zeichenkette) des Vektors x. |
attributes(obj)
| Abfragen aller Attribute des Objektes obj. |
attributes(obj) <- value
| replacement-Version von attributes(): Setzen der Attribute für das Objekt obj mit value (intern werden dabei zuerst alle Attribute gelöscht und dann neu gesetzt). |
unname(obj)
| Erzeugt ein Objekt, bei dem das Attribut names aus dem Objekt obj beseitigt wurde (dies gilt bei Vektoren; bei Matrizen oder Feldern wird das Attribut dimnames gelöscht). Die Funktion ist keine replacement-Funktion, das heißt obj bleibt unverändert. |
Die folgende Tabelle beschreibt die Rückgabewerte der Funktionen und ihre Datentypen:
Funktion | Rückgabewert | Datentyp |
names(x)
| character-Vektor mit den Namen des Vektors x; dessen Länge stimmt mit der von x überein | Vektor (Modus "character") |
names(x) <- value
| replacement-Version von names(): das Objekt x wird verändert, indem seine Namen auf value gesetzt werden; ist value gleich NULL, wird das Attribut names gelöscht. | kein Rückgabewert (replacement form von names()) |
attr(x, which)
| Falls das mit which benannte Attribut von x existiert, wird dies angezeigt; andernfalls wird NULL zurückgegeben. | Datentyp des Attributes (falls es existiert) |
attr(x, which) <- value
| replacement-Version von attr(): Setzen des Attributes which (Zeichenkette) des Vektors x. | kein Rückgabewert (replacement form von attr()) |
attributes(obj)
| Abfragen aller Attribute des Objektes obj. | Liste (Datentyp list) der Attribute von obj |
attributes(obj) <- value
| replacement-Version von attributes(): Setzen der Attribute für das Objekt obj mit value (intern werden dabei zuerst alle Attribute gelöscht und dann neu gesetzt); dazu muss value eine geeignete Liste sein. | kein Rückgabewert (replacement form von attributes()) |
unname(obj)
| Stimmt mit dem Objekt obj überein, allerdings sind die Attribute names und dimnames gelöscht (Letzteres bei Matrizen oder Feldern). | Falls obj ein Vektor: Vektor, in dem das Attribut names nicht gesetzt ist. |