【问题标题】:R - Data.table - Using variable column names in RHS operationsR - Data.table - 在 RHS 操作中使用变量列名
【发布时间】:2016-03-30 05:42:43
【问题描述】:

如何在 := 操作的 RHS 上使用可变列名?例如,给定这个 data.table “dt”,我想创建两个新列,“first_y”和“first_z”,其中包含对“x”值的给定列的第一个观察值。

dt <- data.table(x = c("one","one","two","two","three"), 
                 y = c("a", "b", "c", "d", "e"), 
                 z = c(1, 2, 3, 4, 5))

dt
       x y z
1:   one a 1
2:   one b 2
3:   two c 3
4:   two d 4
5: three e 5

以下是不使用可变列名的方法。

dt[, c("first_y", "first_z") := .(first(y), first(z)), by = x]

dt
       x y z first_y first_z
1:   one a 1       a       1
2:   one b 2       a       1
3:   two c 3       c       3
4:   two d 4       c       3
5: three e 5       e       5

但是如果“y”和“z”列名动态存储在变量中,我该怎么做呢?

cols <- c("y", "z")

# This doesn't work
dt[, (paste0("first_", cols)) := .(first(cols)), by = x]

# Nor does this
q <- quote(first(as.name(cols[1])))
p <- quote(first(as.name(cols[2])))
dt[, (paste0("first_", cols)) := .(eval(q), eval(p)), by = x]

我尝试了很多其他的 quote() 和 eval() 以及 as.name() 的组合,但都没有成功。该操作的 LHS 似乎按预期工作,并且在许多地方都有记录,但我找不到任何关于在 RHS 上使用变量列名的信息。提前致谢。

【问题讨论】:

  • 这可能是一个解决方案,但是根据这个faq:cran.r-project.org/web/packages/data.table/vignettes/…,不推荐:dt[, (paste0("first_", cols)) := first(.SD[[ cols]]), by = x]
  • 作为一个有趣的说明,这种排序已经有效:dt[, (paste0("first_", cols)) := lapply(lapply(lapply(cols,as.name),eval),first) , by = x] 但在顶级 env 的上下文中进行评估
  • 我收到Error: object 'first' not found,您能否更新您的问题以使其可重现?
  • jangorecki:首先是一个 dplyr 函数,我认为他只需要一个库(dplyr)在顶部,或者它被包含在某个地方。但由于没有一个解决方案使用它,所以它有点没有实际意义。

标签: r data.table


【解决方案1】:

我不熟悉 first 函数(虽然它看起来像 Hadley 定义的东西)。

dt[, paste0("first_", cols) := lapply(.SD, head, n = 1L), 
   by = x, .SDcols = cols]
#       x y z first_y first_z
#1:   one a 1       a       1
#2:   one b 2       a       1
#3:   two c 3       c       3
#4:   two d 4       c       3
#5: three e 5       e       5

【讨论】:

  • 我一直认为lapply(.SD, function(x) x[1L]) 看起来更自然(事实上head 就是这样做的),但这基本上是品味问题
  • .SD[1] 足够了吗?它还在内部进行了优化(因此快得多)。
【解决方案2】:

.SDcols 答案适用于这种情况,但您也可以只使用get:

dt[, paste0("first_", cols) := lapply(cols, function(x) get(x)[1]), by = x]
dt
#       x y z first_y first_z
#1:   one a 1       a       1
#2:   one b 2       a       1
#3:   two c 3       c       3
#4:   two d 4       c       3
#5: three e 5       e       5

另一种选择是矢量化版本 - mget:

dt[, paste0("first_", cols) := setDT(mget(cols))[1], by = x]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 2022-01-15
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    相关资源
    最近更新 更多