Breit vs. lang: dieselben Daten, zwei Formen
Jede Umformungsfrage läuft auf eine Unterscheidung hinaus, also sehen wir sie uns an. Hier ist ein kleiner Datensatz - Quartalsumsätze für zwei Städte - in beiden Formen aufgebaut:
Identische Information, andere Geometrie. Breit hat eine Zeile pro Stadt und eine Spalte pro Quartal - das Quartal lebt in den Spaltennamen. Lang hat eine Zeile pro Beobachtung (Stadt × Quartal), mit dem Quartal zur gewöhnlichen Spalte degradiert und jedem Messwert in einer einzigen sales-Spalte.
Keine der Formen ist "richtig" - sie dienen verschiedenen Herren. Breit ist, was Menschen lesen und Tabellenkalkulationen exportieren: kompakt, auf einen Blick vergleichbar. Lang ist, was Werkzeuge konsumieren, und das Umwandeln zwischen beiden heißt Pivotieren (oder Umformen - dasselbe).
Warum das lange Format für Analysen gewinnt
Schau, was das breite Format mit dem Konzept "Quartal" gemacht hat: Es hat eine Variable in Spaltennamen zerschreddert. Mit einem Spaltennamen lässt sich nichts berechnen. Im langen Format ist quarter wieder Daten, und der ganze Werkzeugkasten gruppierter Analysen schaltet sich ein:
aggregate(sales ~ quarter, ...)odergroup_by(quarter)- unmöglich im breiten Format, wo jedes Quartal eine eigene Spalte ist, die du von Hand behandeln müsstest (gruppierte Zusammenfassungen setzen alle lange Daten voraus).- ggplot2 bildet Spalten auf Ästhetiken ab:
aes(x = quarter, y = sales, color = city)braucht diese drei Spalten. Breite Daten zu plotten ist ein Dauerkampf; lange Daten zu plotten ist eine Zeile. - Q3 hinzuzufügen heißt Zeilen hinzufügen - keine Schemaänderung -, während das breite Format eine neue Spalte bekommt, von der jeder nachgelagerte Schritt erfahren muss.
Die praktische Regel: lang speichern und analysieren, breit präsentieren. Deshalb werden die beiden Umwandlungen unten so viel genutzt - Daten kommen breit aus Tabellenkalkulationen, werden für die Analyse verlängert und für die finale Tabelle im Bericht wieder verbreitert.
Breit zu lang: pivot_longer()
Das Paket tidyr (dplyrs Geschwister im Tidyverse) besitzt das moderne Umformen. Seine Ausschnitte sind hier statisch - die Sandbox führt nur Base R aus. Das Verlängern braucht drei Entscheidungen, je ein Argument:
library(tidyr)
long <- pivot_longer(wide,
cols = c(Q1, Q2), # which columns to stack
names_to = "quarter", # new column that receives the old NAMES
values_to = "sales" # new column that receives the cell VALUES
)
Gehen wir es durch: cols benennt die Spalten, die aufgelöst werden (die Bereichssyntax Q1:Q2 und Helfer wie starts_with("Q") funktionieren ebenfalls - praktisch, wenn es zwanzig davon gibt). Jede gewählte Zelle wird zu einer Zeile; die Spalte, aus der sie kam, landet in quarter, die Zahl selbst in sales. Spalten, die nicht in cols aufgeführt sind (hier city), gelten als Identifikatoren und wiederholen sich über die Zeilen. Das Ergebnis ist exakt der oben ausgegebene long-Frame.
Lang zu breit: pivot_wider()
Die Rückreise braucht zwei Entscheidungen - woher die neuen Spaltennamen kommen und was sie füllt:
wide <- pivot_wider(long,
names_from = quarter, # distinct values here become new columns
values_from = sales # these values fill the cells
)
Jeder eindeutige Wert von quarter (Q1, Q2) wird zu einer Spalte; jede Zelle wird mit dem sales-Wert aus der Zeile gefüllt, die zu Stadt und Quartal passt. Die übrigen Spalten (city) fungieren als Zeilenidentifikatoren - eine Ausgabezeile pro eindeutiger Kombination. Fehlt einer Stadt ein Quartal, bekommt sie NA in dieser Zelle (das Argument values_fill setzt etwas anderes ein, z. B. values_fill = 0 bei Zähldaten).
In älteren Tutorials triffst du außerdem auf die Vorgängergeneration: spread() ist pivot_wider() und gather() ist pivot_longer() - seit tidyr 1.0 abgelöst, weiterhin funktionsfähig, über das Wiedererkennen hinaus nicht lernenswert.
Base R hat reshape() - eine ehrliche Warnung
Base R kann das ohne Pakete, über reshape() - eine Funktion, die so berüchtigt verwirrend ist, dass ihre eigene Dokumentation sich historisch dafür entschuldigt hat. Sie wurde rund um das Vokabular von Längsschnittstudien entworfen (idvar, timevar, direction), die Argumentnamen passen unbeholfen auf Alltagsdaten, und alle vergessen sie zwischen zwei Einsätzen. Sie funktioniert aber:
Beachte die Ausgabenamen: sales.Q1, sales.Q2 - der Name der Wertespalte ist an jede angeschmolzen. In der Not in Ordnung, in einer abhängigkeitsfreien Umgebung oder wenn du ihr in altem Code begegnest. Aber wenn du Daten öfter als einmal im Jahr umformst, ist install.packages("tidyr") die ehrliche Empfehlung - das ist die eine Datenaufbereitungsaufgabe, bei der Base R's Werkzeug wirklich mehr kostet als die eingesparte Abhängigkeit.
Die Doppelschlüssel-Falle beim Verbreitern
Verbreitern setzt voraus, dass jede Kombination aus Identifikator und Name einen Wert festlegt. Hat Lima zwei Q1-Zeilen, welche Zahl kommt in die eine Q1-Zelle? pivot_wider() weigert sich zu raten: Es meldet eine Warnung (values are not uniquely identified) und legt eine Listenspalte in die Zelle - einen Data Frame mit verschachtelten Listen darin, was das Nächste, was du damit tust, zerbricht.
Wenn du diese Warnung siehst, greif nicht zuerst zur Notluke values_fn - frag, warum Duplikate existieren. Meist liegen die Daten feiner vor, als du dachtest (Tageszeilen statt Quartalszeilen - also erst zusammenfassen, dann verbreitern), oder ein vorgelagerter Join hat Zeilen dupliziert. values_fn = mean (oder sum) ist erst dann die legitime Lösung, wenn du laut aussprechen kannst, unter welcher Aggregation die Duplikate zusammenfallen sollen. reshape() ist hier schlimmer: Es behält still das erste Duplikat und verwirft den Rest, mit nur einer Warnung, über die man leicht hinwegscrollt.
Was du mitnimmst
- Breit: Variablen, die sich in Spaltennamen verstecken, gemacht fürs Lesen. Lang: eine Zeile pro Beobachtung, gemacht für Analyse und ggplot2.
- Lang speichern und analysieren, breit präsentieren.
pivot_longer(cols, names_to, values_to)stapelt Spalten in Zeilen; nicht aufgeführte Spalten werden zu wiederholenden Identifikatoren.pivot_wider(names_from, values_from)verteilt Zeilen auf Spalten; Lücken füllen sich mitNA.spread()/gather()sind die alten Namen; Base-reshape()funktioniert, ist aber berüchtigt umständlich.- Doppelte Identifikator-Namen-Paare machen das Verbreitern mehrdeutig - erst zusammenfassen, nicht bloß die Warnung stummschalten.
Als Nächstes: echte Daten aus Dateien einlesen - read.csv() und seine scharfen Kanten.
Häufig gestellte Fragen
Was ist der Unterschied zwischen breiten und langen Daten in R?
Dieselben Daten, verschiedene Formen. Das breite Format verteilt eine Variable über Spalten (etwa eine Spalte pro Quartal) - eine Zeile pro Subjekt, gemacht fürs Lesen durch Menschen. Das lange Format stapelt sie in Zeilen - eine Zeile pro Beobachtung, mit einer Namensspalte und einer Wertespalte - gemacht für gruppierte Analysen und ggplot2.
Wie wandle ich in R breite Daten in lange um?
pivot_longer(df, cols = Q1:Q4, names_to = "quarter", values_to = "sales") aus tidyr stapelt die gewählten Spalten in zwei neue: Die alten Spaltennamen wandern in die names_to-Spalte, die Zellwerte in die values_to-Spalte.
Wie wandle ich in R lange Daten in breite um?
pivot_wider(df, names_from = quarter, values_from = sales) aus tidyr verteilt Zeilen auf Spalten: Jeder eindeutige Wert von names_from wird zu einer Spalte, gefüllt mit den passenden values_from-Einträgen. Fehlende Kombinationen werden NA.
Was hat spread und gather in R ersetzt?
pivot_wider() hat spread() und pivot_longer() hat gather() in tidyr 1.0 (2019) ersetzt. Die alten Funktionen laufen weiterhin - du siehst sie in älteren Tutorials -, aber jeder neue Code sollte das pivot_*-Paar nutzen, das klarere Argumente und mehr Funktionen bietet.