我正在尝试创建一个函数,该函数使用readxl::read_excel
读取excel工作簿中的所有工作表并将其绑定到单个数据框中,并允许我将其他参数传递给{{1} } 。我可以将第一部分做得很好,但不能做第二部分。
read_excel
我应该找回一个文件,相反,我得到一个错误:
library(magrittr)
# example excel workbook with multiple sheets
path <- readxl::readxl_example("datasets.xlsx")
# function with simple forwarding
read_all <- function(path, ...) {
path %>%
readxl::excel_sheets() %>%
rlang::set_names() %>%
purrr::map_df(~ readxl::read_excel(path = path, sheet = .x, ...))
}
# errors with and without additional arguments
read_all(path)
read_all(path, skip = 5)
Error: Can't guess format of this cell reference: iris
In addition: Warning message: Cell reference follows neither the A1 nor R1C1 format. Example: iris NAs generated.
# Function works without passing extra params
read_all_0 <- function(path) {
path %>%
readxl::excel_sheets() %>%
rlang::set_names() %>%
purrr::map_df(~ readxl::read_excel(path = path, sheet = .x))
}
read_all_0(path)
的简单函数中,参数传递可以正常工作purrr::map_df
答案 0 :(得分:2)
我遇到了类似的问题:在完全不同的上下文中(不使用函数且不使用省略号),通过map
传递错误的参数,以供参考,请参见{{3 }}。
然后的解决方案是创建一个仅使用一个参数的命名函数,并将其传递给recode_df
,以便唯一的参数是您要遍历的向量/列表。
适用于您的问题的解决方案如下所示:
map
似乎此问题源于对# function with forwarding
read_all <- function(path, ...) {
# function within function that sets the arguments path and ellipsis as given and only leaves sheet to be determined
read_xl <- function(sheet) {
readxl::read_excel(path = path, sheet, ...)
}
path %>%
readxl::excel_sheets() %>%
rlang::set_names() %>%
purrr::map_df(read_xl)
}
# this allows you to pass along arguments in the ellipsis correctly
read_all(path)
read_all(path, col_names = FALSE)
函数的不正确的环境处理。为了避免这种情况,我建议在注释中使用匿名函数。显然,下面的方法也可以。
purrr::as_mapper
要验证实际上是导致问题的read_all <- function(path, ...) {
path %>%
readxl::excel_sheets() %>%
rlang::set_names() %>%
purrr::map_df(function(x) {
readxl::read_excel(path = path, sheet = x, ...)
})
}
函数,我们可以使用as_mapper
从上面重写命名的函数中函数。在省略号中带有或不带有其他参数的情况下,都会再次产生错误。
as_mapper
更新
知道# function with forwarding
read_all <- function(path, ...) {
# named mapper function
read_xl <- purrr::as_mapper(~ readxl::read_excel(path = path, sheet = .x, ...))
path %>%
readxl::excel_sheets() %>%
rlang::set_names() %>%
purrr::map_df(read_xl)
}
会导致问题,使我们可以更深入地研究问题。现在,我们可以在RStudio调试器中检查运行简单的as_mapper
映射器版本时幕后情况:
read_excel
似乎在映射器函数中包含省略号时,read_xl <- purrr::as_mapper(~ readxl::read_excel(path = .x, sheet = .y, ...))
debugonce(read_xl)
read_xl(path, 1)
不仅将第一个参数映射到as_mapper
,而且还自动将其映射到省略号.x
。我们可以通过创建一个简单的映射器函数...
并使用两个参数paster
和.x
来验证这一点。
...
现在的问题是:我们应该在映射器函数中使用省略号还是另一种错误?
答案 1 :(得分:0)
我认为以下方法会起作用:
read_all <- function(path, ...) {
path %>%
readxl::excel_sheets() %>%
purrr::set_names() %>%
map_df(~readxl::read_excel(path=path, sheet=.x), ...)
}
因为map
系列具有一个...
参数,用于将其他参数传递给映射函数。但是,以下代码将忽略n_max
参数,并仍然返回各种数据帧的所有行,而不是具有8行(每四张纸中的每两行)的数据帧:
p <- readxl_example("datasets.xlsx")
read_all(p, n_max=2)
但是,这可行:
read_all <- function(path, ...) {
path %>%
excel_sheets() %>%
set_names() %>%
map_df(read_excel, path=path, ...)
}
p <- readxl_example("datasets.xlsx")
read_all(path=p, n_max=2)
在上面,path
和...
中的任何其他参数都传递给read_excel
和(显然)工作表名称(如果我们使用.x
它显式地)隐式传递给sheet
参数,我想是因为已经提供了第一个path
参数。我真的不明白这一点,而且这似乎不是一种特别透明的方法,但是我认为我应该把它放在这里,以防其他人可以解释正在发生的事情并提供更好的代码。