지난번 포스팅에서는 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의 기본 구문에 대해서 소개하겠습니다. 



많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.



728x90
반응형
Posted by Rfriend
,