--- disqus: ahb0222 GA : G-VF9ZT413CG --- # R 快速合併多個檔案_以CSV為例 > [color=#40f1ef][name=LHB阿好伯, 2023/04/15][:earth_africa:](https://www.facebook.com/LHB0222/) ###### tags: `R` ![](https://hackmd.io/_uploads/SJxUqC_G2.png) [TOC] # CSV ```r= library(dplyr) # 指定資料夾路徑 dir_path <- "C:\\R\\111Q3每日噪音監測資料(原始)" ``` ## 方法一 for() ```r= # 初始化空資料框 result_df <- data.frame() # 循環讀取並合併CSV檔案 for (i in c(1:length(df_files))) { temp_df <- read.csv(df_files[i], header = TRUE) result_df <- rbind(result_df,temp_df) # 合併進度 progress <- round(i/length(df_files), 2)*100 cat(sprintf("Processed file %d of %d (%.0f%%)\n", i, length(df_files), progress)) } # 將合併後的資料保存到新的CSV檔案中 write.csv(result_df, "輸出檔案名稱.csv", row.names = FALSE) ``` ## 方法二 map() ```r= # 讀取目錄下的所有 CSV 檔案 csv_files <- list.files(dir_path, pattern = ".dbf", full.names = TRUE) df_all <- map_df(csv_files, read.dbf) str(df_all) ``` ## 方法三 lapply() ```r=+ data <- lapply(csv_files, read.dbf) final_data <- do.call(rbind, data) #bind_rows() str(final_data) ``` ## 方法三 SQLite ```r= # 加載庫 library(RSQLite) # 建立與數據庫的連接 con <- dbConnect(RSQLite::SQLite(), dbname = "20230404.db") # 循環讀取並寫入CSV檔案 for (i in c(1:length(df_files))) { # 讀取CSV文件 temp_df <- read.csv(df_files[i], header = TRUE) # 將資料直接寫入SQLite dbWriteTable(con, "my_table", temp_df, append = TRUE) # 合併進度 progress <- round(i/length(df_files), 2)*100 cat(sprintf("Processed file %d of %d (%.0f%%)\n", i, length(df_files), progress)) } # 關閉連接 dbDisconnect(con) ``` # 輸出執行進度 `sprintf`是一個用於格式化字串的函數。它的用法如下: `sprintf(format, value1, value2, ...)` 其中,`format`是一個字串,其中包含要格式化的內容以及控制格式化的特殊符號,`value1`、`value2`等則是需要格式化的實際值。 在格式化字串中,透過 `%` 符號來控制具體的格式,例如: - `%s` 使用字串方式輸出變數。 - `%d` 使用數值方式輸出變數。 - `%f` 使用浮點數方式輸出變數。 - `%e` 使用科學計數法方式輸出浮點數。 - `%x` 使用十六進位方式輸出變數。 例如,使用`sprintf`函數將數字和字串格式化為一個字串: ```r= num <- 10 str <- "hello" result <- sprintf("num=%d, str=%s", num, str) print(result) # 輸出:num=10, str=hello ``` `sprintf`函數可以幫助我們方便地格式化輸出結果,特別是在需要將變數輸出為特定格式時。 # 效能測試 ## 測試基準_1000個CSV檔 ```r= # 生成1000個CSV檔案 set.seed(42) csv_files <- sapply(1:1000, function(i) { df <- data.frame( A = rnorm(1000), B = rnorm(1000), C = rnorm(1000), D = rnorm(1000) ) file_name <- paste0("test_csv_", i, ".csv") write.csv(df, file_name, row.names = FALSE) return(file_name) }) ``` ## 計算循環讀取並合併CSV檔案所需時間 ### FOR_99s ```r= profvis({ for (i in c(1:length(csv_files))) { temp_df <- read.csv(csv_files[i], header = TRUE) result_df <- rbind(result_df,temp_df) } }) ``` ![](https://hackmd.io/_uploads/r15XiBdG3.png) ### sqlite_23s ![](https://hackmd.io/_uploads/Skmmz8dz2.png) ### lapply_7s ```r= profvis({ result_df <- do.call(rbind, lapply(csv_files, read.csv, header = TRUE)) }) ``` ![](https://hackmd.io/_uploads/SyhLyLuG3.png) ### purrr&dplyr_6.6s ```r= # 計算使用purrr和dplyr讀取和合併CSV檔案所需時間 profvis({ result_df <- csv_files %>% map(~ read.csv(.x, header = TRUE)) %>% bind_rows() }) ``` ![](https://hackmd.io/_uploads/rJj6RHOf3.png) ### data.table套件_1.1s ```r= # 讀取 CSV 檔案,並將所有檔案合併成一個資料表 profvis({ result_dt <- rbindlist(lapply(csv_files, fread)) }) ``` ![](https://hackmd.io/_uploads/HyS9wC_M2.png) 來個暴力測試將資料提高到10000萬個檔案共四億筆數據的讀取 花費約40秒也比單純for迴圈來的快速 ![](https://hackmd.io/_uploads/By64ZkFzn.png) ## 計算將合併後的資料保存所需時間 ### for()_to_CSV_27s ![](https://hackmd.io/_uploads/B15tsB_M3.png) ![](https://hackmd.io/_uploads/H1J-pr_fh.png) ### to_sqlite_23s ![](https://hackmd.io/_uploads/rkK-GUOMn.png) ![](https://hackmd.io/_uploads/rkhYZUdzh.png) ### fwrite()_to_csv_120ms ![](https://hackmd.io/_uploads/SyHYuCuG2.png) ![](https://hackmd.io/_uploads/rkdCdRdG3.png) ### to_feather_30ms ![](https://hackmd.io/_uploads/HJHY2B_G3.png) ![](https://hackmd.io/_uploads/H1efTHuz2.png) 🌟全文可以至下方連結觀看或是補充 全文分享至 https://www.facebook.com/LHB0222/ https://www.instagram.com/ahb0222/ 有疑問想討論的都歡迎於下方留言 喜歡的幫我分享給所有的朋友 \o/ 有所錯誤歡迎指教 # [:page_with_curl: 全部文章列表](https://hackmd.io/@LHB-0222/AllWritings) ![](https://i.imgur.com/nHEcVmm.jpg)