Một tidyverse
giải pháp nhanh chóng và cô đọng : (nhanh hơn gấp đôi so với Base R read.csv
)
tbl <-
list.files(pattern = "*.csv") %>%
map_df(~read_csv(.))
và data.table 's fread()
thậm chí có thể cắt những thời gian tải một nửa nữa. (cho 1/4 số lần R cơ sở )
library(data.table)
tbl_fread <-
list.files(pattern = "*.csv") %>%
map_df(~fread(.))
Đối stringsAsFactors = FALSE
số giữ cho yếu tố khung dữ liệu miễn phí, (và như chỉ ra, là cài đặt mặc định cho fread
)
Nếu typecasting đang táo tợn, bạn có thể buộc tất cả các cột là ký tự với col_types
đối số.
tbl <-
list.files(pattern = "*.csv") %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
Nếu bạn muốn nhúng vào các thư mục con để xây dựng danh sách các tệp của mình để cuối cùng liên kết, thì hãy chắc chắn bao gồm tên đường dẫn, cũng như đăng ký các tệp với tên đầy đủ của chúng trong danh sách của bạn. Điều này sẽ cho phép công việc ràng buộc đi ra ngoài thư mục hiện tại. (Suy nghĩ về các tên đường dẫn đầy đủ hoạt động như hộ chiếu để cho phép di chuyển trở lại qua thư mục 'viền'.)
tbl <-
list.files(path = "./subdirectory/",
pattern = "*.csv",
full.names = T) %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
Như Hadley mô tả ở đây (khoảng một nửa):
map_df(x, f)
có hiệu quả tương tự như do.call("rbind", lapply(x, f))
....
Tính năng Phần thưởng - thêm tên tệp vào bản ghi theo yêu cầu tính năng Niks trong các nhận xét bên dưới:
* Thêm bản gốc filename
vào mỗi bản ghi.
Mã giải thích: tạo một hàm để nối tên tệp vào mỗi bản ghi trong quá trình đọc các bảng ban đầu. Sau đó sử dụng chức năng đó thay vì read_csv()
chức năng đơn giản .
read_plus <- function(flnm) {
read_csv(flnm) %>%
mutate(filename = flnm)
}
tbl_with_sources <-
list.files(pattern = "*.csv",
full.names = T) %>%
map_df(~read_plus(.))
(Các cách tiếp cận xử lý kiểu chữ và thư mục con cũng có thể được xử lý bên trong read_plus()
hàm theo cách tương tự như minh họa trong các biến thể thứ hai và thứ ba được đề xuất ở trên.)
### Benchmark Code & Results
library(tidyverse)
library(data.table)
library(microbenchmark)
### Base R Approaches
#### Instead of a dataframe, this approach creates a list of lists
#### removed from analysis as this alone doubled analysis time reqd
# lapply_read.delim <- function(path, pattern = "*.csv") {
# temp = list.files(path, pattern, full.names = TRUE)
# myfiles = lapply(temp, read.delim)
# }
#### `read.csv()`
do.call_rbind_read.csv <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
do.call(rbind, lapply(files, function(x) read.csv(x, stringsAsFactors = FALSE)))
}
map_df_read.csv <- function(path, pattern = "*.csv") {
list.files(path, pattern, full.names = TRUE) %>%
map_df(~read.csv(., stringsAsFactors = FALSE))
}
### *dplyr()*
#### `read_csv()`
lapply_read_csv_bind_rows <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
lapply(files, read_csv) %>% bind_rows()
}
map_df_read_csv <- function(path, pattern = "*.csv") {
list.files(path, pattern, full.names = TRUE) %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
}
### *data.table* / *purrr* hybrid
map_df_fread <- function(path, pattern = "*.csv") {
list.files(path, pattern, full.names = TRUE) %>%
map_df(~fread(.))
}
### *data.table*
rbindlist_fread <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
rbindlist(lapply(files, function(x) fread(x)))
}
do.call_rbind_fread <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
do.call(rbind, lapply(files, function(x) fread(x, stringsAsFactors = FALSE)))
}
read_results <- function(dir_size){
microbenchmark(
# lapply_read.delim = lapply_read.delim(dir_size), # too slow to include in benchmarks
do.call_rbind_read.csv = do.call_rbind_read.csv(dir_size),
map_df_read.csv = map_df_read.csv(dir_size),
lapply_read_csv_bind_rows = lapply_read_csv_bind_rows(dir_size),
map_df_read_csv = map_df_read_csv(dir_size),
rbindlist_fread = rbindlist_fread(dir_size),
do.call_rbind_fread = do.call_rbind_fread(dir_size),
map_df_fread = map_df_fread(dir_size),
times = 10L)
}
read_results_lrg_mid_mid <- read_results('./testFolder/500MB_12.5MB_40files')
print(read_results_lrg_mid_mid, digits = 3)
read_results_sml_mic_mny <- read_results('./testFolder/5MB_5KB_1000files/')
read_results_sml_tny_mod <- read_results('./testFolder/5MB_50KB_100files/')
read_results_sml_sml_few <- read_results('./testFolder/5MB_500KB_10files/')
read_results_med_sml_mny <- read_results('./testFolder/50MB_5OKB_1000files')
read_results_med_sml_mod <- read_results('./testFolder/50MB_5OOKB_100files')
read_results_med_med_few <- read_results('./testFolder/50MB_5MB_10files')
read_results_lrg_sml_mny <- read_results('./testFolder/500MB_500KB_1000files')
read_results_lrg_med_mod <- read_results('./testFolder/500MB_5MB_100files')
read_results_lrg_lrg_few <- read_results('./testFolder/500MB_50MB_10files')
read_results_xlg_lrg_mod <- read_results('./testFolder/5000MB_50MB_100files')
print(read_results_sml_mic_mny, digits = 3)
print(read_results_sml_tny_mod, digits = 3)
print(read_results_sml_sml_few, digits = 3)
print(read_results_med_sml_mny, digits = 3)
print(read_results_med_sml_mod, digits = 3)
print(read_results_med_med_few, digits = 3)
print(read_results_lrg_sml_mny, digits = 3)
print(read_results_lrg_med_mod, digits = 3)
print(read_results_lrg_lrg_few, digits = 3)
print(read_results_xlg_lrg_mod, digits = 3)
# display boxplot of my typical use case results & basic machine max load
par(oma = c(0,0,0,0)) # remove overall margins if present
par(mfcol = c(1,1)) # remove grid if present
par(mar = c(12,5,1,1) + 0.1) # to display just a single boxplot with its complete labels
boxplot(read_results_lrg_mid_mid, las = 2, xlab = "", ylab = "Duration (seconds)", main = "40 files @ 12.5MB (500MB)")
boxplot(read_results_xlg_lrg_mod, las = 2, xlab = "", ylab = "Duration (seconds)", main = "100 files @ 50MB (5GB)")
# generate 3x3 grid boxplots
par(oma = c(12,1,1,1)) # margins for the whole 3 x 3 grid plot
par(mfcol = c(3,3)) # create grid (filling down each column)
par(mar = c(1,4,2,1)) # margins for the individual plots in 3 x 3 grid
boxplot(read_results_sml_mic_mny, las = 2, xlab = "", ylab = "Duration (seconds)", main = "1000 files @ 5KB (5MB)", xaxt = 'n')
boxplot(read_results_sml_tny_mod, las = 2, xlab = "", ylab = "Duration (milliseconds)", main = "100 files @ 50KB (5MB)", xaxt = 'n')
boxplot(read_results_sml_sml_few, las = 2, xlab = "", ylab = "Duration (milliseconds)", main = "10 files @ 500KB (5MB)",)
boxplot(read_results_med_sml_mny, las = 2, xlab = "", ylab = "Duration (microseconds) ", main = "1000 files @ 50KB (50MB)", xaxt = 'n')
boxplot(read_results_med_sml_mod, las = 2, xlab = "", ylab = "Duration (microseconds)", main = "100 files @ 500KB (50MB)", xaxt = 'n')
boxplot(read_results_med_med_few, las = 2, xlab = "", ylab = "Duration (seconds)", main = "10 files @ 5MB (50MB)")
boxplot(read_results_lrg_sml_mny, las = 2, xlab = "", ylab = "Duration (seconds)", main = "1000 files @ 500KB (500MB)", xaxt = 'n')
boxplot(read_results_lrg_med_mod, las = 2, xlab = "", ylab = "Duration (seconds)", main = "100 files @ 5MB (500MB)", xaxt = 'n')
boxplot(read_results_lrg_lrg_few, las = 2, xlab = "", ylab = "Duration (seconds)", main = "10 files @ 50MB (500MB)")
Trường hợp sử dụng Middling
Trường hợp sử dụng lớn hơn
Các trường hợp sử dụng
Hàng: số tập tin (1000, 100, 10)
Cột: kích thước khung dữ liệu cuối cùng (5MB, 50MB, 500MB)
(nhấp vào hình ảnh để xem kích thước ban đầu)
Các kết quả cơ sở R tốt hơn cho các trường hợp sử dụng nhỏ nhất trong đó chi phí đưa các thư viện C của purrr và dplyr vượt xa hiệu suất đạt được khi quan sát các tác vụ xử lý quy mô lớn hơn.
nếu bạn muốn chạy thử nghiệm của riêng mình, bạn có thể thấy tập lệnh bash này hữu ích.
for ((i=1; i<=$2; i++)); do
cp "$1" "${1:0:8}_${i}.csv";
done
bash what_you_name_this_script.sh "fileName_you_want_copied" 100
sẽ tạo 100 bản sao tệp của bạn được đánh số liên tục (sau 8 ký tự ban đầu của tên tệp và dấu gạch dưới).
Phân bổ và đánh giá cao
Với lời cảm ơn đặc biệt đến:
- Tyler Rinker và Akrun để chứng minh microbenchmark.
- Jake Kaupp đã giới thiệu tôi đến
map_df()
đây .
- David McLaughlin cho phản hồi hữu ích về việc cải thiện trực quan hóa và thảo luận / xác nhận các nghịch đảo hiệu suất được quan sát trong tệp nhỏ, kết quả phân tích khung dữ liệu nhỏ.
- marbel để chỉ ra hành vi mặc định cho
fread()
. (Tôi cần nghiên cứu về data.table
.)