R data.table按列名称列出的操作
假设我有一个R data.table按列名称列出的操作,r,data.table,R,Data.table,假设我有一个data.table a <- data.table(id=c(1,1,2,2,3),a=21:25,b=11:15,key="id") 但是,假设我有列名: (c中的n(“a”、“b”)){ s编辑2020-02-15关于。 data.table还支持。语法“查找级别”,在大多数情况下,例如下面的dt[,…n1]和dt[,…n2]都不需要with=FALSE 查看数据中的和。表: dt <- data.table(id=1:5,a=21:25,b=11:15,key
data.table
a <- data.table(id=c(1,1,2,2,3),a=21:25,b=11:15,key="id")
但是,假设我有列名:
(c中的n(“a”、“b”)){
s编辑2020-02-15关于。
data.table
还支持。
语法“查找级别”,在大多数情况下,例如下面的dt[,…n1]
和dt[,…n2]
都不需要with=FALSE
查看
数据中的和。表:
dt <- data.table(id=1:5,a=21:25,b=11:15,key="id")
dt[, n3 := dt[ , n1, with = FALSE ] * dt[ , n2, with = FALSE ], with = FALSE ]
dt这类似于:
但是您也希望将它与by=
相结合,因此set()
不够灵活。这是一种经过深思熟虑的设计,在这方面set()
不太可能改变
我有时会在回答的末尾使用EVAL
助手。
有些人对这种方法感到畏缩,但我只是认为它就像构造一个动态SQL语句,这是一种非常常见的做法。EVAL
方法提供了极大的灵活性,而不必对EVAL()
和quote()
。查看已构造的动态查询(检查它)您可以在EVAL
helper函数中添加print
但是,在这个简单的示例中,您可以用括号将:=
的LHS括起来,告诉数据。table
查找值(比with=FALSE
更清晰),RHS需要一个get()
(c中的n(“a”、“b”)){
s您也可以这样做:
a <- data.table(id=c(1,1,2,2,3),a=21:25,b=11:15,key="id")
a[, c("sa", "sb") := lapply(.SD, sum), by = id]
下面是一种方法,它使用.SD
# a helper function
makeCall <- function(x,fun) bquote(.(fun)(.(x)))
# the columns you wish to sum (apply function to)
cols <- c('a','b')
new.cols <- paste0('s',cols)
# create named list of names
name.cols <- setNames(sapply(cols,as.name), new.cols)
# create the call
my_call <- as.call(c(as.name(':='), lapply(name.cols, makeCall, fun = as.name('sum'))))
(a[, eval(my_call), by = 'id'])
# id a b sa sb
# 1: 1 21 11 43 23
# 2: 1 22 12 43 23
# 3: 2 23 13 47 27
# 4: 2 24 14 47 27
# 5: 3 25 15 25 15
#辅助函数
makeCall可能相关:而且有点老:…和data.table FAQ中的1.6。@joran:我不知道如何在这里使用eval
/quote
;我尝试了s@sds,我只是在头脑风暴。不过,我很同情。data.table为我造成的这类问题的混乱程度是我不使用它的最大原因经常。我不需要s
周围的参数,是吗?是的,否则它将在循环的两次迭代中创建一个名为“s”
的列。哦,对不起-我错过了with=FALSE
。我们已经向(LHS)移动了:=
因为这更容易阅读。with=FALSE
不清楚它指的是的LHS还是RHS:=
。这提醒了我,当使用:=
时,我们应该正式地反对with=FALSE
。对,所以问题不大。只要用get(n)包装n
是所需的全部。错误来自sum(“a”)
+1甚至更好,因为它是在一个单独的分组中进行的,而不是一个一个地添加每个列的分组。在这种情况下使用.SD
不应该起作用,因为.SD
中的所有数据都被使用。@MattDowle作为旁白-使用.SD
的主要作用发生在[.data.table
由于该函数的巨大开销而被涉及,因此类似于.SD[1:N]
的东西在.SD
的“by”循环中会慢几个数量级。哦,是的,谢谢提醒。它在列表中可以优化。@eddi,只是提醒讨论。它不仅仅是[.data.table
。它肯定会让事情变慢。但仅仅评估.SD
似乎也会让事情变慢。我将用data.frame和data.table以及post back做一个适当的基准测试。
dt <- data.table(id=1:5,a=21:25,b=11:15,key="id")
dt[ , dt.names["n3"] := 1L, with = FALSE ]
dt.names <- c( n1 = "a", n2 = "b", n3 = "c" )
setnames( dt, dt.names, names(dt.names) )
dt[ , n3 := n1 * n2, by = "id" ]
setnames( dt, names(dt.names), dt.names )
for (n in c("a","b")) {
s <- paste0("s",n)
a[, (s) := sum(get(n)), by="id"]
}
a <- data.table(id=c(1,1,2,2,3),a=21:25,b=11:15,key="id")
a[, c("sa", "sb") := lapply(.SD, sum), by = id]
cols.to.sum = c("a", "b")
a[, paste0("s", cols.to.sum) := lapply(.SD, sum), by = id, .SDcols = cols.to.sum]
# a helper function
makeCall <- function(x,fun) bquote(.(fun)(.(x)))
# the columns you wish to sum (apply function to)
cols <- c('a','b')
new.cols <- paste0('s',cols)
# create named list of names
name.cols <- setNames(sapply(cols,as.name), new.cols)
# create the call
my_call <- as.call(c(as.name(':='), lapply(name.cols, makeCall, fun = as.name('sum'))))
(a[, eval(my_call), by = 'id'])
# id a b sa sb
# 1: 1 21 11 43 23
# 2: 1 22 12 43 23
# 3: 2 23 13 47 27
# 4: 2 24 14 47 27
# 5: 3 25 15 25 15