给定data.table
具有任意数量的列
dt = data.table( a = letters[1:5], b = rep('-', 5), c = LETTERS[1:5] )
# a b c
# 1: a - A
# 2: b - B
# 3: c - C
# 4: d - D
# 5: e - E
和一个任意format
字符串,其中包含多个与列数相对应的占位符
format = '%s0%s1%s'
如何在未明确调用所有列名的情况下应用sprintf
?
只是提供data.table
将无效,因为sprintf
在这种情况下需要3个参数。调用sprintf(format, dt$a, dt$b, dt$b)
是不可取的,因为我事先既不知道format
也不知道data.table
。
行索引上的sapply
也不起作用,因为操作必须在保留其顺序的行子集上完成。
idx = seq( 1, by = 2, to = 5 )
所以目标是通过发出假设命令
dt[ idx, sprintf( format, * )]
实现这个
# [1] "a0-1A" "c0-1C" "e0-1E"
可以通过调用
来完成cols = paste( names( dt ) ), collapse=',' )
# "a,b,c"
eval( parse( text = sprintf( 'dt[ idx, sprintf( format,%s )]', cols ) ) )
# [1] "a0-1A" "c0-1C" "e0-1E"
但这是相当神秘且绝对不干净的代码,如果data.table
包本身有更多的语义方式,那就太好了。
所以问题基本上是否存在。直到现在谷歌和data.table
手册都没有给我一个答案。
此外,我既不想paste
一些/多列,但我想使用所有列而不是我正在寻找通过使用data.frame
实现此目的的方法。我正在寻找流畅的data.table
语法。
答案 0 :(得分:6)
我们可以通过在ds_Subject.Tables("iswe").Rows(0).Item(2).Delete()
sprintf
作为参数来实现此目的
do.call
如果我们需要在' dt'中创建一个列,请指定(dt[, do.call(sprintf, c(.SD, fmt = format))]
#[1] "a-A" "b-B" "c-C" "d-D" "e-E"
)它以创建新列
:=
我们也可以将dt[, newCol := do.call(sprintf, c(.SD, fmt = format))]
与paste
do.call
答案 1 :(得分:1)
另一种选择是使用Reduce
和paste0
:
dt[, abc := Reduce(paste0, .SD)]
给出:
a b c abc
1: a - A a-A
2: b - B b-B
3: c - C c-C
4: d - D d-D
5: e - E e-E
在大型数据集上,这比do.call
/ sprintf
或do.call
/ paste0
方法慢一点:
akrun1 <- dt[sample.int(5, 1e6, TRUE)]
akrun2 <- copy(akrun)
jaap <- copy(akrun)
> system.time(akrun1[, newCol := do.call(sprintf, c(.SD, fmt = format))])
user system elapsed
0.280 0.002 0.282
> system.time(akrun2[, newCol := do.call(paste0, .SD)])
user system elapsed
0.187 0.001 0.188
> system.time(jaap[, abc := Reduce(paste0, .SD)])
user system elapsed
0.325 0.002 0.327