我认为元编程在这里是正确的术语.
我希望能够使用data.table,就像在webapp中使用MySQL一样.也就是说,Web用户使用一些Web前端(例如Shiny服务器)来选择数据库,选择要过滤的列,选择要分组的列,选择要聚合的列和聚合函数.我想使用R和data.table作为查询,聚合等的后端.假设前端存在,R将这些变量作为字符串,并验证它们等.
我编写了以下函数来构建data.table表达式并使用R的parse/eval元编程功能来运行它.这是一种合理的方法吗?
我包括所有相关代码来测试这个.获取此代码(在读取安全性之后!)并运行test_agg_meta()来测试它.这只是一个开始.我可以添加更多功能.
但我的主要问题是我是否过度思考这一点.有没有更直接的方法来使用data.table,所有的输入都是事先确定的,而不需要求助于parse/eval元编程?
我也知道"with"声明和一些其他无糖功能方法,但不知道他们是否可以处理所有情况.
require(data.table)
fake_data<-function(num=12){
#make some fake data
x=1:num
lets=letters[1:num]
data=data.table(
u=rep(c("A","B","C"),floor(num/3)),
v=x %%2, w=lets, x=x, y=x^2, z=1-x)
return(data)
}
data_table_meta<-function(
#aggregate a data.table meta-programmatically
data_in=fake_data(),
filter_cols=NULL,
filter_min=NULL,
filter_max=NULL,
groupby_cols=NULL,
agg_cols=setdiff(names(data_in),groupby_cols),
agg_funcs=NULL,
verbose=F,
validate=T,
jsep="_"
){
all_cols=names(data_in)
if (validate) {
stopifnot(length(filter_cols) == length(filter_min))
stopifnot(length(filter_cols) == length(filter_max))
stopifnot(filter_cols %in% all_cols)
stopifnot(groupby_cols %in% all_cols)
stopifnot(length(intersect(agg_cols,groupby_cols)) == 0)
stopifnot((length(agg_cols) == length(agg_funcs)) | (length(agg_funcs)==1) | (length(agg_funcs)==0))
}
#build the command
#defaults
i_filter=""
j_select=""
n_agg_funcs=length(agg_funcs)
n_agg_cols=length(agg_cols)
n_groupby_cols=length(groupby_cols)
if (n_agg_funcs == 0) …Run Code Online (Sandbox Code Playgroud) 在评估data.table(vs. dplyr)的效用时,关键因素是在函数和循环中使用它的能力.
为此,我修改了这篇文章中使用的代码片段:data.table vs dplyr:一个做得好,另一个做不好或做得不好?这样,代替硬编码的数据集变量名称("钻石"数据集的"切割"和"价格"变量),它变得与数据集无关 - 切割n-paste准备好在任何函数或循环内使用(当我们事先不知道列名.
这是原始代码:
library(data.table)
dt <- data.table(ggplot2::diamonds)
dt[cut != "Fair", .(mean(price),.N), by = cut]
Run Code Online (Sandbox Code Playgroud)
这是与数据集无关的等价物:
dt <- data.table(diamonds)
nVarGroup <- 2 #"cut"
nVarMeans <- 7 #"price"
strGroupConditions <- levels(dt[[nVarGroup]])[-1] # "Good" "Very Good" "Premium" "Ideal"
strVarGroup <- names(dt)[nVarGroup]
strVarMeans <- names(dt)[nVarMeans]
qAction <- quote(mean(get(strVarMeans))) #! w/o get() it does not work!
qGroup <- quote(get(strVarGroup) %in% strGroupConditions) #! w/o get() it does not work!
dt[eval(qGroup), .(eval(qAction), .N), by = strVarGroup]
Run Code Online (Sandbox Code Playgroud)
注意(感谢下面的回复):如果您需要通过引用更改变量值,则需要使用 …