【发布时间】:2014-09-10 01:52:48
【问题描述】:
首先:感谢@MattDowle; data.table 是最好的东西之一
自从我开始使用R 以来,我从未遇到过。
第二:我知道变量列的各种用例有很多变通方法
data.table 中的名称,包括:
- Select / assign to data.table variables which names are stored in a character vector
- pass column name in data.table using variable in R
- Referring to data.table columns by names saved in variables
- passing column names to data.table programmatically
- Data.table meta-programming
- How to write a function that calls a function that calls data.table?
- Using dynamic column names in `data.table`
- dynamic column names in data.table, R
- Assign multiple columns using := in data.table, by group
- Setting column name in "group by" operation with data.table
- R summarizing multiple columns with data.table
可能还有更多我没有参考的内容。
但是:即使我学会了上面记录的所有技巧,以至于我 从来不用查找它们来提醒自己如何使用它们,我仍然会发现 使用作为参数传递给函数的列名是 一项极其繁琐的任务。
我正在寻找的是“经过最佳实践批准”的替代方案 到以下解决方法/工作流程。考虑 我有一堆类似数据的列,并且想对这些列或它们的集合执行一系列类似的操作,其中操作具有任意高的复杂性,并且列名组传递给指定的每个操作一个变量。
我意识到这个问题听起来是人为的,但我却以惊人的频率遇到它。这些示例通常非常混乱,以至于很难分离出与此问题相关的功能,但我最近偶然发现了一个相当简单的示例,可以在此处用作 MWE:
library(data.table)
library(lubridate)
library(zoo)
the.table <- data.table(year=1991:1996,var1=floor(runif(6,400,1400)))
the.table[,`:=`(var2=var1/floor(runif(6,2,5)),
var3=var1/floor(runif(6,2,5)))]
# Replicate data across months
new.table <- the.table[, list(asofdate=seq(from=ymd((year)*10^4+101),
length.out=12,
by="1 month")),by=year]
# Do a complicated procedure to each variable in some group.
var.names <- c("var1","var2","var3")
for(varname in var.names) {
#As suggested in an answer to Link 3 above
#Convert the column name to a 'quote' object
quote.convert <- function(x) eval(parse(text=paste0('quote(',x,')')))
#Do this for every column name I'll need
varname <- quote.convert(varname)
anntot <- quote.convert(paste0(varname,".annual.total"))
monthly <- quote.convert(paste0(varname,".monthly"))
rolling <- quote.convert(paste0(varname,".rolling"))
scaled <- quote.convert(paste0(varname,".scaled"))
#Perform the relevant tasks, using eval()
#around every variable columnname I may want
new.table[,eval(anntot):=
the.table[,rep(eval(varname),each=12)]]
new.table[,eval(monthly):=
the.table[,rep(eval(varname)/12,each=12)]]
new.table[,eval(rolling):=
rollapply(eval(monthly),mean,width=12,
fill=c(head(eval(monthly),1),
tail(eval(monthly),1)))]
new.table[,eval(scaled):=
eval(anntot)/sum(eval(rolling))*eval(rolling),
by=year]
}
当然,此处对数据和变量的特定影响是无关紧要的,因此请不要关注它或建议改进以完成它在此特定情况下所完成的工作。相反,我正在寻找的是一种通用策略,用于重复将任意复杂的data.table 操作过程应用于列列表或列列表列表,在变量中指定或作为参数传递到一个函数,其中过程必须以编程方式引用变量/参数中命名的列,并且可能包括更新、连接、分组、对data.table特殊对象.I、.SD的调用等;但是一种比上面的或其他需要频繁quote-ing 和eval-ing 的更简单、更优雅、更短或更容易设计、实现或理解的方法。
请特别注意,由于过程可能相当复杂并且涉及反复更新data.table,然后引用更新的列,标准lapply(.SD,...), ... .SDcols = ... 方法通常不是可行的替代品。同样,用DT[[a.column.name]] 替换eval(a.column.name) 的每个调用既不能简化很多,也不能完全正常工作,因为据我所知,这与其他data.table 操作不兼容。
【问题讨论】:
-
不太确定你在找什么,因为那个例子远非最小的 imo,但我通常在 RHS 上使用
get(varname)(其中varname是例如“var1”而不是引用表达式),对于:=的 LHS,您可以简单地执行以下操作:dt[, paste0(varname, '.rolling') := ...] -
公平点,虽然很难知道如何“最小化”做出一个明确应该表明问题仅在程序复杂/涉及许多步骤时才相关的示例。关于
get(),我考虑过,但stackoverflow.com/a/12392269/241643 暗示它是次优的。现在不是这样了吗? -
理论上,如果您有大量列,
get可能不是最理想的,但在实践中我发现它更容易使用(这通常意味着更快的整体运行时间,当您包括编写时间/理解/维护代码)。在某些时候,它可能会被优化为与eval(quote一样高效。我还记得有一个 FR 要求将.实现为j-表达式中的一个函数,该函数相当于get,但效率很高(它还包括使用..作为访问外部变量的函数本地范围)。 -
IIUC 你所要求的功能似乎太笼统了..涵盖了 data.table 的许多功能并处理任何复杂的操作..
-
从阅读 adv-r.had.co.nz/Expressions.html 开始 - 你的
quote.convert()只是as.name()
标签: r data.table calculated-columns programmatically-created