在dplyr的group_map中使用defuse-inject模式失败的问题排查
问题:dplyr group_map中使用defuse-inject模式失败
场景复现
我在尝试用dplyr的group_map函数结合defuse-inject(拥抱操作符{{}})模式将分组数据转换为xts对象时遭遇失败,以下是完整代码及报错信息:
library(dplyr) library(tidyquant) library(xts) tbl.data <- tidyquant::tq_get(c("GS", "C", "BAC")) to.xts <- function(group, group_key, date_col, price_col){ a <- group %>% dplyr::pull({{ price_col }}) b <- group %>% dplyr::pull({{ date_col }}) x <- xts::xts(a, order.by=b) colnames(x) <- key$symbol # 此处存在变量名错误 x } make.xts <- function(data, date_col, price_col){ data %>% group_by(symbol) %>% group_map(~to.xts(.x, .y, date_col, price_col)) } # 失败示例一: tbl.data %>% group_by(symbol) %>% group_map(to.xts, date, close) # 失败示例二: make.xts(tbl.data, date, close)
报错信息
Error in `dplyr::pull()`: ! Can't extract column with `!!enquo(var)`. ✖ `!!enquo(var)` must be numeric or character, not a function. Run `rlang::last_error()` to see where the error occurred.
正常运行的对比案例
单独提取分组调用to.xts可正常执行:
gs.grp <- tbl.data %>% dplyr::filter(symbol=="GS") gs.grp %>% to.xts("GS", date, close) # 单独pull操作也正常: gs.grp %>% dplyr::pull(close)
问题原因
group_map的参数传递机制:group_map会将额外参数按字面量传递给回调函数,而非在dplyr的tidy eval上下文解析。当你传入date和close时,它们被识别为全局环境中的函数(base R的date()、dplyr的close()),而非数据框的列名符号,导致{{}}无法正确解析为目标列。- 函数内部变量错误:
to.xts中colnames(x) <- key$symbol的key未定义,应该使用参数group_key。
解决方案
方案1:保留tidy eval,用匿名函数传递参数
在group_map中用匿名函数包裹调用,确保参数在原数据的tidy eval上下文中被解析:
# 修复to.xts函数的变量错误 to.xts <- function(group, group_key, date_col, price_col){ a <- group %>% dplyr::pull({{ price_col }}) b <- group %>% dplyr::pull({{ date_col }}) x <- xts::xts(a, order.by=b) colnames(x) <- group_key$symbol x } # 修复失败示例一 tbl.data %>% group_by(symbol) %>% group_map(~to.xts(.x, .y, {{ date }}, {{ close }})) # 修复失败示例二 make.xts <- function(data, date_col, price_col){ data %>% group_by(symbol) %>% group_map(~to.xts(.x, .y, {{ date_col }}, {{ price_col }})) } make.xts(tbl.data, date, close)
方案2:改用字符串传递列名(非tidy eval方式)
直接传递列名字符串,pull可直接接收字符串参数:
to.xts <- function(group, group_key, date_col, price_col){ a <- group %>% dplyr::pull(price_col) b <- group %>% dplyr::pull(date_col) x <- xts::xts(a, order.by=b) colnames(x) <- group_key$symbol x } # 调用时传递字符串列名 tbl.data %>% group_by(symbol) %>% group_map(to.xts, "date", "close") make.xts <- function(data, date_col, price_col){ data %>% group_by(symbol) %>% group_map(to.xts, date_col, price_col) } make.xts(tbl.data, "date", "close")
内容的提问来源于stack exchange,提问作者stucash
相关产品推荐
相关产品推荐

