如果变量名存储在字符向量中,如何引用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)]
不起作用(我也没想到)。
答案 0 :(得分:105)
以编程方式选择变量的两种方法:
with = FALSE
:
DT = data.table(col1 = 1:3)
colname = "col1"
DT[, colname, with = FALSE]
# col1
# 1: 1
# 2: 2
# 3: 3
'dot dot'(..
)前缀:
DT[, ..colname]
# col1
# 1: 1
# 2: 2
# 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)
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)]