带有sprintf的R data.table列通配符

时间:2017-01-22 10:17:04

标签: r data.table

给定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语法。

2 个答案:

答案 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)

另一种选择是使用Reducepaste0

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 / sprintfdo.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