[R data.table] 데이터를 읽어와서 data.table 만들기, data.frame을 data.table로 변환하기
R 분석과 프로그래밍/R 데이터 전처리 2020. 9. 27. 22:04지난번 포스팅에서는 R data.table 이 무엇이고, 왜 data.table 이 좋은지, 어떻게 패키지를 설치하는지에 대해서 알아보았습니다.
그러면 이번 포스팅에서는 샘플 데이터를 가지고 data.table 을 만들어보는 몇 가지 방법을 소개하겠습니다.
-- 로컬에서 csv 파일, txt 파일을 읽어와서 data.table 만들기
(1) fread() 함수로 csv 파일을 빠르게 읽어와서 R data.table 로 만들기
(2) fwrite() 함수로 R data.table을 csv 파일로 빠르게 쓰기
-- 메모리 상에서 data.table 만들기
(3) data.table() 함수로 R data.table 만들기
(4) data.table() 함수로 기존의 data.frame을 data.table로 변환하기
(5) rbindlist() 함수로 여러개로 쪼개져 있는 파일들을 하나의 data.table로 합치기
먼저, data.table의 fread() 함수를 사용해서 로컬 머신에 있는 csv file 을 빠르게(Fast!!) 읽어와서 R data.table로 만들거나, 혹은 반대로 fwrite() 함수를 사용해서 data.table을 빠르게(Fast!!!) csv file로 쓰는 방법을 소개하겠습니다.
(1) fread() 함수로 csv 파일을 빠르게 읽어와서 R data.table 로 만들기 |
data.table의 fread() 함수는 Base R의 read.csv() 함수 또는 read.table() 함수와 유사한 역할을 합니다만, 대신에 fread() 라는 이름에서 짐작할 수 있듯이 매우 빠릅니다(Fast Read)! 벤치마킹 테스트를 해보면 fread() 가 read.table() 보다 40배 이상 빠릅니다!!
파일을 빠르게 읽어와서 data.table 자료로 만들 때 로컬 file path (directory/file_name)를 입력해줘도 되고, https:// 로 시작하는 url 을 입력해줘도 됩니다. 아래 예에서는 UCI Machine Learning Repository에 오픈되어 있는 abalone.data 데이터셋을 url을 통해 읽어와서 data.table로 만들어보았습니다.
Base R 의 data.frame에서는 문자형 칼럼의 경우 디폴트가 요인형(factor)으로 인식하는데요, data.table은 그렇지 않습니다. 만약 data.table에서 문자형 칼럼을 요인형(factor)로 인식하게 하려면 stringsAsFactors = TRUE 라고 명시적으로 설정을 해줘야 합니다.
#install.packages("data.table") library(data.table) # (1) Fast reading csv file using fread() url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data' abalone_dt <- fread(url, sep=",", stringsAsFactors=TRUE, header = FALSE, col.names=c("sex", "length", "diameter", "height", "whole_weight", "shucked_weight", "viscera_weight", "shell_weight", "rings")) > head(abalone_dt) sex length diameter height whole_weight shucked_weight viscera_weight shell_weight rings 1: M 0.455 0.365 0.095 0.5140 0.2245 0.1010 0.150 15 2: M 0.350 0.265 0.090 0.2255 0.0995 0.0485 0.070 7 3: F 0.530 0.420 0.135 0.6770 0.2565 0.1415 0.210 9 4: M 0.440 0.365 0.125 0.5160 0.2155 0.1140 0.155 10 5: I 0.330 0.255 0.080 0.2050 0.0895 0.0395 0.055 7 6: I 0.425 0.300 0.095 0.3515 0.1410 0.0775 0.120 8
|
* 참고: https://www.rdocumentation.org/packages/data.table/versions/1.13.0/topics/fread
(2) fwrite() 함수로 R data.table을 csv 파일로 빠르게 쓰기 |
data.table의 fwrite() 함수는 Base R의 write.csv() 와 유사한 역할을 합니다만, 역시 fwrite()의 이름에서 짐작할 수 있듯이 매우 매우 빠릅니다! Base R의 write.csv()보다 data.table의 fwrite()가 약 30~40배 더 빠릅니다!!! 여러개의 CPU가 있을 경우 fwrite()는 이들 CPU를 모두 이용해서 쓰기를 하기 때문입니다.
# (2) fwrite(): Fast CSV Writer fwrite(x = abalone_dt, file = "/Users/ihongdon/Downloads/abalone.csv", append = FALSE, sep = ",", na = "", row.names = FALSE, col.names = TRUE )
-- [Terminal] command line (base) ihongdon@lhongdon-a01 ~ % cd Downloads (base) ihongdon@lhongdon-a01 Downloads % (base) ihongdon@lhongdon-a01 Downloads % ls abalone.csv (base) ihongdon@lhongdon-a01 Downloads % (base) ihongdon@lhongdon-a01 Downloads % (base) ihongdon@lhongdon-a01 Downloads % cat abalone.csv sex,length,diameter,height,whole_weight,shucked_weight,viscera_weight,shell_weight,rings M,0.455,0.365,0.095,0.514,0.2245,0.101,0.15,15 M,0.35,0.265,0.09,0.2255,0.0995,0.0485,0.07,7 F,0.53,0.42,0.135,0.677,0.2565,0.1415,0.21,9 ... |
* 참고: https://www.rdocumentation.org/packages/data.table/versions/1.13.0/topics/fwrite
(3) data.table() 함수로 R data.table 만들기 |
data.table 자료구조는 data.frame 의 특성을 그대로 이어받아서 확장한 데이터 구조입니다. 따라서 Base R 에서 사용하는 함수를 모두 사용할 수 있습니다.
아래 예에서는 2개의 변수와 10개의 관측치를 가진 데이터셋에 대해 data.table() 함수를 사용해서 data.table 클래스 객체를 만들어보았습니다.
# (3) constructing data.table data_dt <- data.table(g = c(rep('a', 5), rep('b', 5)), x = 1:10) > > str(data_dt) Classes 'data.table' and 'data.frame': 10 obs. of 2 variables: $ g: chr "a" "a" "a" "a" ... $ x: int 1 2 3 4 5 6 7 8 9 10 - attr(*, ".internal.selfref")=<externalptr> > > head(data_dt) g x 1: a 1 2: a 2 3: a 3 4: a 4 5: a 5 6: b 6 |
* 참고: https://www.rdocumentation.org/packages/data.table/versions/1.13.0/topics/data.table-package
(4) data.table() 함수로 기존의 data.frame을 data.table로 변환하기 |
기존 Base R의 data.frame을 data.table() 함수를 사용하면 간단하게 data.table 자료구조로 변환할 수 있습니다.
> # DataFrame of base R > data_df <- data.frame(g = c(rep('a', 5), rep('b', 5)), x = 1:10) > > str(data_df) 'data.frame': 10 obs. of 2 variables: $ g: Factor w/ 2 levels "a","b": 1 1 1 1 1 2 2 2 2 2 $ x: int 1 2 3 4 5 6 7 8 9 10 > > # (4) converting data.frame to data.table > data_dt2 <- data.table(data_df) > > str(data_dt2) Classes 'data.table' and 'data.frame': 10 obs. of 2 variables: $ g: Factor w/ 2 levels "a","b": 1 1 1 1 1 2 2 2 2 2 $ x: int 1 2 3 4 5 6 7 8 9 10 - attr(*, ".internal.selfref")=<externalptr> > > head(data_dt2) g x 1: a 1 2: a 2 3: a 3 4: a 4 5: a 5 6: b 6 |
(5) rbindlist() 함수로 여러개로 쪼개져 있는 파일들을 하나의 data.table로 합치기 |
여러개의 파일을 폴더에서 차례대로 읽어들여서 하나의 data.table로 합치는 방법은 rbindlist() 함수를 사용하면 무척 간단하게 할 수 있습니다.
예를 들어, 아래처럼 'file_1.txt', 'file_2.txt', 'file_3.txt' 의 3개의 텍스트 파일이 있다고 해보겠습니다. 이럴 경우 먼저 list.files() 함수로 특정 폴더에 들어있는 이들 3개의 파일 이름을 리스트로 만들어 놓습니다. 다음으로 읽어온 파일을 하나씩 리스트로 쌓아놓을 빈 templist 를 만들어놓고, for loop 반복문을 사용하여 텍스트 파일 이름이 들어있는 리스트 f_list 로부터 하나씩 차례대로 파일이름을 읽어와서 paste0(base_dir, f_list[i]) 로 전체의 파일 경로(디렉토리/파일이름.txt)를 만들고, fread() 함수로 하나씩 읽어와서 templist 에 차곡차곡 쌓아놓습니다. 마지막에 rbindlist(templist) 로 모든 리스트를 합쳐서 하나의 data.table 을 만듭니다.
> # (5) combining multiple files into a data.table using rbindlist() > base_dir <- '/Users/ihongdon/Downloads/files/' > f_list <- list.files(base_dir) > print(f_list) [1] "file_1.txt" "file_2.txt" "file_3.txt" > > paste0(base_dir, f_list[1]) [1] "/Users/ihongdon/Downloads/files/file_1.txt" > > templist <- list() # black list to store multiple data.tables > for(i in 1:length(f_list)) { + f_path <- paste0(base_dir, f_list[i]) + templist[[i]] <- fread(f_path) + } > > all_dt <- rbindlist(templist) > str(all_dt) Classes 'data.table' and 'data.frame': 9 obs. of 3 variables: $ x1: int 1 4 7 10 13 16 19 22 25 $ x2: int 2 5 8 11 14 17 20 23 26 $ x3: int 3 6 9 12 15 18 21 24 27 - attr(*, ".internal.selfref")=<externalptr> > > print(all_dt) x1 x2 x3 1: 1 2 3 2: 4 5 6 3: 7 8 9 4: 10 11 12 5: 13 14 15 6: 16 17 18 7: 19 20 21 8: 22 23 24 9: 25 26 27 |
https://rfriend.tistory.com/225 포스팅에 보면 (a) do.call(rbind, data), (b) ldply(data, rbind), (c) rbind.fill(data), (d) rbindlist(data) 의 4가지 패키지/함수별로 비교를 했을 때 data.table의 rbindlist() 가 월등히 빠르다고 소개를 하였습니다.(비교가 안되게 빠름!!!)
다음번 포스팅에서는 data.table의 기본 구문에 대해서 소개하겠습니다.
많은 도움이 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.