You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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)

问题原因

  1. group_map的参数传递机制:group_map会将额外参数按字面量传递给回调函数,而非在dplyr的tidy eval上下文解析。当你传入date和close时,它们被识别为全局环境中的函数(base R的date()、dplyr的close()),而非数据框的列名符号,导致{{}}无法正确解析为目标列。
  2. 函数内部变量错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:45:46