首页 > 解决方案 > R data.table:通过分组有效地访问和更新 j 表达式中的变量列名

问题描述

我想对数据表中的列列表应用一个转换(其类型,松散地说,是“向量”->“向量”),这个转换将涉及分组操作。

这是设置和我想要实现的目标:

library(data.table)

set.seed(123)
n <- 1000
DT <- data.table(
        date = seq.Date(as.Date('2000/1/1'), by='day', length.out = n),
        A = runif(n),
        B = rnorm(n),
        C = rexp(n))

DT[, A.prime := (A - mean(A))/sd(A), by=year(date)]
DT[, B.prime := (B - mean(B))/sd(B), by=year(date)]
DT[, C.prime := (C - mean(C))/sd(C), by=year(date)]

目标是避免输入列名。在我的实际应用程序中,我有一个我想应用此转换的列列表。

library(data.table)
set.seed(123)
n <- 1000
DT <- data.table(
        date = seq.Date(as.Date('2000/1/1'), by='day', length.out = n),
        A = runif(n),
        B = rnorm(n),
        C = rexp(n))

columns <- c("A", "B", "C")

for (x in columns) {
    # This doesn't work.
    # target <- DT[, (x - mean(x, na.rm=TRUE))/sd(x, na.rm = TRUE), by=year(date)]

    # This doesn't work.
    #target <- DT[, (..x - mean(..x, na.rm=TRUE))/sd(..x, na.rm = TRUE), by=year(date)]

    # THIS WORKS! But it is tedious writing "get(x)" every time. 
    target <- DT[, (get(x) - mean(get(x), na.rm=TRUE))/sd(get(x), na.rm = TRUE), by=year(date)][, V1]

    set(DT, j = paste0(x, ".prime"), value = target)
}

问题:实现上述结果的惯用方法是什么?有两点可以改进:

  1. 如何避免get(x)每次使用x访问列时都输入内容?
  2. 访问[, V1]是最有效的方法吗?是否可以通过引用直接更新DT,而不创建中间data.table?

标签: rperformancedata.table

解决方案


您可以使用.SDcols指定要操作的列:

library(data.table)

columns <- c("A", "B", "C")
newcolumns <- paste0(columns, ".prime")

DT[, (newcolumns) := lapply(.SD, function(x) (x- mean(x))/sd(x)),
                      year(date), .SDcols = columns]

这避免了get(x)每次使用和data.table通过引用更新。


推荐阅读