假设我有一个数据表。
# Load package
library(data.table)
# Dummy data table
dt <- data.table(foo = letters[1:10],
bar = LETTERS[11:20],
val = 100:109)
我想对此数据表的一列运行一个函数,该函数返回包含多个列的数据表。假设它看起来像这样:
# Function that returns data table
f <- function(x){
data.table(stuff = paste0(x, "_stuff"),
things = paste0("things_", x))
}
如果我在数据表中的 foo
上运行它,它会返回:
# Returns only columns from function
dt[, f(foo)]
#> stuff things
#> 1: a_stuff things_a
#> 2: b_stuff things_b
#> 3: c_stuff things_c
#> 4: d_stuff things_d
#> 5: e_stuff things_e
#> 6: f_stuff things_f
#> 7: g_stuff things_g
#> 8: h_stuff things_h
#> 9: i_stuff things_i
#> 10: j_stuff things_j
太棒了!现在,我希望将返回的数据表附加到我的原始数据表中。如果我想将其附加到原始数据表中的几列,我可以像这样命名我想要保留的列:
# Returns named column and columns from function
dt[, .(foo, f(foo))]
#> foo stuff things
#> 1: a a_stuff things_a
#> 2: b b_stuff things_b
#> 3: c c_stuff things_c
#> 4: d d_stuff things_d
#> 5: e e_stuff things_e
#> 6: f f_stuff things_f
#> 7: g g_stuff things_g
#> 8: h h_stuff things_h
#> 9: i i_stuff things_i
#> 10: j j_stuff things_j
但是,我想保留所有列,而不必单独命名它们。一种方法是使用 by
:
# Retains all columns
dt[, f(foo), by = names(dt)]
#> foo bar val stuff things
#> 1: a K 100 a_stuff things_a
#> 2: b L 101 b_stuff things_b
#> 3: c M 102 c_stuff things_c
#> 4: d N 103 d_stuff things_d
#> 5: e O 104 e_stuff things_e
#> 6: f P 105 f_stuff things_f
#> 7: g Q 106 g_stuff things_g
#> 8: h R 107 h_stuff things_h
#> 9: i S 108 i_stuff things_i
#> 10: j T 109 j_stuff things_j
由reprex package于2020年2月18日创建(v0.3.0)
这为我提供了此测试用例所需的结果,但显然这仅在行是唯一的情况下才有意义。
我尝试使用类似 dt[, .(names(dt), f(foo))]
的内容,但这不能用作 names
返回一个字符串向量,然后将其添加为一列。
显而易见的解决方案是使用 :=
,如下所示:dt[, c("One", "Two") := f(foo)]
。这给出了所需的结果但是我必须自己命名添加的列,而我想保留函数返回的列名称。
另一个解决方案可能是cbind(dt, dt[, foo(f)])
,但这看起来很笨拙。
达到这个结果的正确方法是什么?
最佳答案
一些建议:
1)修改函数中的data.table
:
f2 <- function(dt){
cols <- c("stuff", "things")
dt[, (cols) := lapply(paste0("_", cols), function(x) paste0(foo, x))]
}
f2(dt)
2)使用 NSE:
eval(substitute(dt[, (LHS) := RHS], list(RHS={a <- dt[, f(foo)]}, LHS=names(a))))
3)或者将结果分配给变量,然后通过引用进行更新,类似于Gainz在评论中提到的
a <- dt[, f(foo)]
dt[, names(a) := a]
我更喜欢选项 (3)。
关于应用返回多列数据表的函数时,保留原始数据表中的所有列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60287102/