Чтение и запись текстовых файлов
В работе аналитики и исследователи чаще всего сталкиваются с данными, которые хранятся в простом текстовом формате (txt, разделители строк \n, \r или \n\r ) и основанных на них табличных форматах csv (с разделителями , или ;) или tsv (\t).
Чтение текстовых файлов: read.table()
Для чтения текстовых файлов, которые содержат в табличном формате, в базовом R есть функция read.table() и функции-обертки, которые обращаются к ней, но с другими значениями аргументов по умолчанию (read.csv(), read.csv2, read.delim(), read.delim2()). Табличный формат предполагает наличие строк и колонок в файле, выделенных разделителями строк и полей соответственно, при этом формат файла может быть как txt, так и csv.
Несмотря на всю видимую простоту, при импорте табличных форматов можно столкнуться с очень большим количеством нетривиальных проблем. В немалой части это можно назвать следствием их широкой распространенности: практически все современные текстовые процессоры умеют работать с csv-файлами, экспорт из баз данных также нередко делается в csv. Ко всему прочему, текстовые форматы хорошо сжимаются при архивации.
К наиболее частым сложностям, которые возникают при импорте текстовых файлов, можно отнести следующие:
- неожиданные разделители (например, экспорт из MS Excel в
csvсоздаёт файл с разделителем;); - лишние или пропущенные разделители строк или колонок (
\t\tвместо\t), что создаёт разное количество колонок в таблице; - несоответствие файла расширению или вообще отсутствие расширения;
- нестандартные кодировки, в том числе проблемы их импорта при работе в Windows;
- наличие embedded nuls (
\0) или метки порядка байтов (bite order marks, BOM); - наличие символов
"""",////и прочих технических символов - метаданные (запись о дате и источнике данных) в первых строках файла.
Большинство этих нюансов решается при настройке параметров импорта с помощью аргументов функций импорта (т. е. настройки по умолчанию не справляются). В частности, в функциях чтения таблиц можно задать разделители полей и десятичные разделители (sep и dec), кодировку файла и отображения, обработку пустых строк и т. д. Некоторые проблемы, например, импорт данных с embedded nuls, постепенно решаются в новых версиях функций и пакетов. Помимо этих аргументов, также очень полезны аргументы, которые позволяют прямо указать, сколько строк импортировать (или пропустить от начала), какие типы данных в колонках и какие колонки стоит пропустить, а также надо ли конвертировать в факторы строковые значения.
Приведем простой скрипт, который наглядно продемонстрирует запись и чтение текстового файла
df <- trees
write.table(df, "file.txt")
data <- read.table(file = "file.txt", header = TRUE)
head(data)
plot(data)
set.seed(454)
rnd = round(rnorm(500, 100, 40))
write.table(rnd, "rnd.txt",col.names = F,row.names = F)
RND = read.table(file = "rnd.txt")
head(RND)
RND = RND$V1
hist(RND, breaks = 20)
Запись данных в текстовые файлы: cat, writeLines, write.table
Записывать данные в текстовые форматы можно как построчно, так и сразу всей таблицей. Для записи построчно обычно используется функция writeLines(), в редких случаях — cat() (при указании имени файла происходит перенаправление вывода с консоли в файл).
Ранее в таблицах использовались осмысленные названия строк, поэтому функции для записи по умолчанию сохраняли в файл отдельной колонкой и названия строк. Сейчас именование строк встречается реже, поэтому можно выставлять аргумент row.names = FALSE, чтобы в файл не были записаны отдельной колонкой бесполезные номера строк.
df <- trees
write.table(df, "file.txt")
data <- read.table(file = "file.txt", header = TRUE)
head(data)
plot(data)
set.seed(454)
rnd = round(rnorm(500, 100, 40))
write.table(rnd, "rnd.txt",col.names = F,row.names = F)
RND = read.table(file = "rnd.txt")
head(RND)
RND = RND$V1
hist(RND, breaks = 20)
crnd = as.character(rnd)
writeLines(crnd, con = 'rnd2.txt')
rnd1 = read.table(file = "rnd2.txt")
head(rnd1)
RND1 = read.table(file = "rnd2.txt")
head(RND)
RND1 = RND1$V1
hist(RND1, breaks = 20)