일단 뭘 하더라도 파일을 읽어와야 분석을 하던 그래프를 그리던 할 것이다. 당연히 되겠지… 하면서 덤비지만 정작 내가 사용한 코드는 동작하지 않는걸… 그러다보면 자연스레 엑셀을 켜게 되는 자신을 발견하게 된다. 그래도 엑셀에서 되면 그나마 다행인데 엑셀에서 지원하지 않는 분석 기법이나 그래프가 필요하다면 다시 좌절하게 된다. 그럼 기본함수 부터 패키지 활용까지 알아보도록 하자.
나는 무엇을 들고 있나?
레슨 받는 학생이나 주변사람의 파일이 읽어지지 않는다는 제보를 받을 때가 있다. 그래서 “파일이 뭐에요?” 라고 여쭤보면 “XX 실험 데이터요.” 라고 답하는 경우가 있다. 사실 무슨 데이터건 관심은 없는데 앞에서 말한 질문을 조금 풀어써보면 “읽어오려는 파일의 확장자가 정확하게 어떻게 되나요?”가 된다.
확장자?
확장자. 보다 정확하게는 파일 확장자. 영어로는 file extension이라고 한다.
파일명 뒤에 csv
, json
이런것이다. 옛날에는 파일 및 확장자에 할당되는 데이터 용량을 제한했기 때문에 파일명도 8자를 못넘기고 확장자의 경우 3자리 까지 표기(FAT의 8.3RULE 참조)했었지만, 요즘에는 json
, xlsx
같이 길이가 4자 이상인 것이 많아졌다.
아무튼 확장자는 파일에 어떤 내용이 들어있는지, 어떤 프로그램으로 열 수 있는지 알려주는 역할을 하며 확장자를 확인해야 그에 맞는 함수를 선택하여 데이터를 읽어올 수 있다.
R 기본 함수 활용
R 콘솔에서 다음과 같이 입력해보자.
1 | ?read.csv |
분명 read.csv()
함수의 도움말을 호출했는데 상당히 많은 함수의 도움말이 같이 호출되었다. read.csv()
함수를 포함하여 read.table()
, read.csv2()
, read.delim()
, read.delim2()
함수는 기능이 거의 비슷하여 어떤 함수를 골라써도 큰 무리가 없다.
이 중에서 가장 많이 사용하는 함수는 read.csv()
함수로 각 값이 쉼표(comma)로 구분된 csv(comma-separated values)파일을 읽어올 때 사용한다.
사실 read.csv2()
함수가 조금 더 개선된 함수이긴 하나 잘 사용하지 않는다.
read.csv()
함수에 대응되는 파일 쓰기 함수는 write.csv()
함수이다. csv 파일 확장자로 파일을 저장하는데 사용되는 가장 기본적인 함수이며 이 함수의 도움말을 호출할 경우 write.table()
, write.csv()
, write.csv2()
함수를 볼 수 있다.
앞에서 소개한 함수는 기본적으로 windows 운영체제 기준 메모장(MAC은 TextEdit)에서 열 수 있는 특별하지 않는 텍스트 파일 대상으로 한다고 생각하면 되겠다. 그리고 읽고 쓰는 파일의 기준은 엑셀 스프레드시트에서 열어서 보는 2차원 데이터를 기준으로 하고 향후 별도의 게시물에서 다양한 형식의 파일과 함께 관련 함수를 다루고자 한다.
패키지 활용
기본함수는 한계가 있다. 첫 번째는 속도. 두 번째는 범용성. read.csv()
같은 함수로 1GB 이상의 큰 파일을 읽는다면 제법 시간이 오래걸린다. 하지만 파일 입출력에 최적화된 패키지를 사용한다면 속도가 5~20배 정도는 빨라진다.
다양한 패키지가 있지만, 속도 면에서 이점이 있는 data.table과 readr 패키지를, 엑셀 파일을 읽고 쓰는 readxl과 writexl 패키지를 소개하고자 한다.
1. data.table
기본적으로 병렬처리를 지원하는 패키지이다. 패키지를 불러오면 몇 개의 스레드(thread)를 사용하는지 다음과 같이 알려준다.
컴퓨터의 CPU에 core가 많을수록 사용 가능한 스레드는 증가하는데 아무튼 4개의 스레드를 사용한다는 것은 이론적으로는 4배, 현실적으로는 약 3.2배 정도(정확하게 벤치마킹 하지 않아 확실치 않음) 빨라진다고 볼 수 있다. 이게 read.csv()
함수 대비 3.2배 정도 빠른 것이 아니라 data.table 패키지의 fread()
함수가 1 스레드를 사용하는 것 대비 빠르다는 것이다. 기본적으로 fread()
함수는 read.csv()
보다 최소 10배 이상 빠른데 여기에서 병렬처리 까지 더해지니 굉장히 빠른 함수라고 보면 되겠다. 이런 이유로 필자 또한 200MB 이상의 파일이라면 고민하지 않고 fread()
함수(fast read)를 사용하여 처리한다.
fread()
로 읽어온 데이터는 data.table 이라는 객체 속성을 가지는데 이는 기본 객체인 data.frame과 다르기 때문에 data.table 문법을 모른다면 읽어올 때 다음과 같이 data.table 인자에 FALSE 값을 할당해주자.
1 | library("data.table") |
그리고 데이터를 기록할 때는 fwrite()
함수(fast write)를 사용하면 된다.
1 | fwrite("file_name.csv") |
데이터를 보조기억장치(HDD, SSD)에 기록하는 속도는 굉장히 빨라서 데이터가 2GB가 넘지 않는 이상 1~2초 내에 작업이 끝나는 것을 볼 수 있을 것이다.
2. readr
data.table 패키지 처럼 병렬처리를 지원하진 않지만 기본 함수 보다는 빠르다. 그리고 이 패키지도 읽어오는 객체의 경우 기본 data.frame이 아니라 tibble 이라는 객체 속성을 사용하여 속도 향상을 꾀한다.
대표적인 파일 읽기 함수인 read_csv()
를 사용하면 다채로운 색상으로 콘솔창이 꾸며지는데 이 패키지의 특징이다. tibble 객체의 특징은 각 변수별로 속성을 친절하게 표기해줘서 분석가가 보다 편리하게 데이터를 다룰 수 있도록 한다.
이미 눈치 챘겠지만 readr 패키지의 쓰기 함수는 write_csv()
이다. 이 외에도 다양한 함수가 많으니 찾아보면 되겠다.
3. readxl/writexl
데이터를 데이터베이스에서 가져오는 것이 아니라 파일 단위로 직접 만들고 편집하는 경우는 엑셀을 꼭 쓰기 마련이다. 엑셀 파일에 있는 데이터를 불러오려면 기본함수로는 해결이 안되는데 R에는 이전부터 꽤 많은 엑셀 관련 패키지가 있었다. 예전에 만들어진 엑셀 패키지는 JAVA에 의존성이 있어 컴퓨터에 JAVA를 설치하고 rJava 패키지 까지 설치하고 정상 동작시켜야 했기에 초보자가 사용하기 꽤 어려웠다. 하지만 readxl과 writexl 패키지는 JAVA 의존성이 없어서 다른 엑셀 관련 패키지 보다 훨씬 사용하기 편리하다.
readxl 패키지는 read_xls()
함수와 read_xlsx()
함수가 있지만 read_excel()
함수 하나로 해결이 가능하다. read_excel()
함수는 파일 확장자를 확인하여 확장자가 xls면 read_xls()
로 파일을 읽고, xlsx면 read_xlsx()
를 사용하여 파일을 읽기 때문에 함수를 외운다면 read_excel()
하나를 외우도록 하자.
엑셀 파일을 다루면서 좀 아쉬운 점은 하나의 패키지에서 읽고 쓰는 함수를 다 지원하지 않는 다는 것이다. 그런데 여기서 언급하고싶은 점이 하나 있다. 업무를 하다보면
라는 요청을 받는다.
하지만 굳이 엑셀파일로 줄 필요가 없다. 이게 나쁜 심보가 아니라, 보통 파일 저장은 csv파일 형식으로 하는데 csv파일의 경우는 엑셀에서 별다른 처리 없이 바로 열 수 있다.
앞에 확장자 설명 부분을 보면 분명 확장자가 csv인데도 불구하고 엑셀 아이콘이 있는 것을 볼 수 있다. csv 파일의 경우 xls나 xlsx와 살짝 다른 아이콘이긴 하나 엑셀에서 호환된다고 충분히 인지할 수 있는 아이콘으로 바뀌며 혹시나 한 번도 파일 확장자와 엑셀에서 연결되지 않은 경우는 하얀 A4 용지와 같은 아이콘으로 되어있다. 그래서 이런 경우에 “이거 되는거 맞아요?” 라는 질문이 오긴 하는데 연결 프로그램 에서 엑셀을 선택해주면 된다고 알려주면(알려주지 않으면 모름) 다음부터 잘 다룬다.
더 없나?
위 내용을 참고하여 파일을 읽어오더라도 문제가 생길 수 있다. 예를 들어 확장자가 잘못되어있는 경우도 있고 파일에 들어있는 데이터에 문제가 있는 경우도 있다. 이렇게 파일을 읽고 쓰는데 있어 발생하는 문제는 향후 다루고자 한다.
<파일 입출력 시리즈>
R 파일 입출력 - 1
R 파일 입출력 - 2
R 파일 입출력 - 3
R 파일 입출력 - 4