작업 디렉터리란 무엇인가
모든 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 호출에는 아무 문제가 없습니다. 세션의 작업 디렉터리와 파일의 위치가 어긋난 것이죠. 아래 두 함수가 이것을 미스터리에서 10초짜리 진단으로 바꿔 줍니다.
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, 부서 서버, 또는 정리를 마친 뒤의 자기 컴퓨터에서는 1번 줄에서 오류가 납니다. 절대 경로를 하드코딩하는 것은 한 사람의 폴더 구조를, 그것보다 오래 살아남아야 할 코드에 구워 넣는 일입니다.
해결책은 책임을 뒤집는 것입니다. 스크립트가 폴더를 찾게 하지 말고, 올바른 폴더에서 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 = ...)가 그 벡터의 모든 이름을 삭제하는 것이죠. 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를 자동 저장하거나 복원하지 마세요. 깨끗하게 시작해 스크립트를 다시 실행하는 것이 작업을 재현 가능하게 만듭니다.
다음 순서는 실제 데이터를 읽는 일입니다. R이 이제 올바른 폴더를 보고 있으니 read.csv()와 그 친구들을 다뤄 봅시다.
자주 묻는 질문
R에서 작업 디렉터리는 어떻게 설정하나요?
setwd("path/to/folder")로 변경하고 getwd()로 현재 위치를 확인합니다. RStudio에서는 메뉴(Session → Set Working Directory)도 쓸 수 있습니다. 다만 다시 실행하거나 공유할 것이라면 하드코딩된 setwd() 줄보다 작업 디렉터리를 자동으로 설정해 주는 RStudio 프로젝트를 택하세요. 절대 경로는 다른 모든 컴퓨터에서 깨집니다.
R에서 환경을 어떻게 비우나요?
rm(list = ls())는 전역 환경의 모든 객체를 제거합니다. ls()가 모든 객체 이름을 나열하고 rm()이 그것들을 삭제합니다. 객체 하나만 제거하려면 rm(x)를 쓰세요. 이는 객체만 비운다는 점에 주의하세요. 로드된 패키지는 그대로 남고 콘솔 텍스트도 건드리지 않습니다(그것은 RStudio에서 Ctrl+L입니다).
파일이 있는데도 read.csv가 왜 'cannot open file'이라고 하나요?
R이 상대 경로를 작업 디렉터리를 기준으로 해석하는데, 여러분의 작업 디렉터리가 그 파일이 있는 폴더가 아닌 다른 곳을 가리키고 있기 때문입니다. getwd()로 R이 어디를 보고 있는지, list.files()로 그곳에서 무엇이 보이는지 확인하세요. 스크립트에 절대 경로를 붙여 넣는 대신 올바른 폴더에서 프로젝트를 열어(또는 setwd()로) 고치세요.