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

如何在data.table的.SD调用中获取列名并实现文本追加

在data.table的.SD中获取列名并批量处理单元格内容

需求:为表格中包含字符"a"的单元格追加后缀" by {列名}",其中{列名}是该单元格所在列的原始变量名,需对所有列执行此操作。

输入表格

library(data.table)
# Input 
ip <- data.table(x = c("ab", "cd", "ac", "de"),
                 y = c("fr", "ad", "fa", "we"))

ip[]
#>     x  y
#> 1: ab fr
#> 2: cd ad
#> 3: ac fa
#> 4: de we

期望输出

# Desired Output table
op <- data.table(x = c("ab by x", "cd", "ac by x", "de"),
                 y = c("fr", "ad by y", "fa by y", "we"))
op[]
#>          x       y
#> 1: ab by x      fr
#> 2:      cd ad by y
#> 3: ac by x fa by y
#> 4:      de      we

尝试过的方法及问题

最初尝试用deparse(substitute(x))获取列名,单独调用函数时正常:

add_if_pattern <- function(x, pattern) {
  y <- deparse(substitute(x))
  fifelse(test = grepl(pattern, x),
          paste(x, "by",  y),
          x)
}

pattern <- "a"
z <- "blah"
q <- "bleh"
add_if_pattern(z, pattern) ## 符合预期
#> [1] "blah by z"
add_if_pattern(q, pattern) ## 符合预期
#> [1] "bleh"

但将该函数放入lapply(.SD)中执行时,得到的是X[[i]]而非原始列名:

tp <- copy(ip)
ip <- copy(tp)

vars <- names(ip)
ip[, (vars) := lapply(.SD,add_if_pattern, pattern)]
ip[]
#>               x            y
#> 1: ab by X[[i]]           fr
#> 2:           cd ad by X[[i]]
#> 3: ac by X[[i]] fa by X[[i]]
#> 4:           de           we

尝试用names(.SD)获取列名时,因作用域和参数含义错误报错:

ip <- copy(tp)
ip[, (vars) := lapply(.SD,
                      \(x){
                        fifelse(test = grepl("classified", x),
                                paste(x, "by",  names(.SD)[..x]),
                                x)
                      })]
#> Error in `[.data.table`(ip, , `:=`((vars), lapply(.SD, function(x) {: Variable 'x' is not found in calling scope. Looking in calling scope because this symbol was prefixed with .. in the j= parameter.

解决方案

方法1:使用Map同时遍历列值与列名

Map可以同时传入列值(.SD)和对应的列名(names(.SD)),这样就能在函数中直接拿到当前列的名称:

ip <- copy(tp)
pattern <- "a"
ip[, (vars) := Map(function(col_val, col_name) {
  fifelse(grepl(pattern, col_val), paste(col_val, "by", col_name), col_val)
}, .SD, names(.SD))]
ip[]

方法2:遍历列索引获取列名

通过seq_along(.SD)遍历列的索引,再通过索引从.SD中取列值、从names(.SD)中取列名:

ip <- copy(tp)
ip[, (vars) := lapply(seq_along(.SD), function(i) {
  col_val <- .SD[[i]]
  col_name <- names(.SD)[i]
  fifelse(grepl(pattern, col_val), paste(col_val, "by", col_name), col_val)
})]
ip[]

问题原因解释

  • deparse(substitute(x))在lapply(.SD)中时,x代表的是.SD中的元素,内部表现为X[[i]],因此解析后得到的是这个字符串而非原始列名。
  • 第二种报错是因为x是列的单元格值,不是列的索引,用names(.SD)[..x]试图通过值取列名逻辑错误,且..前缀用于引用上层作用域的变量,这里使用场景不对。

内容的提问来源于stack exchange,提问作者R.Andres Castaneda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:24:40