如何在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
相关产品推荐
相关产品推荐

