Die Funktionen zum Formen von Datenrahmen werden durch die tidyverse-Bibliothek tidyr bereitgestellt.
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.2 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.2 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
16.1 Transponieren
Beim Transponieren von Datenrahmen werden die Spalten und Zeilen von Merkmalen neu ausgerichtet.
Das Transponieren von Datenrahmen ist keine vollständige Operation, sondern unterliegt je nach Ausgangsorientierung unterschiedlichen Anforderungen.
Die Funktion pivot_longer() überführt Vektoren von der Matrixform (Breitform) in die Vektorform (Langform). Alle der transponierten Vektoren müssen dafür vom gleichen Datentyp sein. Beim Transponieren in die Vektorform werden immer zwei Vektoren erzeugt:
Der Wertevektor, der die Werte der ursprünglichen Vektoren aufnimmt und
Der Namenvektor für die ursprünglichen Vektorennamen.
Falls keine anderen Angaben gemacht werden, heisst der Wertevektor value und der Namenvektor name.
Merke
Der Namenvektor ist gleichzeitig ein Sekundärindex.
Fall nicht alle Vektoren transponiert werden, dann werden die nicht transponierten Teile der Datensätze auf alle Datensätze der transponierten Vektoren erweitert.
Merke
Ein Primärindex wird nach dem Transponieren zum Sekundärindex.
Beispiel 16.1 (Transponieren in die Vektorform)
# Ursprünglich Daten(schweizerStaedte =read_csv("geschlechter_schweizer_staedte.csv") |>select(-c(S, N)))
Rows: 10 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Ort
dbl (7): Gesamt, S_M, S_F, N_M, N_F, S, N
ℹ 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.
Die Funktion pivot_wider() transponiert einen Datenrahmen von der Vektorform (Langform) in die Matrixform (Breitform). Damit diese Operation durchführbar ist, muss neben dem Wertevektor ein Sekundärindex für die Vektorennamen und ein Sekundärindex für die zeilenweise Zuordnung der Werte vorliegen. Dieser Index wird von R verwendet, um die Vektorennamen zu erzeugen: Die Operation erzeugt für jeden diskreten Wert im Sekundärindex einen Vektor für die Matrixform. Der zweite Sekundärindex wird nach dem Transponieren zum Primärindex.
Existieren weitere Vektoren im Datenrahmen, dann werden diese beim Transponieren zusammengefasst, so dass die Werte nach dem Transponieren nur noch einmal im Ergebnis erscheinen.
Achtung
Existiert kein zweiter Sekundärindex beim Transponieren in die Breitform, dann fasst R alle Datensätze zusammen, bei denen alle Werte in den zusätzlichen Vektoren gleich sind. Dieses Verhalten kann dazuführen, dass mehr Werte transponiert werden müssen als Zieldatensätze erzeugt werden können. In solchen Fällen werden die überzähligen Werte als Listenvektor abgelegt (Beispiel 16.3). Dieses Verhalten ist normalerweise unerwünscht.
Beispiel 16.3 (Transponieren mehrdeutiger Werte in die Matrixform)
ℹ Using "','" as decimal and "'.'" as grouping mark. Use `read_delim()` for more control.
Rows: 136 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ";"
chr (1): Angebot
dbl (3): Punkte, Interesse, Bedeutung
ℹ 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.
# A tibble: 136 × 4
Punkte Angebot Interesse Bedeutung
<dbl> <chr> <dbl> <dbl>
1 207. B 5 5
2 101. A 2 3
3 312. A 5 5
4 242. B 3 2
5 256. A 2 2
6 188. B 6 2
7 343. B 3 6
8 202. A 5 5
9 175. A 3 3
10 213. B 3 2
# ℹ 126 more rows
Warning: Values from `Punkte` are not uniquely identified; output will contain
list-cols.
• Use `values_fn = list` to suppress this warning.
• Use `values_fn = {summary_fun}` to summarise duplicates.
• Use the following dplyr code to identify duplicates.
{data} %>%
dplyr::group_by(Interesse, Bedeutung, Angebot) %>%
dplyr::summarise(n = dplyr::n(), .groups = "drop") %>%
dplyr::filter(n > 1L)
Es sollen mehrere Vektoren eines Datenrahmens auf die gleiche Art transformiert oder aggregiert werden.
16.1.1.2 Lösung
Die Vektoren werden zuerst in die Vektorform (Langform) transponiert. Anschliessend wird eine (gruppierte) Transformation oder gruppierte Aggregation durchgeführt.
Durch das transponieren entstehen ein Namenvektor und ein Wertevektor, wobei der Namenvektor auch als Sekundärindex behandelt werden kann. Sich wiederholende Operationen lassen sich so in einer gruppierten Operation zusammenfassen. Durch das Transponieren lässt sich die Code-Komplexität reduzieren, wodurch die Lösung insgesamt weniger fehleranfällig wird.
Diese Logik lässt sich auf alle Datenoperationen anwenden. Im Beispiel 16.6 werden die Anteile am Gesamtvolumen von vier Merkmalen berechnet. Ohne das Transponieren würden repetitive Codeteile entstehen (Beispiel 16.5). Die sich wiederholenden Codeteile entfallen durch das Transponieren und können in einer Operation behandelt werden.
Beispiel 16.5 (Bestimmung des Anteils mehrerer Merkmale ohne Transponieren)
Beim gruppierten Zählen werden die Sekundärindizes und die Ergebnisse nebeneinander dargestellt, so dass sich die Ergebnisse nur schwer vergleichen lassen.
16.1.2.2 Lösung
Nach dem gruppierten Zählen wird das Ergebnis in die Matrixform transponiert.
Beispiel 16.7 (Lesbarere Präsentation des gruppierten Zählen)
daten =read_csv2("data_ab_semi.csv")
ℹ Using "','" as decimal and "'.'" as grouping mark. Use `read_delim()` for more control.
Rows: 136 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ";"
chr (1): Angebot
dbl (3): Punkte, Interesse, Bedeutung
ℹ 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.
Werden beim Zählen über einen Datenrahmen mehrere Sekundärindizes verwendet, ist das Ergebnis nur schwer interpretierbar. Damit das Ergebnis für Menschen leichter zu lesen ist, muss die spaltenweise Darstellung in ein eleganteres Format überführt werden. Mit der Funktion pivot_wider() lassen sich die Daten in eine Kreuztabelle überführen. Das Ergebnis ähnelt nach dem Transponieren dem Ergebnis der table()-Funktion. Auf diese Weise lassen sich Häufungen in den Werten leichter erkennen.
In der Lösung werden drei besondere Parameter eingesetzt:
Der Parameter names_from zeigt an, aus welchem Index die neuen Vektornamen erzeugt werden sollen.
Der Parameter values_from zeigt an, in welchem Vektor die zu transponierenden Werte stehen.
der Parameter values_fill kommt zur Anwendung, wenn für eine Position kein Wert bereitsteht. Für die Zählung bedeutet das, dass nichts gezählt wurde. Deshalb wurde der Wert im Beispiel auf den Wert 0 gesetzt.
16.2 Hierarchisieren
Beim Hierarchisieren werden ausgewählte Vektoren eines Datenrahmens entlang eines Sekundärinzes zu separaten Datenrahmen organisiert und in den ursprünglichen Datenrahmen eingebettet. Über solche eingebettete Datenrahmen lassen sich hierarchische Datenstrukturen erzeugen, die beispielsweise in einem JSON- oder YAML-Dokument (s. Kapitel 7) gespeichert werden können. In R übernimmt diese Aufgabe die Funktion nest().
Weil R jedoch keine Vektoren mit Datenrahmen erlaubt, müssen diese Datenrahmen zusätzlich in eine Liste geschachtelt werden. Diese Liste dient nur zur Ablage in einem Vektor und besteht immer nur aus einem Element, nämlich dem eingebetteten Datenrahmen.
Mit der Funktion unnest() lassen sich eingebettete Datenrahmen wieder ausbetten. Diese Operation funktioniert jedoch nur dann zuverlässig, wenn alle eingebetteten Datenrahmen einheitliche Vektoren haben. Ist diese Bedingung nicht gegeben, dann erzeugt R zusätzliche Vektoren mit NA für alle Datensätze, die die Vektoren ursprünglich nicht enthielten. Die Funktion unnest() führt mehrere Spaltenkonkatenationen aus und ähnelt damit im Ergebnis der Funktion bind_rows().
Die beiden Funktionen nest() und unnest() sind speziell zur Erzeugung bzw. zum Auflösen von eingebetteten Datenrahmen gedacht. Gelegentlich enthält ein Datenrahmen einen Vektor mit einfachen Listen oder benannten Listen. Solche Vektoren sind vom Typ list und sollten mit den Funktionn unnest_longer() für einfache Listen sowie unnest_wider() für einheitlich benannte Listen (Wickham et al., 2023).
16.3 Transponieren mit Zeichenketten
Ein spezieller Fall ist gegeben, wenn die Daten in Zeichenketten kodiert sind. Streng genommen handelt es sich hierbei nicht um eine Transponierenoperation, sondern um eine normale Transformation. Die entsprechenden Funktionen für diese Operation wurden aber nach dem gleichen Prinzip wie beim Hierarchisieren bzw. beim Transponieren angepasst.
Wie beim Transponieren kann ein Vektor in die Lang- oder die Breitform getrennt werden. Für die meisten Anwendungen eignen sich zwei Funktionen:
separate_longer_delim()
separate_wider_delim()
Gelegentlich sind die Daten in einer Zeichenkette nicht über ein eindeutiges Trennzeichen, sondern über ein Trennmuster kodiert. In diesem Fall kann das Trennmuster als regulärer Ausdruck der Funktion separate_longer_regex() bzw. separate_wider_regex() übergeben werden.
Für festkodierte Werte stehen die beiden Funktionen separate_longer_position() und separate_wider_position() zur Verfügung. Diese Funktionen erwarten einen Vektor mit den Feldbreiten, um die Werte trennen zu können.
Die Umkehrfunktion für alle separate_-Funktionen ist die Funktion unite(), mit der sich die Werte aus einer Lang- oder Breitform zu einem Zeichenkettevektor verketten lassen.