首先:感谢@MattDowle; data.table是我开始使用以来发生过的最好的事情之一R.
第二:我知道变量列名的各种用例的许多变通方法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 …Run Code Online (Sandbox Code Playgroud) 我认为元编程在这里是正确的术语.
我希望能够使用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.非常感谢您的帮助.我该怎么做呢:
getResult <- function(dt, expr, gby) {
e <- substitute(expr)
b <- substitute(gby)
return(dt[,eval(e),by=b])
}
v1 <- "Sepal.Length"
v2 <- "Species"
dt <- data.table(iris)
rDT <- getResult(dt, sum(v1, na.rm=TRUE), v2)
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
sum中的错误(v1,na.rm = TRUE):参数的'type'(字符)无效
现在,无论是v1和v2从其他程序通过为字符型变量,所以我不能做到这一点v1<- quote(Sepal.Length),这似乎工作.
我有一个数学表达式,例如:
((2-x+3)^2+(x-5+7)^10)^0.5
Run Code Online (Sandbox Code Playgroud)
我需要将^符号替换pow为C语言的功能.我认为正则表达式是我需要的,但我不知道像专业人士那样的正则表达式.所以我最终得到了这个正则表达式:
(\([^()]*)*(\s*\([^()]*\)\s*)+([^()]*\))*
Run Code Online (Sandbox Code Playgroud)
我不知道如何改善这一点.你能建议我解决这个问题吗?
预期产量:
pow(pow(2-x+3,2)+pow(x-5+7,10),0.5)
Run Code Online (Sandbox Code Playgroud) 这看起来似乎是一个过于复杂的问题,但它让我有点疯狂了一段时间.这也是为了好奇,因为我已经有办法做我需要的事情,所以并不重要.
在R中,我需要一个函数来返回一个带有所有参数和用户输入的值的命名列表对象.为此,我制作了这个代码(玩具示例):
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- frm
for (i in 1:length(frm))
parms[[i]] <- get(names(frm)[i])
return(parms)
}
Run Code Online (Sandbox Code Playgroud)
所以当被问到这个时:
> foo(b=0)
$a
[1] 1
$b
[1] 0
$h
[1] "coconut"
Run Code Online (Sandbox Code Playgroud)
这个结果很完美.问题是,当我尝试使用lapply相同的目标时,为了更高效(和优雅),它不能像我想要的那样工作:
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- lapply(names(frm), get)
names(parms) <- names(frm)
return(parms)
}
Run Code Online (Sandbox Code Playgroud)
问题显然在于get评估它的第一个参数的环境(字符串,变量的名称).我部分地从错误消息中得知:
> foo(b=0)
Error in FUN(c("a", "b", "h")[[1L]], ...) : object 'a' not found
Run Code Online (Sandbox Code Playgroud)
而且,因为在.GlobalEnv环境中有正确名称的对象,foo会返回它们的值:
> a <- 100
> …Run Code Online (Sandbox Code Playgroud) 如何使用字符向量变量作为参数动态查找多个字段并通过引用添加.在下面的情况下,我想查找两列并删除i.它们中的前缀.当然,他们可以覆盖具有相同名称的现有列.
library(data.table)
set.seed(1)
ID <- data.table(id = 1:3, meta = rep(1,3), key = "id")
JN <- data.table(idd = sample(ID$id, 3, FALSE), value = sample(letters, 3, FALSE), meta = rep(1,3), key = "idd")
select <- c("value","meta") # my fields to lookup
j.lkp <- call(":=", select, lapply(paste0("i.",select), as.symbol))
j.lkp
# `:=`(c("value", "meta"), list(i.value, i.meta))
ID[JN, eval(j.lkp)]
# Error in eval(expr, envir, enclos) : could not find function "i.value"
ID[JN, `:=`(c("value", "meta"), list(i.value, i.meta))]
# id meta value
# …Run Code Online (Sandbox Code Playgroud) 我有两个包含许多字段的data.tables.
我想加入这两个表,添加一些计算字段并附加第一个,第二个或两个表中的所有其他字段(类似于SQL select a+b AS sum, DT1.*, DT2.* FROM...)而不键入所有字段名称.
我该怎么做(关于最简单的语法和最佳性能)?
简化的示例数据:
library(data.table)
DT1 = data.table(x=c("c", "a", "b", "a", "b"), a=1:5)
DT2 = data.table(x=c("d", "c", "b"), b=6:8)
Run Code Online (Sandbox Code Playgroud)
现在我想加入表并添加一个计算字段:
DT1[DT2, .(sum=a + b, <<< how to say DT1.*, DT2.* here? >>> ), on="x"]
Run Code Online (Sandbox Code Playgroud)
2016年5月4日更新: 灵感来自用户jangorecki我发现了一个功能请求:
我已经搜索了规范的方法来做我正在尝试的东西,但我似乎没有运气得到快速和优雅的工作.简而言之,我有一个包含多个值列的大表,并希望将每个值乘以查找表中的相应因子.我无法弄清楚如何动态传递我想要的列乘以查找值,或者如何在基本表达式之外引用查询值.
这是我的例子,我设置了300万行,有10个值列,这不需要太长时间,并且有点代表数据大小(这将作为更大的循环的一部分实现,因此强调关于表现).我们的value_1:value_10列还有一个包含6个级别和一些匹配乘数的查找表.
library(data.table)
setsize <- 3000000
value_num <- 10
factors <- c("factor_a", "factor_b", "factor_c", "factor_d", "factor_e", "factor_f")
random <- data.table(replicate(10, sample(factors, size = setsize, replace = T))
, replicate(10, rnorm(setsize, mean = 700, sd = 50)))
lookup <- data.table("V1" = factors, replicate(10, seq(.90, 1.5, length.out = length(factors))))
wps <- paste("value", c(1:10), sep = "_")
names(random)[11:20] <- wps
names(lookup)[2:11] <- wps
setkeyv(random, "V1")
setkeyv(lookup, "V1")
Run Code Online (Sandbox Code Playgroud)
解决方案1:它相当快,但我无法弄清楚如何一般地引用i-columns,i.value_1因此我可以将它们传递到循环中或更好地同时应用它们.
f <- function() {
random[lookup, value_1 := value_1 * i.value_1, by = .EACHI] …Run Code Online (Sandbox Code Playgroud)