比較 R 軟體 7 種不同的資料檔存取方法

最近在臉書的 「台灣R軟體Club」社團 中,Kang-Chung Yang 網友提到希望能用平行運算方式存/取大檔案以加快速度。熱心的陳慶全網友 Google 出可以使用 R 軟體內建的 readRDS/saveRDS 搭配 xz 或 pigz 兩個平行壓縮軟體來加快速度。

以下是我測試的結果,先講結論:

(1) 如果硬碟空間夠大:feather 套件的 read_feather 與 write_feather 速度最快,而且遠遠超過其他方法

(2) 如果硬碟空間有限:顧及存取速度、檔案大小、read/write 函數/資料檔格式的一致性,則 readRDS/saveRDS + pigz 是最適當的組合

這次比較的 7 種 read/write 組合:

1. R 內建的 read.csv/write.csv  (CSV 檔)

2. data.table 套件的 fread/fwrite (CSV 檔)

3. R 內建的 load/save (Rdata 檔)

4. R 內建的 readRDS/saveRDS  (rds 檔)

5. readRDS/saveRDS 搭配 pxz 平行壓縮軟體 (readRDS.xz, saveRDS.xz)

6. readRDS/saveRDS 搭配 pigz 平行壓縮軟體 (readRDS.gz, saveRDS.gz)

7. feather 套件的 feather_read/feather_write

測試環境:IBM X3650 M4 伺服器, Xeon E5-2620 V2 單 CPU (12 threads), 128 GB 記憶體

測試時使用的檔案讀寫空間:從記憶體切出 50 GB 當作 Ram Disk

參考文章:

(1) 陳慶全網友找出的 Stackoverflow.com 上的原始程式碼建議
(2) Kang-Chung Yang 網友在 PTT R_Language 版用 33 GB 資料檔測試。結果顯示 readRDS/saveRDS 搭配 pigz 組合表現最佳

(3) pigz 網站
(4) pigz windows 版

Note: Debian/Ubuntu Linux

相關的 R codes (前 4 個函數來自 stackoverflow.com 文章, pigz windows R code 是陳慶全網友撰寫) :

?View Code LANGUAGE
saveRDS.xz = function(object,file,threads=parallel::detectCores()) {
  con = pipe(paste0("pxz -T",threads," > ",file),"wb")
  saveRDS(object, file = con, compress=FALSE)
  close(con)
}
 
readRDS.xz = function(file,threads=parallel::detectCores()) {
  con = pipe(paste0("pxz -d -k -c -T",threads," ",file))
  object = readRDS(file = con)
  close(con)
  return(object)
}
 
saveRDS.gz = function(object,file,threads=parallel::detectCores()) {
  con = pipe(paste0("pigz -p",threads," > ",file),"wb")
  saveRDS(object, file = con)
  close(con)
}
 
readRDS.gz = function(file,threads=parallel::detectCores()) {
  con = pipe(paste0("pigz -d -c -p",threads," ",file))
  object = readRDS(file = con)
  close(con)
  return(object)
}
 
#########################################################
# Windows version
#########################################################
saveRDS.gz = function(object,file,threads=parallel::detectCores()) {
con = pipe(paste0("C:\\pigz-2.3-bin-win32\\pigz.exe -p",threads," > ",file),"wb")
saveRDS(object, file = con)
close(con)
}
 
readRDS.gz = function(file,threads=parallel::detectCores()) {
con = pipe(paste0("C:\\pigz-2.3-bin-win32\\pigz.exe -d -c -p",threads," ",file))
object = readRDS(file = con)
close(con)
return(object)
}