Что такое рабочий каталог
Каждая сессия R выполняется «внутри» ровно одной папки — рабочего каталога. Всякий раз, когда вы используете относительный путь (путь, не начинающийся от корня файловой системы), R разрешает его относительно этой папки. read.csv("data.csv") означает не «найди data.csv где-нибудь на моём компьютере»; это означает «открой файл с именем data.csv в рабочем каталоге».
Один этот факт объясняет самую частую ошибку новичков в R:
read.csv("data.csv")
# Error in file(file, "rt") : cannot open the connection
# In addition: Warning message: cannot open file 'data.csv': No such file or directory
Файл существует — просто не в той папке, куда сейчас смотрит R. С вашим вызовом read.csv всё в порядке; расходятся рабочий каталог сессии и расположение файла. Две функции ниже превращают эту загадку в десятисекундную диагностику.
getwd() и setwd()
getwd() (get working directory) говорит, куда R смотрит прямо сейчас:
Выполните это — и увидите абсолютный путь, папку, к которой привязана сессия. setwd() (set working directory) меняет его:
setwd("C:/Users/rosa/projects/sales-analysis") # Windows: use / not \
setwd("/Users/rosa/projects/sales-analysis") # macOS / Linux
getwd() # confirm it took
Две технические заметки. На Windows пишите пути через / (или удвоенный \\) — одиночный \ внутри строк R является экранирующим символом, поэтому "C:\Users" это синтаксическая ошибка. И setwd() немедленно даёт ошибку, если папки не существует, — это самый дружелюбный отказ за весь день: он не может молча оставить вас смотрящим не туда.
Поэтому порядок отладки для любой ошибки «cannot open file» такой: getwd(), чтобы увидеть, куда смотрит R, а затем сравнить это с тем, где на самом деле лежит файл.
list.files(): посмотреть, что видит R
Третий инструмент набора перечисляет содержимое рабочего каталога — буквально множество имён, до которых может дотянуться относительный путь:
Если файл, который вы пытаетесь прочитать, есть в этом выводе, read.csv("thatfile.csv") его найдёт. Если нет, никакое переписывание строки read.csv не поможет — чинить нужно рабочий каталог. list.files("data") заглядывает в подпапку, а list.files(pattern = "\\.csv$") фильтрует только CSV. Когда имя файла выглядит правильным, но не находится, list.files() также вскрывает классических виновников: невидимое расширение .txt, дописанное текстовым редактором, или Data.csv вместо data.csv в системе, чувствительной к регистру.
Почему жёстко прописанный setwd() ломается
Теперь принципиальная часть. Вам встретятся скрипты, которые открываются строкой:
setwd("C:/Users/me/Desktop/stuff/project3/final_FINAL")
Эта строка работает ровно на одной машине — авторской. На вашем ноутбуке, на Mac коллеги, на сервере отдела или на вашем же компьютере после реорганизации она падает на первой строке. Жёстко прописанный абсолютный путь впекает раскладку папок одного человека в код, который должен её пережить.
Решение — перевернуть ответственность: не заставляйте скрипт искать папку — запускайте R в правильной папке и используйте относительные пути внутри скрипта. Конкретно:
- Используйте проекты RStudio. Открытие файла
.Rprojавтоматически задаёт рабочий каталог папкой проекта на любой машине. Внутри скриптаread.csv("data/sales.csv")тогда работает у всех, у кого есть проект. - Запуск из терминала делает то же самое:
Rscript analysis.Rиспользует папку, из которой вы его запустили, в качестве рабочего каталога (см. запуск скриптов R). - Пакет here идёт ещё дальше для тех, кому это нужно:
here::here("data", "sales.csv")строит пути от корня проекта независимо от того, куда забрёл рабочий каталог, — но проекты плюс относительные пути закрывают большинство потребностей и без него.
Сам по себе setwd() не зло — он вполне уместен в интерактивной работе, при разведке. Дурно пахнет именно абсолютный, привязанный к машине setwd(), закоммиченный в начало общего скрипта.
Рабочее пространство: ls() и rm()
Рядом с вопросом «в какой я папке» стоит вторая часть состояния сессии — рабочее пространство (глобальное окружение), то есть все объекты, созданные вами в этой сессии. ls() их перечисляет, rm() удаляет:
Последний ls() печатает character(0) — пустое рабочее пространство. Заклинание rm(list = ls()) выглядит странно, пока его не разберёшь: ls() возвращает символьный вектор всех имён объектов, а rm(list = ...) удаляет каждое имя из этого вектора. Это кодовый эквивалент иконки метлы на панели Environment в RStudio.
Знайте, чего оно не делает: пакеты, загруженные через library(), остаются загруженными, опции остаются установленными, а рабочий каталог остаётся на месте. Оно очищает объекты и ничего больше — так что это не замена перезапуску R, когда вам нужен по-настоящему чистый лист.
Очистка консоли и ловушка .RData
Очистка консоли — прокрутки команд и вывода — косметична и отделена от очистки рабочего пространства. В RStudio это Ctrl+L; в коде причудливая cat("\014") посылает символ перевода страницы, который большинство консолей понимают как «очистить экран». Ни то ни другое не трогает ваши объекты.
Наконец, ловушка. При выходе из R он предлагает «save workspace image?» — записать каждый объект в скрытый файл .RData, который молча перезагрузится в следующий раз, когда вы запустите R в этой папке. Откажитесь и отключите это навсегда (RStudio: Tools → Global Options → снять галочку «Restore .RData», поставить «Save workspace» в Never). Восстановленное рабочее пространство означает, что ваша сессия стартует загрязнённой объектами недельной давности, созданными кодом, который вы с тех пор могли изменить или удалить. Ваш скрипт кажется рабочим — потому что опирается на устаревший model_v2, который в файле уже ничто не создаёт, — ровно до момента, когда он запустится на чистой машине и рухнет.
Профессиональная привычка обратная: стартуйте с чистого листа и перезапускайте скрипт. Если ваш анализ — это скрипт, выполняющийся сверху вниз в свежей сессии, он воспроизводим по построению; рабочее пространство — расходный вывод, а не драгоценное состояние. Перезапускайте R почаще (RStudio: Session → Restart R) именно затем, чтобы доказать, что ваш скрипт по-прежнему держится сам по себе.
Что вы уносите с собой
- Относительные пути разрешаются относительно рабочего каталога;
getwd()его показывает,setwd()меняет,list.files()показывает, что доступно. - «Cannot open file» почти всегда означает расхождение рабочего каталога и папки с файлом — диагностируйте через
getwd()+list.files(). - Никогда не коммитьте абсолютный
setwd()в общий скрипт — используйте проекты RStudio (или запускайте скрипт из его папки) и относительные пути. ls()перечисляет объекты рабочего пространства;rm(x)удаляет один;rm(list = ls())очищает все — пакеты и опции остаются.- Ctrl+L (или
cat("\014")) очищает только текст консоли. - Не сохраняйте и не восстанавливайте
.RDataавтоматически: стартуйте чисто и перезапускайте скрипт — именно это делает вашу работу воспроизводимой.
Дальше: чтение настоящих данных — read.csv() и родственные функции, теперь, когда R смотрит в нужную папку.
Часто задаваемые вопросы
Как задать рабочий каталог в R?
Вызовите setwd("path/to/folder"), чтобы сменить его, и getwd(), чтобы увидеть текущий. В RStudio можно также воспользоваться меню: Session → Set Working Directory. Но для всего, что вы будете перезапускать или передавать другим, предпочитайте проект RStudio (он задаёт рабочий каталог автоматически) вместо жёстко прописанной строки setwd() — абсолютные пути ломаются на любой другой машине.
Как очистить окружение в R?
rm(list = ls()) удаляет каждый объект из глобального окружения: ls() перечисляет все имена объектов, а rm() их удаляет. Чтобы убрать один объект, используйте rm(x). Учтите, что это очищает только объекты — загруженные пакеты остаются загруженными, а текст консоли не трогается (за это отвечает Ctrl+L в RStudio).
Почему read.csv говорит «cannot open file», хотя файл существует?
Потому что R разрешает относительные пути относительно своего рабочего каталога, а ваш указывает не на ту папку, где лежит файл. Выполните getwd(), чтобы увидеть, куда смотрит R, и list.files(), чтобы увидеть, что он там видит. Исправьте это, открыв проект в правильной папке (или через setwd()), а не вставляя абсолютный путь в скрипт.