write.csv() esporta un data frame
Far uscire un data frame da R e metterlo in un file che altri programmi possono aprire richiede una sola chiamata:
write.csv(df, "results.csv", row.names = FALSE)
È la riga da imparare a memoria, compreso il row.names = FALSE, che giustificheremo tra un attimo. Il primo argomento è il data frame, il secondo è il nome del file, e la funzione non restituisce nulla: tutto il suo lavoro è l'effetto collaterale di creare il file.
Puoi vedere esattamente cosa produce write.csv() senza toccare il disco, perché accetta qualsiasi connessione dove si aspetta un nome di file, compreso stdout(), che semplicemente stampa:
Ecco il tuo CSV: una riga di intestazione, una riga per ogni riga dei dati, i valori di testo tra virgolette e i numeri senza. (Le virgolette sono il default quote = TRUE; ogni lettore di CSV diffuso le gestisce, quindi lasciale stare.) Scrivere su un file vero è la stessa chiamata con "results.csv" al posto di stdout().
Perché row.names = FALSE dovrebbe essere il tuo default
Ogni data frame ha dei nomi di riga, di solito solo i numeri 1, 2, 3..., e il default di write.csv() è scriverli nel file come prima colonna in più con un'intestazione vuota. Guarda com'è l'output di default, e cosa succede quando quel file fa il viaggio di ritorno in R:
L'export si è ritrovato con una prima colonna senza nome che contiene "1", "2", e alla reimportazione read.csv() doveva pur chiamarla in qualche modo, quindi si è inventato X. È la misteriosa colonna X che lascia perplesso ogni principiante: non sono dati, è la numerazione delle righe di R che finisce nel tuo file. Ripeti qualche volta il ciclo di esportazione e importazione e accumulerai X, X.1, X.2...
I nomi di riga non contengono quasi mai informazioni reali, e quando lo fanno, quell'informazione dovrebbe comunque stare in una colonna vera. Quindi fai di row.names = FALSE un riflesso. Probabilmente avrebbe dovuto essere il default; non lo è per motivi di compatibilità con il passato, quindi l'abitudine tocca a te.
Dove finisce il file
write.csv(df, "results.csv") scrive nella directory di lavoro di R, e se non è dove ti aspettavi, il file sembra sparire. Non è fallito niente: è semplicemente nella cartella che getwd() stampa. È lo stesso tranello della lettura, allo specchio, e lo risolvono gli stessi due strumenti:
getwd() # the folder your file went to
write.csv(df, "C:/Users/ada/results/out.csv", row.names = FALSE) # or: remove all doubt
I percorsi completi (le barre normali funzionano su ogni piattaforma, Windows compreso) rendono gli script privi di ambiguità. Come si imposta e si gestisce la directory di lavoro è spiegato in directory di lavoro.
write.table() per altri delimitatori, e la questione dell'aggiunta
write.csv() è in realtà un sottile involucro attorno alla funzione generica write.table(), già configurata per le virgole. Chiama direttamente write.table() quando ti serve una forma diversa, il più delle volte separata da tabulazioni:
Separato da tabulazioni, senza virgolette: il formato che preferiscono molti strumenti a valle. Nota che con write.table() imposti tutto in modo esplicito; non eredita i default di write.csv su virgole e virgolette.
Una cosa che write.csv() si rifiuta di fare è aggiungere in coda: passare append = TRUE ti procura un avviso che dice che l'impostazione è stata ignorata, perché aggiungere riscriverebbe la riga di intestazione in mezzo al file. Se ti serve davvero aggiungere righe a un CSV esistente, per esempio per registrare i risultati di più esecuzioni, scendi a write.table() e togli tu l'intestazione:
write.table(new_rows, "log.csv", sep = ",",
append = TRUE, col.names = FALSE, row.names = FALSE)
E se lavori con il tidyverse, readr::write_csv(df, "out.csv") è la controparte di read_csv(): stesso output, più veloce sui data frame grandi, e non scrive mai i nomi di riga, un argomento in meno da ricordare.
saveRDS() e readRDS(): salvare e ricaricare in modo esatto
Il CSV è un formato che perde informazioni. Salva testo, punto: una colonna Date diventa la stringa "2026-08-07", un factor diventa le sue etichette senza l'ordine dei livelli, gli attributi spariscono e ogni tipo va dedotto di nuovo all'importazione (di solito correttamente, a volte no: pensiamo agli zeri iniziali). E un CSV può contenere solo una tabella rettangolare: un modello stimato, una lista o una matrice con dimnames non hanno alcuna rappresentazione in CSV.
Quando il file è per R, per esempio per salvare i dati puliti di oggi per la sessione di domani, salta del tutto i formati di testo:
saveRDS(df, "clean_data.rds") # today
df <- readRDS("clean_data.rds") # tomorrow: identical object, types intact
saveRDS() serializza un oggetto R, qualsiasi oggetto, in modo esatto. readRDS() te lo restituisce byte per byte: i factor mantengono i loro livelli, le date sono ancora date, niente viene dedotto di nuovo. Funziona con qualsiasi cosa: un data frame, una lista di data frame, un modello di regressione stimato. Il file .rds è binario compresso, quindi di solito è anche più piccolo del CSV. L'unico costo è che solo R lo può aprire, ed è proprio per questo che la regola pratica è: CSV per condividere con persone e altri strumenti, RDS per salvare per te.
save() e load(), e perché di solito vince RDS
Incontrerai anche una coppia più vecchia. save() scrive più oggetti con nome in un unico file .RData, e load() li ripristina nel tuo workspace, con i loro nomi originali:
save(df, model, params, file = "session.RData")
load("session.RData") # df, model, params silently appear
Il problema è proprio questa comodità. È load() a decidere i nomi delle variabili, non tu: pianta oggetti nel tuo ambiente senza che tu li veda, sovrascrivendo in silenzio tutto ciò che aveva già quei nomi. Sei mesi dopo, nessuno si ricorda cosa contiene session.RData senza caricarlo per scoprirlo.
readRDS() ha un'interfaccia onesta: il nome lo scegli tu (df <- readRDS(...)), niente viene sovrascritto alle tue spalle e un file corrisponde a un oggetto. A meno che tu non abbia proprio bisogno di raggruppare diversi oggetti in un unico file, preferisci RDS. (Se ti serve davvero un pacchetto di oggetti, metterli in una lista con nomi e salvare la lista con saveRDS() ti dà lo stesso effetto senza sorprese.)
Cosa ti porti a casa
write.csv(df, "out.csv", row.names = FALSE): questo è tutto l'export, e sì, sempre conrow.names = FALSE.- La misteriosa colonna
Xalla reimportazione sono i nomi di riga finiti nel file; il default li ha scritti, tu non dovresti. - I file finiscono nella directory di lavoro:
getwd()ritrova gli export "persi", i percorsi completi li evitano. write.table()gestisce altri delimitatori e (concol.names = FALSE) la vera aggiunta in coda;write.csv()per scelta non può aggiungere.saveRDS()/readRDS()salvano e ricaricano qualsiasi oggetto R in modo esatto, con tipi, factor e attributi intatti. CSV per condividere, RDS per te.- Preferisci RDS a
save()/load(): nomi espliciti, nessuna sovrascrittura silenziosa.
Prossimo passo: un tipo di dati che merita una pagina tutta sua prima che ti morda durante un'importazione, cioè le date.
Domande frequenti
Come si esporta un data frame in CSV in R?
write.csv(df, "output.csv", row.names = FALSE). La parte row.names = FALSE è importante: senza, R scrive i suoi numeri di riga interni come prima colonna in più, che compare come una misteriosa colonna chiamata X quando qualcuno reimporta il file.
Perché il mio CSV esportato ha una colonna X quando lo rileggo?
Perché il default di write.csv è row.names = TRUE: ha scritto i numeri di riga come prima colonna senza nome, e read.csv, rileggendo il file, ha chiamato quella colonna X. Esporta con row.names = FALSE e la colonna fantasma sparisce.
Qual è la differenza tra write.csv e saveRDS in R?
write.csv produce una tabella di testo semplice che chiunque può aprire, ma salva solo testo: i livelli dei factor, i tipi Date, gli attributi e gli oggetti non tabellari vengono appiattiti o persi, e all'importazione i tipi vanno dedotti di nuovo. saveRDS salva un oggetto R byte per byte; readRDS lo restituisce esattamente com'era. Usa il CSV per condividere con altri, l'RDS per salvare per le tue sessioni di R.
Dove salva il file write.csv?
Nella directory di lavoro corrente di R, a meno che tu non indichi un percorso completo. Esegui getwd() per vedere dove si trova: se il tuo file sembra sparito, è nella cartella che getwd() stampa. Passare un percorso completo come "C:/Users/ada/results/out.csv" elimina ogni ambiguità.