R/Tidyverse中批量转换Excel日期至POSIXct的间接引用问题
问题:批量转换Excel序列日期为POSIXct格式的函数报错
我有一个包含多列Excel序列日期格式的数据集,用单个mutate操作可以正常将日期转换为POSIXct格式:
myDataSet_wrangled <- myDataSet %>% mutate(startDate = as.POSIXct(as.numeric(startDate) * 3600 * 24, origin = "1899-12-30", tz = "GMT"))
但将逻辑重构为convertXlDateToPOSIXct(df, ...)形式的函数后,传入单个列名可以正常运行,传入多个列名时会报错:Error in 'mutate()': ... ! object 'endDate' not found。
示例代码
myDataSet <- data.frame( startDate = c(44197.924, 44258.363, 44320.634), # Excel格式日期 endDate = c(44201.131, 44270.859, 44330.023) ) convertXlDateToPOSIXct <- function(df, ..., epoch = "1899-12-30", timezone = "GMT") { cols <- enquos(...) df <- df %>% mutate(across(!!!cols, ~ as.POSIXct(as.numeric(.x) * 3600 * 24, origin = epoch, tz = timezone))) return(df) } # 单列调用:正常运行 myDataSet_wrangled <- myDataSet %>% convertXlDateToPOSIXct(startDate) # 多列调用:报错 myDataSet_wrangled <- myDataSet %>% convertXlDateToPOSIXct(startDate, endDate)
问题原因
across()的第一个参数接受的是列选择器(如列名向量、tidyselect语法),而不是通过enquos()生成的quosure对象。原代码中用!!!cols展开多个quosure时,第一个quosure会被当作.cols参数,第二个quosure会被错误地传给across()的第二个参数.fns,导致R试图把endDate当作函数解析,自然找不到该对象。
解决方案
有两种简单的修正方式:
方案1:直接将...传入across()
利用across()支持直接接收多个列名的特性,不需要额外的引用处理:
convertXlDateToPOSIXct <- function(df, ..., epoch = "1899-12-30", timezone = "GMT") { df %>% mutate(across(c(...), ~ as.POSIXct(as.numeric(.x) * 3600 * 24, origin = epoch, tz = timezone))) }
方案2:用ensyms()配合all_of()
如果需要先捕获列名,可使用ensyms()将输入转换为符号向量,再通过all_of()传入across():
convertXlDateToPOSIXct <- function(df, ..., epoch = "1899-12-30", timezone = "GMT") { cols <- ensyms(...) df %>% mutate(across(all_of(cols), ~ as.POSIXct(as.numeric(.x) * 3600 * 24, origin = epoch, tz = timezone))) }
测试验证
修正后的函数无论是单列还是多列调用都能正常运行:
# 单列转换 myDataSet_wrangled1 <- myDataSet %>% convertXlDateToPOSIXct(startDate) # 多列转换 myDataSet_wrangled2 <- myDataSet %>% convertXlDateToPOSIXct(startDate, endDate)
内容的提问来源于stack exchange,提问作者Panko
相关产品推荐
相关产品推荐

