tidyverse
โซลูชันที่รวดเร็วและรวบรัด: (เร็วกว่าสองเท่าของBase R read.csv
)
tbl <-
list.files(pattern = "*.csv") %>%
map_df(~read_csv(.))
และdata.table 's fread()
ยังสามารถตัดเวลาในการโหลดเหล่านั้นโดยครึ่งหนึ่งอีกครั้ง (สำหรับ 1/4 ฐาน Rครั้ง)
library(data.table)
tbl_fread <-
list.files(pattern = "*.csv") %>%
map_df(~fread(.))
stringsAsFactors = FALSE
อาร์กิวเมนต์ช่วยให้ฟรีปัจจัย dataframe (และเป็นจุดเบญจมบพิตรออกเป็นค่าเริ่มต้นสำหรับfread
)
หาก typecasting หน้าด้านคุณสามารถบังคับคอลัมน์ทั้งหมดให้เป็นตัวละครที่มีcol_types
อาร์กิวเมนต์
tbl <-
list.files(pattern = "*.csv") %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
หากคุณต้องการที่จะจุ่มลงในไดเรกทอรีย่อยเพื่อสร้างรายการของไฟล์ที่จะผูกในที่สุดให้แน่ใจว่าได้รวมชื่อพา ธ เช่นเดียวกับการลงทะเบียนไฟล์ที่มีชื่อเต็มของพวกเขาในรายการของคุณ สิ่งนี้จะช่วยให้การเชื่อมโยงทำงานนอกไดเรกทอรีปัจจุบัน (การพิจารณาชื่อพา ธ แบบเต็มว่าทำงานเหมือนกับหนังสือเดินทางเพื่อให้การเคลื่อนที่ย้อนกลับข้าม 'ขอบเขต' ของไดเรกทอรี)
tbl <-
list.files(path = "./subdirectory/",
pattern = "*.csv",
full.names = T) %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
ดังที่ Hadley อธิบายไว้ที่นี่ (ประมาณครึ่งทาง):
map_df(x, f)
มีประสิทธิภาพเหมือนกับdo.call("rbind", lapply(x, f))
....
คุณสมบัติโบนัส - การเพิ่มชื่อไฟล์ลงในระเบียนต่อคำขอคุณสมบัติ Niks ในความคิดเห็นด้านล่าง:
* เพิ่มต้นฉบับfilename
ไปยังแต่ละระเบียน
รหัสอธิบาย: ทำให้ฟังก์ชั่นเพื่อผนวกชื่อไฟล์ไปยังแต่ละระเบียนในระหว่างการอ่านเริ่มต้นของตาราง จากนั้นใช้ฟังก์ชั่นนั้นแทนread_csv()
ฟังก์ชั่นพื้นฐาน
read_plus <- function(flnm) {
read_csv(flnm) %>%
mutate(filename = flnm)
}
tbl_with_sources <-
list.files(pattern = "*.csv",
full.names = T) %>%
map_df(~read_plus(.))
(แนวทางการจัดการ typecasting และไดเรกทอรีย่อยยังสามารถจัดการภายในread_plus()
ฟังก์ชันในลักษณะเดียวกับที่แสดงในตัวแปรที่สองและสามที่แนะนำข้างต้น)
### 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)")
Middling กรณีการใช้งาน
กรณีใช้งานที่ใหญ่ขึ้น
กรณีการใช้ที่หลากหลาย
แถว: นับจำนวนไฟล์ (1,000, 100, 10)
คอลัมน์: ขนาดดาต้าเฟรมสุดท้าย (5MB, 50MB, 500MB)
(คลิกที่ภาพเพื่อดูขนาดดั้งเดิม)
ผลลัพธ์ฐาน R นั้นดีกว่าสำหรับกรณีการใช้งานที่น้อยที่สุดซึ่งค่าใช้จ่ายในการนำไลบรารี C ของ purrr และ dplyr เพื่อแบกรับผลการดำเนินงานที่เกินดุลที่สังเกตได้เมื่อดำเนินการประมวลผลขนาดใหญ่
หากคุณต้องการทำการทดสอบของคุณเองคุณอาจพบว่าสคริปต์ทุบตีนี้มีประโยชน์
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
จะสร้าง 100 ไฟล์ของคุณตามลำดับหมายเลข (หลังจาก 8 ตัวอักษรเริ่มต้นของชื่อไฟล์และขีดล่าง)
คุณสมบัติและชื่นชม
ขอขอบคุณเป็นพิเศษกับ:
- Tyler RinkerและAkrunสำหรับแสดงให้เห็นถึง microbenchmark
- เจค Kaupp สำหรับการแนะนำฉันไปที่นี่
map_df()
- David McLaughlin สำหรับข้อเสนอแนะที่เป็นประโยชน์ในการปรับปรุงการสร้างภาพข้อมูลและการอภิปราย / ยืนยันการรุกรานประสิทธิภาพที่พบในไฟล์ขนาดเล็กผลการวิเคราะห์ดาต้าเฟรมขนาดเล็ก
fread()
เบญจมบพิตรสำหรับการชี้ให้เห็นพฤติกรรมเริ่มต้นสำหรับ (ฉันต้องศึกษาต่อdata.table
)