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

在R data.table中创建参数化函数时遇错误的解决方法

参数化实现data.table文本列数字翻倍

需求背景

需要编写一个参数化函数,实现对data.table指定列中的数字提取后翻倍,再将翻倍后的数字替换回原文本的逻辑。原始逻辑代码如下:

dt <- data.table(  text = c("AAA 123 BBB", "1 CCC")
                 , text2 = c("AAA 123 BBB", "1 CCC"))

double_number <- function(x) x*2
regex_identify_num <- "\\d+" 

# 提取数字、翻倍、替换回原文本
dt[, calc_value := text |> str_extract(regex_identify_num) |> as.numeric() |> double_number()]
dt[, text := mapply(function(x,y) gsub(regex_identify_num, x, y, perl = T), calc_value, text)]
dt[, calc_value:=NULL]

预期结果:指定列中的数字翻倍,例如"AAA 123 BBB"变为"AAA 246 BBB","1 CCC"变为"2 CCC"。

问题现象

尝试编写参数化函数时遇到错误:

第一次尝试代码

change_value <- function(dt_, fun, regex, column_name) {
  dt_[, new_column := get(column_name) |> str_extract(get(regex)) |> fun()]
  dt_[, column_name := mapply(function(x, y) gsub(get(regex), x, y, perl = T), new_column, get(column_name))]
  dt_[, new_column := NULL]
  return(dt)
}

change_value(dt, function(x) x |> as.numeric() |> double_number(), "regex_identify_num", "text") 

报错信息:

Error in get(column_name) : first argument has length > 1

调试发现get(column_name) |> str_extract(get(regex)) |> fun()计算结果正确,但赋值列名和mapply中的变量作用域存在问题。

第二次尝试代码(NSE方式)

change_value <- function(dt_, fun, regex, column_name) {
  dt_[, new_column:= column_name |> str_extract(regex) |> fun()
      , env = list(  fun = substitute(fun)
                   , column_name = substitute(column_name)
                   , regex = substitute(regex)
                   )
      ]
  dt_[, column_name := mapply(function(x, y) gsub(regex, x, y, perl = T), new_column, column_name)]
  dt_[, new_column := NULL]
  return(dt)
}

同样未成功执行。

修复方案

方案1:修正字符串列名赋值与变量作用域

change_value <- function(dt_, fun, regex, column_name) {
  # 计算翻倍后的值,直接使用函数参数regex,无需get
  dt_[, new_column := get(column_name) |> str_extract(regex) |> fun()]
  # 用(column_name)实现字符串列名的赋值,同时将regex传入匿名函数
  dt_[, (column_name) := mapply(function(x, y, r) gsub(r, x, y, perl = TRUE), 
                               new_column, get(column_name), MoreArgs = list(r = regex))]
  # 删除临时列
  dt_[, new_column := NULL]
  return(dt_)
}

# 调用示例
dt <- data.table(  text = c("AAA 123 BBB", "1 CCC")
                 , text2 = c("AAA 123 BBB", "1 CCC"))
double_number <- function(x) x*2
regex_identify_num <- "\\d+" 

change_value(dt, function(x) x |> as.numeric() |> double_number(), regex_identify_num, "text")

关键修复点:

  • 赋值列名时使用(column_name),让data.table将字符串参数识别为列名,而非字面量。
  • mapply通过MoreArgs传入regex,避免匿名函数中get(regex)的作用域错误。

方案2:使用data.table非标准求值(NSE)风格

change_value <- function(dt_, fun, regex, column_name) {
  # 捕获传入的表达式
  col_sym <- substitute(column_name)
  fun_expr <- substitute(fun)
  regex_expr <- substitute(regex)
  
  # 计算临时列,用eval在data.table环境中解析列名和正则
  dt_[, new_column := do.call("|>", list(
    do.call("|>", list(str_extract(eval(col_sym), eval(regex_expr)), as.numeric)),
    fun_expr
  ))]
  
  # 替换原列,同样用eval处理列名
  dt_[, (col_sym) := mapply(function(x, y, r) gsub(r, x, y, perl = TRUE), 
                           new_column, eval(col_sym), MoreArgs = list(r = eval(regex_expr)))]
  
  dt_[, new_column := NULL]
  return(dt_)
}

# 调用时可直接传列名(无需加引号)
change_value(dt, function(x) x*2, regex_identify_num, text)

关键修复点:

  • 使用substitute捕获传入的列名、函数、正则表达式的表达式。
  • 通过eval在data.table的计算环境中解析这些表达式,符合data.table的NSE编程习惯。

内容的提问来源于stack exchange,提问作者Fabio Correa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:17:29