read.csv() превращает CSV-файл в датафрейм
Чтение CSV в R — это один вызов функции, встроенной в язык, без всяких пакетов:
sales <- read.csv("sales.csv")
read.csv() читает файл, использует первую строку как имена столбцов, угадывает тип каждого столбца и возвращает датафрейм. Для благополучного файла это вся история.
Понаблюдать за её работой можно вообще без файла, потому что read.csv() принимает также сырой CSV-текст через аргумент text — тот же парсер, которому подали строку вместо имени файла:
str() — первое, что стоит запускать на всём импортированном: она показывает каждый столбец с угаданным типом. Здесь name пришёл как character, score как integer, passed как logical — всё угадано по значениям. Для быстрой визуальной проверки head(students) показывает первые строки, а nrow(students) их считает. Если столбец, который вы ожидали числовым, оказался chr, значит, что-то в этом столбце не является числом — затесавшийся комментарий, "N/A", разделитель тысяч, — и чинить это надо именно сейчас, а не через три графика.
Аргументы, которые имеют значение
У read.csv() десятки параметров; вы будете использовать примерно пять.
header — содержит ли первая строка имена столбцов. По умолчанию TRUE. Если ваш файл начинается сразу с данных, передайте header = FALSE, и R назовёт столбцы V1, V2, ...
sep — разделитель полей, по умолчанию ",". Большая часть Европы пишет CSV с точками с запятой в качестве разделителей, потому что запятая там — десятичный знак. R поставляет преднастроенный вариант ровно для этого: read.csv2() использует sep = ";" и dec = ",":
Значения роста получились нормальными числами — read.csv2 знала, что 1,63 означает одна целая шестьдесят три сотых. Если бы вы применили к этому файлу обычную read.csv, вы получили бы один искорёженный столбец, потому что ничто не разделит корректно по запятой, которая является десятичным знаком.
na.strings — какие строки считаются пропусками. По умолчанию только "NA" становится пропущенным значением. Реальные выгрузки записывают пропуски как пустые ячейки, "missing", "-", "NULL" — и пока вы их не объявите, они приходят текстом и утаскивают весь столбец в character:
С правильным na.strings пустые значения становятся настоящими NA, а score остаётся числовым. Без него "missing" — просто слово, и столбец текстовый.
skip — сколько строк проигнорировать до начала данных. Выгрузки обожают ставить строку-другую заголовка над самой таблицей; skip = 2 их перескакивает.
colClasses — задать типы столбцов вместо угадывания. Классическая жертва — всё с ведущими нулями: почтовые индексы, номера телефонов, идентификаторы товаров, — которые угадыватель R читает как числа, уничтожая нули:
00501 превратился в 501. Данные были верны в файле и молча неверны в R. colClasses = c("integer", "character") сообщает парсеру, чем является каждый столбец, по порядку, и нули выживают.
Один аргумент, который больше не нужен, — stringsAsFactors. Большую часть истории R read.csv() превращала каждый текстовый столбец в фактор, если не сказать иначе, что вызывало колоссальную путаницу. Начиная с R 4.0 по умолчанию стоит FALSE — текст остаётся текстом. Вы всё ещё будете встречать stringsAsFactors = FALSE в старых учебниках; на современном R это безвредно, но избыточно.
Пути к файлам: причина сбоев read.csv номер один
Ошибка, с которой каждый изучающий R сталкивается на первой неделе:
Error in file(file, "rt") : cannot open the connection
In addition: Warning message:
cannot open file 'sales.csv': No such file or directory
Файл существует — вы смотрите на него в файловом менеджере. Но R смотрит не туда. Голое имя файла вроде "sales.csv" разрешается относительно рабочего каталога R, а тот обычно не является папкой с вашим файлом. Две строки ставят диагноз:
getwd() # where R is actually looking
file.exists("sales.csv") # FALSE means the path is wrong, full stop
Если file.exists() говорит FALSE, никакие перезапуски не помогут — чините путь. Либо укажите полный путь (read.csv("C:/Users/ada/data/sales.csv") — прямые слеши работают и на Windows и безопаснее обратных), либо переместите рабочий каталог R в папку с данными через setwd(). Что такое рабочий каталог, как им управляют проекты и почему setwd() в скриптах не приветствуется, разобрано в статье про рабочий каталог.
Доведите file.exists() до рефлекса. Она за секунду превращает «загадочный сбой импорта» в «опечатку в пути».
Чтение CSV прямо по URL
read.csv() принимает URL везде, где принимает имя файла, и скачивает файл за вас:
url <- "https://raw.githubusercontent.com/mwaskom/seaborn-data/master/penguins.csv"
penguins <- read.csv(url)
str(penguins)
Это удобно для учебных материалов и публичных наборов данных — без шага скачивания и без проблем с путями. Плата в том, что ваш скрипт теперь зависит от сети и от того, что URL останется живым; для всего, что вы будете часто перезапускать, скачайте один раз и читайте локальную копию.
readr::read_csv — более быстрая и разговорчивая альтернатива
Tidyverse поставляет собственный ридер CSV в пакете readr: read_csv() (с подчёркиванием, а не с точкой). Её стоит знать, потому что большая часть современного кода на R, который вы прочтёте, использует именно её:
install.packages("readr") # once
library(readr) # every session
flights <- read_csv("flights.csv")
Практические отличия от read.csv():
- Скорость — заметно быстрее на файлах в сотни тысяч строк.
- Она возвращает тиббл — модернизированный датафрейм, который печатает компактный предпросмотр вместо заливания консоли.
- Она сообщает о своих догадках — после чтения печатает определённый тип каждого столбца, так что столбец, разобранный как character там, где вы ждали числа, виден сразу, а не становится сюрпризом позже.
- Она никогда не коверкает имена столбцов —
read.csv()переписывает заголовок вродеfirst nameвfirst.name;read_csv()оставляет его как есть.
Для маленького файла подойдёт любая функция. Берите read_csv(), когда файлы становятся большими или когда остальная часть вашего скрипта и так на tidyverse. Всё сказанное выше про пути, разделители (read_csv2() тоже существует) и строки пропусков (na =) переносится сюда с немного другими именами аргументов.
Когда анализ закончен, обратный путь — экспорт результатов в файл — это write.csv.
Что вы уносите с собой
df <- read.csv("file.csv")читает CSV в датафрейм; сразу проверяйте его черезstr()иhead().read.csv(text = "...")разбирает строку CSV напрямую — отлично для экспериментов и небольших примеров.- Аргументы, которые окупаются:
header,sep(илиread.csv2для точек с запятой),na.strings,skip,colClasses. - «Cannot open file» означает, что рабочий каталог не там, где вы думаете, —
getwd()иfile.exists()решают вопрос мгновенно. readr::read_csv()— более быстрая версия из tidyverse: тибблы, сообщаемые типы столбцов, нетронутые имена.
Дальше: файлы, которые вовсе не являются простым текстом, — чтение таблиц Excel с помощью пакета readxl.
Часто задаваемые вопросы
Как прочитать CSV-файл в R?
С помощью read.csv("file.csv") — она встроена, пакет не нужен. Она возвращает датафрейм с одним столбцом на каждый столбец CSV, используя первую строку как имена столбцов. Присвойте результат переменной: df <- read.csv("sales.csv"), а затем проверьте его через str(df) и head(df).
Почему read.csv говорит «cannot open file: No such file or directory»?
R ищет файл относительно своего рабочего каталога, а тот, скорее всего, не является папкой с вашим файлом. Выполните getwd(), чтобы увидеть, куда смотрит R, и file.exists("file.csv"), чтобы подтвердить промах. Исправьте это полным путём или установив рабочий каталог в папку с файлом.
В чём разница между read.csv и read_csv в R?
read.csv() — базовый R: всегда доступна, возвращает обычный датафрейм. read_csv() приходит из пакета readr: она быстрее на больших файлах, возвращает тиббл, не трогает имена ваших столбцов и печатает угаданные типы столбцов, чтобы вы сразу заметили неверный разбор. Для маленьких файлов подойдёт любая; для больших файлов или конвейеров tidyverse используйте read_csv().
Как прочитать CSV с точкой с запятой в R?
Используйте read.csv2("file.csv") — это read.csv, преднастроенная под европейское соглашение: точка с запятой как разделитель и запятая как десятичный знак. Или передайте sep = ";" (и при необходимости dec = ",") в обычную read.csv().