write.csv() exportiert einen Data Frame
Einen Data Frame aus R heraus in eine Datei zu bekommen, die andere Programme öffnen können, ist ein Aufruf:
write.csv(df, "results.csv", row.names = FALSE)
Das ist die Zeile zum Auswendiglernen - einschließlich row.names = FALSE, das wir gleich begründen. Das erste Argument ist der Data Frame, das zweite der Dateiname, und die Funktion gibt nichts zurück: Ihre gesamte Aufgabe ist der Seiteneffekt, die Datei zu erzeugen.
Du kannst genau sehen, was write.csv() erzeugt, ohne die Festplatte zu berühren, denn es akzeptiert jede Verbindung dort, wo es einen Dateinamen erwartet - auch stdout(), das schlicht ausgibt:
Da ist deine CSV: eine Kopfzeile, eine Zeile je Datensatz, Textwerte in Anführungszeichen, Zahlen nackt. (Das Quoting ist die Voreinstellung quote = TRUE; jeder verbreitete CSV-Leser kommt damit klar, lass es also in Ruhe.) In eine echte Datei zu schreiben ist derselbe Aufruf mit "results.csv" anstelle von stdout().
Warum row.names = FALSE dein Standard sein sollte
Jeder Data Frame trägt Zeilennamen - meist bloß die Zahlen 1, 2, 3 ... - und die Voreinstellung von write.csv() ist, sie als zusätzliche erste Spalte mit leerem Kopf in die Datei zu schreiben. Sieh dir an, wie die Standardausgabe aussieht und was passiert, wenn diese Datei die Rundreise zurück nach R antritt:
Der Export hat eine namenlose erste Spalte mit "1", "2" bekommen - und beim Wiedereinlesen musste read.csv() sie irgendwie nennen, also erfand es X. Das ist die rätselhafte X-Spalte, über die jeder Anfänger stolpert: Sie sind keine Daten, sondern R's Zeilennummerierung, die in deine Datei sickert. Mach das ein paar Mal durch einen Export-Import-Zyklus, und du sammelst X, X.1, X.2 ...
Zeilennamen tragen fast nie echte Information - und wenn doch, gehört die Information ohnehin in eine richtige Spalte. Mach row.names = FALSE also zum Reflex. Es hätte wohl die Voreinstellung sein sollen; ist es aus Gründen der Abwärtskompatibilität nicht, also liegt die Gewohnheit bei dir.
Wo die Datei landet
write.csv(df, "results.csv") schreibt in R's Arbeitsverzeichnis - und wenn das nicht dort ist, wo du es erwartet hast, scheint die Datei zu verschwinden. Sie ist nicht gescheitert; sie liegt schlicht in dem Ordner, den getwd() ausgibt. Das ist dieselbe Falle wie beim Lesen, nur spiegelverkehrt, und dieselben zwei Werkzeuge lösen sie:
getwd() # the folder your file went to
write.csv(df, "C:/Users/ada/results/out.csv", row.names = FALSE) # or: remove all doubt
Vollständige Pfade (Schrägstriche funktionieren auf jeder Plattform, auch unter Windows) machen Skripte eindeutig. Wie das Arbeitsverzeichnis gesetzt und verwaltet wird, behandelt Arbeitsverzeichnis.
write.table() für andere Trennzeichen - und die Anhängefrage
write.csv() ist tatsächlich eine dünne Hülle um das allgemeine write.table(), vorkonfiguriert für Kommas. Ruf write.table() direkt auf, wenn du eine andere Form brauchst - am häufigsten tabulatorgetrennt:
Tabulatorgetrennt, ohne Anführungszeichen - das Format, das viele nachgelagerte Werkzeuge bevorzugen. Beachte, dass du bei write.table() alles explizit setzt; es erbt weder das Komma noch die Quoting-Voreinstellungen von write.csv.
Eine Sache, die write.csv() verweigert, ist das Anhängen: append = TRUE zu übergeben liefert dir eine Warnung, dass die Einstellung ignoriert wurde, denn Anhängen würde die Kopfzeile mitten in die Datei schreiben. Musst du wirklich Zeilen an eine bestehende CSV anhängen - etwa um Ergebnisse über mehrere Läufe zu protokollieren -, steig auf write.table() um und unterdrücke die Kopfzeile selbst:
write.table(new_rows, "log.csv", sep = ",",
append = TRUE, col.names = FALSE, row.names = FALSE)
Und wenn du im Tidyverse unterwegs bist, ist readr::write_csv(df, "out.csv") das Gegenstück zu read_csv(): gleiche Ausgabe, schneller bei großen Frames, und es schreibt von vornherein nie Zeilennamen - ein Argument weniger zu merken.
saveRDS() und readRDS(): exakte Rundreisen
CSV ist ein verlustbehaftetes Format. Es speichert Text, Punkt - eine Date-Spalte wird zur Zeichenkette "2026-08-07", ein Faktor wird zu seinen Etiketten mit verlorener Levelreihenfolge, Attribute verschwinden, und jeder Typ muss beim Import neu geraten werden (meist richtig, manchmal nicht - führende Nullen, wir schauen dich an). Und CSV kann nur eine rechteckige Tabelle halten: ein angepasstes Modell, eine Liste, eine Matrix mit dimnames haben überhaupt keine CSV-Darstellung.
Wenn die Datei für R ist - die heute bereinigten Daten für die morgige Sitzung speichern -, überspring Textformate ganz:
saveRDS(df, "clean_data.rds") # today
df <- readRDS("clean_data.rds") # tomorrow: identical object, types intact
saveRDS() serialisiert ein R-Objekt, jedes Objekt, exakt. readRDS() gibt es Byte für Byte zurück: Faktoren behalten ihre Levels, Datumswerte sind noch Datumswerte, nichts wird neu geraten. Es funktioniert mit allem - einem Data Frame, einer Liste von Data Frames, einem angepassten Regressionsmodell. Die .rds-Datei ist komprimiertes Binärformat, also typischerweise auch kleiner als die CSV. Der einzige Preis ist, dass nichts außer R sie öffnen kann - genau deshalb lautet die Faustregel: CSV zum Teilen mit Menschen und anderen Werkzeugen, RDS zum Speichern für dich selbst.
save() und load() - und warum RDS meist gewinnt
Du wirst auch auf ein älteres Paar treffen. save() schreibt mehrere benannte Objekte in eine .RData-Datei, und load() stellt sie wieder her - in deinem Workspace, unter ihren ursprünglichen Namen:
save(df, model, params, file = "session.RData")
load("session.RData") # df, model, params silently appear
Diese Bequemlichkeit ist das Problem. load() entscheidet über die Variablennamen, nicht du - es pflanzt ungesehen Objekte in deine Umgebung und überschreibt still alles, was schon so hieß. Sechs Monate später erinnert sich niemand, was session.RData überhaupt enthält, ohne es zu laden und nachzusehen.
readRDS() hat die ehrliche Schnittstelle: Du wählst den Namen (df <- readRDS(...)), nichts wird hinter deinem Rücken überschrieben, und eine Datei bedeutet ein Objekt. Sofern du nicht ausdrücklich mehrere Objekte in einer Datei bündeln musst, bevorzuge RDS. (Brauchst du doch ein Bündel, bringt dir das Ablegen der Objekte in einer benannten Liste plus saveRDS() denselben Effekt ohne jede Überraschung.)
Was du mitnimmst
write.csv(df, "out.csv", row.names = FALSE)- der ganze Export, und ja, immer dasrow.names = FALSE.- Die rätselhafte
X-Spalte beim Wiedereinlesen sind Zeilennamen, die in die Datei sickern; die Voreinstellung hat sie geschrieben, du solltest es nicht. - Dateien landen im Arbeitsverzeichnis -
getwd()findet "verlorene" Exporte, vollständige Pfade verhindern sie. write.table()beherrscht andere Trennzeichen und (mitcol.names = FALSE) echtes Anhängen;write.csv()kann bewusst nicht anhängen.saveRDS()/readRDS()bringen jedes R-Objekt exakt hin und zurück - Typen, Faktoren, Attribute intakt. CSV zum Teilen, RDS für dich selbst.- Bevorzuge RDS gegenüber
save()/load(): explizite Namen, keine stillen Überschreibungen.
Als Nächstes: ein Datentyp, der eine eigene Seite verdient, bevor er dich bei einem Import erwischt - Datumswerte.
Häufig gestellte Fragen
Wie exportiert man in R einen Data Frame als CSV?
write.csv(df, "output.csv", row.names = FALSE). Der Teil row.names = FALSE ist wichtig: Ohne ihn schreibt R seine internen Zeilennummern als zusätzliche erste Spalte, die beim erneuten Import als rätselhafte Spalte namens X auftaucht.
Warum hat meine exportierte CSV beim Wiedereinlesen eine X-Spalte?
Weil die Voreinstellung von write.csv row.names = TRUE lautet - es hat die Zeilennummern als unbenannte erste Spalte geschrieben, und read.csv hat diese Spalte auf dem Rückweg X genannt. Exportiere mit row.names = FALSE, und die Phantomspalte verschwindet.
Was ist der Unterschied zwischen write.csv und saveRDS in R?
write.csv erzeugt eine Klartexttabelle, die jeder öffnen kann, speichert aber nur Text - Faktorlevels, Date-Typen, Attribute und nicht-tabellarische Objekte werden geplättet oder gehen verloren, und Typen müssen beim Import neu geraten werden. saveRDS speichert ein R-Objekt Byte für Byte; readRDS gibt es exakt so zurück, wie es war. Nutze CSV zum Teilen mit anderen, RDS zum Speichern für deine eigenen R-Sitzungen.
Wo speichert write.csv die Datei?
Im aktuellen Arbeitsverzeichnis von R, sofern du keinen vollständigen Pfad angibst. Führ getwd() aus, um zu sehen, wo das ist - wenn deine Datei verschwunden scheint, liegt sie in dem Ordner, den getwd() ausgibt. Ein vollständiger Pfad wie "C:/Users/ada/results/out.csv" beseitigt die Mehrdeutigkeit.