【问题标题】:Using := multiple times in data.table在 data.table 中多次使用 :=
【发布时间】:2017-04-22 18:08:48
【问题描述】:

我经常发现自己在同一个数据表上使用:= 进行一系列链式计算。比如这样的

test = data.table(1:10, 1:10, 1:10, 1:10)

test[, V1 := V1^2]
test[, V2 := V1*V2]
test[, V3 := V2/V3]
test[, V4 := sqrt(V3)]
test[, new := letters[V4]]

必须在每一行写test[, ...] 1) 需要更长的时间来输入(这不是我能应付的大问题)。但是,更重要的是,这也会在视觉上分散计算的流程和内容。我宁愿写类似的东西

test[, {
  V1 := V1^2
  V2 := V1*V2
  V3 := V2/V3
  V4 := sqrt(V3)
  new := letters[V4]
}]

但这会引发You have wrapped := with {} which is ok but then := must be the only thing inside {} 的错误。

我知道我会写

within(test, {
  V1 = V1^2
  V2 = V1*V2
  V3 = V2/V3
  V4 = sqrt(V3)
  new = letters[V4]
  })

但这失去了使用:=的效率

我尝试编写一个函数来提供这种能力

with.dt = function(dt, expressions){
  e = strsplit(expressions,'\n')
  for (i in 1:length(e)){    
    dt[, eval(parse(text = e[i]))]
  }
  dt
  }

with.dt(test, "
  V1 := V1^2;
  V2 := V1*V2;
  V3 := V2/V3;
  V4 := sqrt(V3);
  new := letters[V4];
  ")

但这不会改变data.table的内容

是否有任何语法允许within 版本的整洁外观,同时保留:= 的引用分配属性?

【问题讨论】:

  • 如果您不需要按顺序完成它们,您可以执行以下操作:test[,:=(v1 = v1^2, v2 = v1*v2)] := 周围应该有反引号
  • 扩展 Kristoferson 所说的内容,我认为您可以使用 DT[, `:=`(V1 = V1 <- 10, V2 = V2 <- V1^2, ...)] 之类的 hack 按顺序进行操作
  • @Frank 感谢您的建议。我使用with.dt 的函数定义再次尝试更新了 q。知道为什么这不起作用吗?
  • @clemlaflemme data.table 和:= 的特点之一是通过引用修改对象,因此您无需重新分配结果。
  • @Kristofersen 我花了很长时间才意识到这一点,但是您可以通过反斜杠在内联代码块中转义 cmets 中的反引号:\` 将保持原样:`:=`

标签: r data.table colon-equals


【解决方案1】:

有几种不同的方法可以做到这一点。

这里使用的原始测试矩阵:

   v1 v2
1:  1  3
2:  2  4

首先,我们可以这样做:

test[,`:=`(v1 = v1^2,
          v2 = v1*v2)

输出:

v1 v2
 1  3
 4  8

或者,如果我们希望它按顺序完成,我们可以使用 Frank 的技巧。

test[, `:=`(v1 = v1 <- v1^2, v2 = v2 * v1)]

输出:

v1 v2
 1  3
 4 16  

或者,类似地我们可以运行这个:

test[,c("v1","v2") := list(v1^2,v1^2*v2)]

输出:

v1 v2
 1  3
 4 16

【讨论】:

  • test[, v1 := v1^2][, v2 := v2*v1]
【解决方案2】:

我们可以使用一个接受表达式列表的函数:

with.dt = function(dt, expr){
  for (j in 1:length(expr)) set(dt, , names(expr)[j], dt[, eval(expr[[j]])])
}

test = data.table(1:10, 1:10, 1:10, 1:10)
with.dt(test, expression(
  V1 = V1^2,
  V2 = V1*V2,
  V3 = V2/V3,
  V4 = sqrt(V3),
  new = letters[V4]
))

#     V1   V2  V3 V4 new
# 1:   1    1   1  1   a
# 2:   4    8   4  2   b
# 3:   9   27   9  3   c
# 4:  16   64  16  4   d
# 5:  25  125  25  5   e
# 6:  36  216  36  6   f
# 7:  49  343  49  7   g
# 8:  64  512  64  8   h
# 9:  81  729  81  9   i
#10: 100 1000 100 10   j

【讨论】:

  • 对反对票的一些反馈会比简单的反对票更有帮助。这种方法有什么问题?它有效,(至少在示例中,如果是这样,也许有边缘情况让我知道)。对其进行基准测试,它与一串单独的 := 调用一样快。那么为什么要投反对票呢?如果有人能告诉我一个真正的问题,我会很乐意删除这个答案,但我想知道为什么。
  • downvote 实际上不是来自我,但我可以想象,downvote 可能是因为 R 语言比 eval-parse 提供的更多。如果可能,最好避免 eval-parse。
  • 是的,投反对票,因为就像我说的那样,如果你要这样做,最好至少尝试直接使用表达式,遵循常见问题解答 1.6 中的建议:rawgit.com/wiki/Rdatatable/data.table/vignettes/… 另外,原始问题只要求像with 版本那样看起来不错的模糊标准,我不认为使用字符串参数可以做到这一点(因为你会错过语法突出显示等)
  • @Frank 我现在使用表达式,没有文本或 eval(parse)。更好?
  • 当然,收回我的投票。仅供参考,无需在帖子正文中写“更新”。如果人们想看它,他们可以找到编辑历史;如果你想制作meta cmets,最好在这里做。至少我是这样做的。
猜你喜欢
  • 2023-03-29
  • 2019-12-17
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
  • 2013-11-22
相关资源
最近更新 更多