当变量名存储在字符向量中时,选择/分配给data.table

时间:2012-09-12 15:46:42

标签: r data.table

如果变量名存储在字符向量中,如何引用data.table中的变量?例如,这适用于data.frame

df <- data.frame(col1 = 1:3)
colname <- "col1"
df[colname] <- 4:6
df
#   col1
# 1    4
# 2    5
# 3    6

如何使用或不使用:=表示法对data.table执行相同的操作?显而易见的dt[ , list(colname)]不起作用(我也没想到)。

5 个答案:

答案 0 :(得分:105)

以编程方式选择变量的两种方法:

  1. with = FALSE

    DT = data.table(col1 = 1:3)
    colname = "col1"
    DT[, colname, with = FALSE] 
    #    col1
    # 1:    1
    # 2:    2
    # 3:    3
    
  2. 'dot dot'(..)前缀:

    DT[, ..colname]    
    #    col1
    # 1:    1
    # 2:    2
    # 3:    3
    
  3. 有关“点点”(..)表示法的进一步说明,请参阅New Features in 1.10.2(目前未在帮助文字中对其进行描述)。

    分配给变量,将:=的LHS包装在括号中:

    DT[, (colname) := 4:6]    
    #    col1
    # 1:    4
    # 2:    5
    # 3:    6
    

    后者称为列 plonk ,因为您通过引用替换整个列向量。如果存在子集i,则它将通过引用进行子分配。 (colname)周围的parens是2014年10月CRAN版本v1.9.4中的简写。这里是the news item

      

    with = FALSE:=一起使用现在在所有情况下都被弃用,因为包装       :=带有括号的LHS已经有一段时间了。

    colVar = "col1"
    DT[, colVar := 1, with = FALSE]                 # deprecated, still works silently
    DT[, (colVar) := 1]                             # please change to this
    DT[, c("col1", "col2") := 1]                    # no change
    DT[, 2:4 := 1]                                  # no change
    DT[, c("col1","col2") := list(sum(a), mean(b)]  # no change
    DT[, `:=`(...), by = ...]                       # no change
    

    另请参阅?`:=`中的详细信息部分:

    DT[i, (colnamevector) := value]
    # [...] The parens are enough to stop the LHS being a symbol
    

    在评论中回答进一步的问题,这是一种方式(通常有很多方法):

    DT[, colname := cumsum(get(colname)), with = FALSE]
    #    col1
    # 1:    4
    # 2:    9
    # 3:   15 
    

    或者,您可能会发现只需eval paste就可以更轻松地进行读取,编写和调试,类似于构建要发送到服务器的动态SQL语句:

    expr = paste0("DT[,",colname,":=cumsum(",colname,")]")
    expr
    # [1] "DT[,col1:=cumsum(col1)]"
    
    eval(parse(text=expr))
    #    col1
    # 1:    4
    # 2:   13
    # 3:   28
    

    如果你这么做,你可以定义辅助函数EVAL

    EVAL = function(...)eval(parse(text=paste0(...)),envir=parent.frame(2))
    
    EVAL("DT[,",colname,":=cumsum(",colname,")]")
    #    col1
    # 1:    4
    # 2:   17
    # 3:   45
    

    既然data.table 1.8.2自动优化了j的效率,最好使用eval方法。例如,get()中的j会阻止某些优化。

    或者,有set():=的低开销,功能形式,这里很好。请参阅?set

    set(DT, j = colname, value = cumsum(DT[[colname]]))
    DT
    #    col1
    # 1:    4
    # 2:   21
    # 3:   66
    

答案 1 :(得分:7)

*这不是一个真正的答案,但我没有足够的街头信誉来发表评论:/

无论如何,对于那些可能希望在数据表中实际创建一个名称存储在变量中的新列的人来说,我已经完成了以下工作。我不知道它的表现。有任何改进建议吗?假设一个无名的新列总是被命名为V1?

是否安全
colname <- as.name("users")
# Google Analytics query is run with chosen metric and resulting data is assigned to DT
DT2 <- DT[, sum(eval(colname, .SD)), by = country]
setnames(DT2, "V1", as.character(colname))

注意我可以在sum()中引用它,但似乎无法在同一步骤中指定它。顺便说一下,我需要这样做的原因是colname将基于Shiny app中的用户输入。

答案 2 :(得分:2)

适用于多列和应用于列值的函数。

更新函数中的值时,RHS必须是列表对象,因此使用.SD上的lapply循环可以实现这一目的。

以下示例将整数列转换为数字列

a1 <- data.table(a=1:5, b=6:10, c1=letters[1:5])
sapply(a1, class)  # show classes of columns
#         a           b          c1 
# "integer"   "integer" "character" 

# column name character vector
nm <- c("a", "b")

# Convert columns a and b to numeric type
a1[, j = (nm) := lapply(.SD, as.numeric ), .SDcols = nm ]

sapply(a1, class)
#         a           b          c1 
# "numeric"   "numeric" "character" 

答案 3 :(得分:2)

通过变量或函数从data.table中检索多个列:

library(data.table)

x <- data.table(this=1:2,that=1:2,whatever=1:2)

# === explicit call
x[, .(that, whatever)]
x[, c('that', 'whatever')]

# === indirect via  variable
# ... direct assignment
mycols <- c('that','whatever')
# ... same as result of a function call
mycols <- grep('a', colnames(x), value=TRUE)

x[, ..mycols]
x[, .SD, .SDcols=mycols]

# === direct 1-liner usage
x[, .SD, .SDcols=c('that','whatever')]
x[, .SD, .SDcols=grep('a', colnames(x), value=TRUE)]

全部产生

   that whatever
1:    1        1
2:    2        2

我发现.SDcols是最优雅的方式。

答案 4 :(得分:1)

您可以尝试这个

colname <-as.name(“ COL_NAME”)

DT2 <-DT [,list(COL_SUM = sum(eval(colname,.SD))),by = c(group)]