我的问题是:
将大型(ish).xlsx Excel文件读入R最快的方法是什么? 10到200 MB的xlsx文件,有多张纸。
是否可以使用某种并行处理,例如每个核心阅读 多页Excel文件的另一页?
还有其他可以执行的优化吗?
到目前为止,我所了解的(以及我尚未了解的):
readxl
往往比openxlsx
快我只对表格数据感兴趣;我对Excel格式,图表,文本标签或任何其他类型的数据都不感兴趣。
我可能希望导入tidyverse拼写,但不一定。然后,我需要将表导出到Microsoft SQL Server中。
某些背景:我主要使用Python,并且对R完全陌生。用Python读取大型Excel文件非常缓慢。我已经看到R的readxl
比Python快得多pandas
(在15页xlsx上,每页有10,000行32列:readxl 5.6秒,熊猫33秒),太好了!但是,我仍然想了解是否有任何方法可以使导入速度更快。我可以使用R读取文件,将其导出到SQL,然后使用从SQL读取Python继续我的工作流程的其余部分。
我认为转换为CSV并不是最好的选择,尤其是当readxl仍然比Python快得多时;基本上转换为csv所需的时间可能比我从csv读取而不是excel节省的时间要长。另外,至少对于Python(我不太了解R是否足以使用readxl对其进行全面测试)而言,使用xlsx推断数据类型要比使用csv更好。
我的代码(欢迎提出任何批评或建议)
library(readxl)
library(tidyverse)
library(tictoc)
this.dir <- dirname(parent.frame(2)$ofile)
setwd(this.dir)
tic("readxl")
path <- "myfile.xlsx"
sheetnames <- excel_sheets(path)
mylist <- lapply(excel_sheets(path), read_excel, path = path)
names(mylist) <- sheetnames
toc()
答案 0 :(得分:4)
您可以尝试使用parallel
软件包并行运行它,但是要估算没有样本数据的速度将有些困难:
library(parallel)
library(readxl)
excel_path <- ""
sheets <- excel_sheets(excel_path)
创建具有指定核心数的集群:
cl <- makeCluster(detectCores() - 1)
使用parLapplyLB
浏览excel表格并使用负载平衡并行读取它们:
parLapplyLB(cl, sheets, function(sheet, excel_path) {
readxl::read_excel(excel_path, sheet = sheet)
}, excel_path)
您可以使用软件包microbenchmark
测试某些选项的运行速度:
library(microbenchmark)
microbenchmark(
lapply = {lapply(sheets, function(sheet) {
read_excel(excel_path, sheet = sheet)
})},
parralel = {parLapplyLB(cl, sheets, function(sheet, excel_path) {
readxl::read_excel(excel_path, sheet = sheet)
}, excel_path)},
times = 10
)
就我而言,并行版本更快:
Unit: milliseconds
expr min lq mean median uq max neval
lapply 133.44857 167.61801 179.0888 179.84616 194.35048 226.6890 10
parralel 58.94018 64.96452 118.5969 71.42688 80.48588 316.9914 10
测试文件包含6张纸,每张纸都包含此表:
test test1 test3 test4 test5
1 1 1 1 1 1
2 2 2 2 2 2
3 3 3 3 3 3
4 4 4 4 4 4
5 5 5 5 5 5
6 6 6 6 6 6
7 7 7 7 7 7
8 8 8 8 8 8
9 9 9 9 9 9
10 10 10 10 10 10
11 11 11 11 11 11
12 12 12 12 12 12
13 13 13 13 13 13
14 14 14 14 14 14
15 15 15 15 15 15
注意:
您可以在过程完成后使用stopCluster(cl)
关闭工作程序。
答案 1 :(得分:1)
我看到了@clemens的回答,但是由于我已经准备了一些东西,所以无论如何我都将其发布。除了@clemens答案以外,我使用更大的测试数据,并使用furrr::future_map()
运行更简单的多核选项,这最终并不会带来任何性能提升...
这将创建10张10000 * 15数据,其中包含浮点数,整数和字符。在我的磁盘上,文件大小为13.2MB。
library(writexl)
library(tidyverse)
n <- 1e4
sample_data <- map(seq(10), function(x) {
sample_data <-
map(1:5, function(x){
data_frame(
num_var = rnorm(n),
int_var = as.integer(sample(1e5:9e5, n, replace = T)),
char_var = sample(letters, n, replace = T)
) %>% rename_all(funs(paste0(., x)))
}) %>% bind_cols()
return(sample_data)
})
fn <- tempfile(tmpdir = "~/Desktop/temp",fileext = ".xlsx")
write_xlsx(sample_data, path = fn)
parallel
部分是从@clemens借来的。
library(parallel)
library(readxl)
sheets <- excel_sheets(fn)
cl <- makeCluster(detectCores() - 1)
excel_path <- fn
microbenchmark::microbenchmark(
map = map(sheets, function(x) read_xlsx(fn, sheet = x)) ,
future_map = furrr::future_map(sheets, function(x) read_xlsx(fn, sheet = x)),
parLapplyLB = {parLapplyLB(cl, sheets, function(sheet, excel_path) {
readxl::read_xlsx(excel_path, sheet = sheet)
}, excel_path)},
times = 10
)
基准测试结果如下:
Unit: milliseconds
expr min lq mean median uq max neval
map 1258.2643 1272.2354 1351.8371 1291.2474 1430.211 1556.992 10
future_map 1276.4125 1302.2022 1469.8349 1436.5356 1616.146 1702.494 10
parLapplyLB 809.2697 863.3299 951.1041 914.9503 1014.907 1189.897 10
我的CPU相对较弱,因此在其他环境中获得的收益一定很大,但是最后,编写SQL部分可能会成为瓶颈,因为对于read_xlsx
而言,读取速度确实非常快。
我还尝试了其他软件包,例如gdata
和xlsx
。这些过程非常缓慢,因此不值得考虑。