= c(TRUE, FALSE, FALSE, TRUE, TRUE)
logischer_vektor
! logischer_vektor
[1] FALSE TRUE TRUE FALSE FALSE
In R stehen die logischen Operationen als binäre Operatoren zur Verfügung, bzw. als Funktionen mit genau zwei Parametern. Diese logischen Operatoren sind vektorisiert. Es ist deshalb unnötig, logische Ausdrücke durch die Boole’sche Arithmetik zu ersetzen. Lediglich die Reihenfolge der Ausführung dieser Operatoren folgt der gleichen Regel wie die Arithmetik.
Daraus folgt, dass immer zuerst das logische Und und erst danach das logische Oder ausgewertet wird. Dieser Regel folgt auch R.
Die Tabelle 11.1 stellt die logischen Operationen und die verschiedenen Schreibweisen gegenüber.
Operation | neutrales Element | Mathematisch | R | arithmetische Operation |
---|---|---|---|---|
Nicht | - | \lnot | ! |
1 - a |
Und | WAHR | \land | & |
a \cdot b |
Oder | FALSCH | \lor | | |
a + b |
Exklusiv-Oder/Antivalenz | - | \oplus | xor() |
(a - b)^2 |
Es gibt neben den beiden Operatoren &
und |
auch die gedoppelte Varianten &&
und ||
. Diese Varianten arbeiten auf den Binärwerten von Ganzzahlen und werden normalerweise nicht im Zusammenhang mit logischen Ausdrücken verwendet.
Das Logisches Nicht wird in R durch den Nicht-Operator (!
) ausgedrückt. Dieser Operator wird auf jeden Wert eines Vektors einzeln angewandt.
Beispiel 11.1 (Logisches Nicht)
= c(TRUE, FALSE, FALSE, TRUE, TRUE)
logischer_vektor
! logischer_vektor
[1] FALSE TRUE TRUE FALSE FALSE
R wandelt numerische Werte automatisch in Wahrheitswerte um, wenn sie mit logischen Operationen verwendet werden. Dabei gilt:
FALSE
entspricht 0
TRUE
entspricht ungleich 0
Beispiel 11.2
! c(1, 2, 0, 4, 0)
[1] FALSE FALSE TRUE FALSE TRUE
Wenn Sie in R zwei Vektoren mit dem Und- (&
), dem Oder-Operator (|
) oder der Antivalenz (xor()
) verknüpfen, dann werden die Werte immer paarweise miteinander verglichen. Ein einzelner Vektor kann nicht an die Funktion des jeweiligen Operators übergeben werden.
Beispiel paarweise Verknüpfung
= c(TRUE, FALSE, FALSE, TRUE, TRUE)
vektor_a = c(TRUE, TRUE, FALSE, FALSE, TRUE)
vektor_b
& vektor_b vektor_a
[1] TRUE FALSE FALSE FALSE TRUE
reduce()
Um logische Vektoren in R zu aggregieren, muss der Vektor reduziert (engl. reduce) werden. Das Reduzieren ist eine besondere Aggregation über eine Reihe von Werten, bei der jeder Wert gemeinsam mit dem Ergebnis der Vorgängerwerte an eine Funktion übergeben wird.
Beispiel 11.3 (Aggregation logischer Vektoren)
= c(TRUE, TRUE, FALSE, TRUE)
beispielWerte
|> reduce(`&`) beispielWerte
[1] FALSE
|> reduce(`|`) beispielWerte
[1] TRUE
|> reduce(`xor`) beispielWerte
[1] TRUE
Beim Reduzieren muss beachtet werden, dass eine Funktion und nicht den Operator übergeben wird. Deshalb muss der jeweilige logische Operator in Backticks (`
) gesetzt und so als Funktionsbezeichner markiert werden.
Neben den logischen Operationen sind Vergleiche ein wichtiges Konzept, das wir in logischen Ausdrücken regelmässig anwenden.
Es gibt genau sechs (6) Vergleichsoperatoren:
==
)!=
)>
)>=
)<
)<=
)Vergleiche erfordern, dass beide Werte vom gleichen Datentyp sind.
Die Vergleiche funktionieren für alle fundamentalen Datentypen.
Bei Zeichenketten wertet R die alphabetische Reihenfolge der Symbole vom Beginn einer Zeichenkette aus, um grösser oder kleiner Vergleiche durchzuführen.
Häufig müssen Sie überprüfen, ob ein Wert in einer Liste vorkommt. Grundsätzlich können Sie das mit komplizierten logischen Verknüpfungen in der Art von Beispiel 11.4 schreiben.
Beispiel 11.4 (Existstenzprüfung ohne %in%
)
= 3
meinWert = c(8, 2, 3)
wertVektor
== wertVektor[1] | meinWert == wertVektor[2] | meinWert == wertVektor[3] meinWert
[1] TRUE
Einfacher ist aber ein sogenannter Existenztest. Dabei wird überprüft, ob ein Wert in einem Vektor vorkommt. Ein solcher Test lässt sich wie in Beispiel 11.5 schreiben:
Beispiel 11.5 (Existstenzprüfung mit %in%
)
= 3
meinWert = c(8, 2, 3)
wertVektor
%in% wertVektor meinWert
[1] TRUE
Entsprechend der Definition des Existenzvergleichs \in funktioniert R’s %in%
-Operator auch für Vektoren als linker Operand.
R kennt die beiden Schlüsselworte if
und else
, um die Ausführung Operationsblöcken an Bedingungen zu knüpfen. Das Schlüsselwort if
erwartet einen logischen Ausdruck, der genau einen Wahrheitswert zurückgibt. Logische Ausdrücke mit Vektoren sind damit nicht möglich.
Soll sowohl die Bedingung als auch die Alternative behandelt werden, dann muss das Schlüsselwort else
in der gleichen Zeile stehen, wie das Ende des Blocks für die Bedingung.
Beispiel 11.6 (Ungültige Vektorbedingung mit if
)
= c(-1, 2, 0, 1)
werte
if (werte > 1) {
= werte - 1
werte else {
} = 0
werte }
Error in if (werte > 1) {: Bedingung hat Länge > 1
Bedingte Operationen sind in R nur selten notwendig. Die einzige relevandte Anwendung ist Datentypkontrolle für Parameter bevor die eigentliche Operation durchgeführt wird.
Beispiel 11.7 (Datentypprüfung mit if
)
if (!is.list(werte)) {
stop("Variable enthält keine Liste")
}
Error in eval(expr, envir, enclos): Variable enthält keine Liste
Häufiger als Bedingungen kommen in R vektorisierte Unterscheidungen vor. Dafür stehen zwei Funktionen zur Verfügung:
ifelse()
case_when()
Die Funktion ifelse()
hat drei Parameter und immer einen Vektor als Ergebnis. Die Parameter sind:
TRUE
) ergibt.FALSE
) ergibt.Die Ergebnisse der beiden Operationen stehen im Ergebnisvektor an den Positionen, an denen der logische Ausdruck Wahr oder Falsch ergab.
Beispiel 11.8 (Vektorisierte Unterscheidung mit ifelse()
)
ifelse(werte > 1, werte * 2, 0)
[1] 0 4 0 0
Die Funktion case_when()
erlaubt es, mehrere miteinander verbundene vektorisierte Unterscheidungen in einer Operation durchzuführen. Dazu werden logische Ausdrücke mit Ergebnisoperationen bzw. -Werten verknüpft. Eine Ergebnisoperation wird dann ausgeführt, wenn der zugehörige logische Ausdruck Wahr (TRUE
) ergibt. Die logischen Ausdrücke werden in der angegebenen Reihenfolge geprüft, wobei die Operation abbricht, sobald ein logischer Ausdruck Wahr ergibt.
Beispiel 11.9 (case_when()
über einen Vektor)
case_when(
> 0 ~ "positiv",
werte == 0 ~ "null",
werte < 0 ~ "negativ"
werte )
[1] "negativ" "positiv" "null" "positiv"
Für den Fall, dass für einen Wert kein logischer Ausdruck Wahr ergibt, kann ein Rückfallergebnis angegeben werden. Dieses Rückfallergebnis muss mit .default =
eingeleitet werden.
Beispiel 11.10 (case_when()
mit Rückfallergebnis)
case_when(
> 0 ~ "positiv",
werte < 0 ~ "negativ",
werte .default = "null"
)
[1] "negativ" "positiv" "null" "positiv"
Das Filtern von Werten in Vektoren und Stichproben ist ein zentrales Element von R. Dafür stehen viele Funktionen bereit. Es ist auch möglich über die Index-Operatoren zu filtern.
In der Praxis wird meistens die Funktion filter()
zum Auswählen von Datensätzen verwendet. Diese Funktion ermöglicht es, einen Datenrahmen mittels eines logischen Ausdrucks einzuschränken. Die Funktion filter()
hat zwei Parameter:
Das Ergebnis ist ein Datenrahmen, der nur Datensätze enthält, für die der logische Ausdruck Wahr (TRUE
) ergibt.
Beispiel 11.11 (Filtern)
A B C 1 Name Sprache Einwohner:innen 2 Basel deutsch 173863 3 Genf französisch 203856 4 Lugano italienisch 62315 5 Zug deutsch 30934 6 Zürich deutsch 421878 Für diese Stichprobe möchten wir wissen, wie viele Einwohner in Städten mit mehr als 100000 Einwohnenden leben?
Diese Frage beantworten wir mit der folgenden Logik:
- Alle Städte mit mehr als 100000 Einwohner:innen filtern.
- Die Einwohner:innen der gefilterten Städte zusammenzählen.
Der logische Ausdruck zum Filtern ist
`Einwohner:innen` > 100000
, weil dieser Ausdruck nur für die Datensätze Wahr wird, wenn im VektorEinwohner:innen
der Wert grösser als100000
ist. Nach dem Filtern im ersten Schritt liegt nur noch die folgende Stichprobe vor:
A B C 1 Name Sprache Einwohner:innen 2 Basel deutsch 173863 3 Genf französisch 203856 6 Zürich deutsch 421878 Für diese Teilstichprobe muss im zweiten Schritt nur noch die Summe über den Vektor
Einwohner:innen
gebildet werden.Daraus ergibt sich die folgende Funktionskette:
1read_delim("daten/einwohnende.psv", delim = "|", trim_ws = T, show_col_types = F) |> 2filter(`Einwohner:innen` > 100000) |> summarise( Gesamteinwohnende = sum(`Einwohner:innen`) )
- 1
read_delim()
muss verwendet werden, weil ein besonderes Trennzeichen benutzt wird.- 2
- Filter operation.
# A tibble: 1 × 1 Gesamteinwohnende <dbl> 1 799597
NA
-Werte filternDie Funktion drop_na()
ist eine spezielle Filterfunktion, deren Ergebnis nur Datensätze enthält, in denen bei keinem Vektor den Wert NA
vorkommt. Die Funktion hat keinen Effekt, wenn ein Datenrahmen nur gültige Werte enthält (Beispiel 11.12).
Beispiel 11.12 (drop_na()
ohne Effekt)
Die tidyverse
Bibliothek umfasst die tidyselect
-Funktionen. Dabei handelt es sich um eine Reihe von Hilfsfunktionen, die die Vektorenauswahl nachvollziehbarer macht. Auf der tidyselect
-Homepage finden sich ausführliche Code-Beispiele.
In R können Vektoren mit der Funktion select()
selektiert werden. Dieser Funktion werden Regeln übergeben, nach denen die Vektoren auswählt werden sollen. Die einfachste Regel ist die direkte Eingabe der Vektorennamen. Ein typischer Anwendungsfall ist die Datenbereinigung, damit die Funktion drop_na()
nicht zu viele Datensätze löscht. Diese Situation kommt vor, wenn ein Datenrahmen viele fehlende Werte enthält, die ungleichmässig in den Vektoren vorkommen. Die Analyse muss deshalb auf die gewünschten Vektoren beschränkt werden.
Für die folgenden Beispiele verwenden wir die Daten der Befragung zum digitalen Umfeld, die mit der read_csv()
-Funktion eingelesen wird.
= read_csv("daten/befragung_digitales_umfeld/deviceuse.csv") stichprobe
Rows: 76 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (4): q00_demo_gen, q00_demo_studyload, q01_mob_typ, q12_fav_apps
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Wir wollen die Vektoren q00_demo_gen
(Gender), q00_demo_studyload
(Studienmodell) und q01_mob_typ
(Mobile OS des Smartphones) auswählen.
Beispiel 11.13 (Direktes selektieren)
|>
stichprobe select(q00_demo_gen, q00_demo_studyload, q01_mob_typ) |>
head()
# A tibble: 6 × 3
q00_demo_gen q00_demo_studyload q01_mob_typ
<chr> <chr> <chr>
1 Weiblich Vollzeit iPhone
2 Weiblich Vollzeit iPhone
3 Weiblich Teilzeit iPhone
4 Weiblich Teilzeit iPhone
5 Männlich <NA> Android Smartphone
6 Weiblich Vollzeit iPhone
Durch diesen Aufruf von select()
wird der Datenrahmen auf die drei ausgewählten Vektoren reduziert.
Vektoren direkt zu benennen ist eine einfache direkte Methode. Wenn man sehr viele Vektoren auswählen möchte, dann ist es manchmal einfacher, nur die Vektoren anzugeben, die nicht in der Ergebnisstichprobe enthalten sein sollen. Mit select()
erreichen wir das, indem wir ein -
den ungewollten Vektoren voranstellen.
Das folgende Beispiel selektiert alle Vektoren ausser q00_demo_gen
aus der Stichprobe.
Beispiel 11.14 (Selektieren durch Ausschliessen)
|>
stichprobe select(-q00_demo_gen) |>
head()
Wenn mehrere Vektoren ausgeschlossen werden sollen, dann müssen diese zu einem Vektor zusammengefasst werden.
Beispiel 11.15 (Selektieren durch mehrfaches Ausschliessen)
|>
stichprobe select(- c(q00_demo_gen, q00_demo_studyload)) |>
head()
Diese Vektorenauswahl wählt alle Vektoren ausser das Geschlecht und das Studienmodell.
Drei leistungsfähige Hilfsfunktionen für select()
sind:
starts_with()
,ends_with()
sowiecontains()
Diesen Funktionen akzeptieren einen Teilnamen, über den mehrere Vektoren ausgewählt werden, in denen der angegebene Teil im Vektornamen vorkommt.
Diese Funktionen lassen sich mittels der iris
-Stichprobe veranschaulichen.
Beispiel 11.16 (Selektieren mit starts_with()
)
|>
iris select(starts_with("Sepal")) |> # wählt die Vektoren Sepal.Width und Sepal.Length aus
head()
Sepal.Length Sepal.Width
1 5.1 3.5
2 4.9 3.0
3 4.7 3.2
4 4.6 3.1
5 5.0 3.6
6 5.4 3.9
Beispiel 11.17 (Selektieren mit ends_with()
)
|>
iris select(ends_with("Length")) |> # wählt die Vektoren Petal.Length und Sepal.Length aus
head()
Sepal.Length Petal.Length
1 5.1 1.4
2 4.9 1.4
3 4.7 1.3
4 4.6 1.5
5 5.0 1.4
6 5.4 1.7
Eine weitere Möglichkeit schneller viele Vektoren auszuwählen ist der :
-Operator. Damit können wir alle Vektoren zwischen zwei Vektoren inklusive der benannten Vektoren auswählen.
Der folgende Aufruf veranschaulicht dies:
Beispiel 11.18 (Vektorenbereich selektieren)
|>
stichprobe select(q00_demo_gen:q01_mob_typ) |>
head()
# A tibble: 6 × 3
q00_demo_gen q00_demo_studyload q01_mob_typ
<chr> <chr> <chr>
1 Weiblich Vollzeit iPhone
2 Weiblich Vollzeit iPhone
3 Weiblich Teilzeit iPhone
4 Weiblich Teilzeit iPhone
5 Männlich <NA> Android Smartphone
6 Weiblich Vollzeit iPhone
Diese Vektorenauswahl wählt die Vektoren q00_demo_gen
, q00_demo_studyload
und q01_mob_typ
für das Ergebnis aus.
Die Reihenfolge von Vektoren kann durch andere Transformationen geändert werden. Deshalb sollte das Selektieren mit Vektorbereichen vermieden werden.
R erlaubt kein Sortieren über logische Ausdrücke. Es ist nur möglich, Werte nach vorgegebenen grösser-kleiner Beziehungen zu sortieren. Deshalb muss für komplexe Sortierungen ein numerischer Hilfsvektor erzeugt werden, der anschliessend sortiert werden kann.
Die Werte eines Vektors werden mit sort()
sortiert.
Beispiel 11.19 (Vektorsortierung für zufällige Ganzzahlen)
set.seed(10)
runif(10, min = 1, max = 10) |> trunc() |> sort()
[1] 1 3 3 3 3 4 4 5 6 7
Die sort()
-Funktion kann nur einzelne Vektoren sortieren. Das ist unpraktisch, wenn Daten in einem Datenrahmen vorliegen. In diesem Fall lassen sich die Datensätze mithilfe der Funktion arrange()
sortieren. Der Funktion werden die Vektoren übergeben, über die eine neue Reihenfolge festgelegt werden soll. Standardmässig sortiert arrange()
aufsteigend. Mit der Hilfsfunktion desc()
(engl. descending = absteigen) werden Datensätze entsprechend der Werte im Sortiervektor absteigend sortiert.
Beispiel 11.20 (Absteigende Datenrahmensortierung mit arrange()
)
|>
mtcars as_tibble(rownames = "model") |>
select(model, hp, disp, mpg, am) |>
arrange(desc(hp)) |>
head()
# A tibble: 6 × 5
model hp disp mpg am
<chr> <dbl> <dbl> <dbl> <dbl>
1 Maserati Bora 335 301 15 1
2 Ford Pantera L 264 351 15.8 1
3 Duster 360 245 360 14.3 0
4 Camaro Z28 245 350 13.3 0
5 Chrysler Imperial 230 440 14.7 0
6 Lincoln Continental 215 460 10.4 0