我有一个函数,在列表中返回两个值.这两个值都需要添加到两个新列的data.table中.对功能的评估是昂贵的,所以我想避免必须两次计算功能.这是一个例子:
library(data.table)
example(data.table)
DT
x y v
1: a 1 42
2: a 3 42
3: a 6 42
4: b 1 4
5: b 3 5
6: b 6 6
7: c 1 7
8: c 3 8
9: c 6 9
Run Code Online (Sandbox Code Playgroud)
这是我的功能的一个例子.记住我说这是昂贵的计算,除此之外,没有办法从其他给定值中推导出一个返回值(如下例所示):
myfun <- function (y, v)
{
ret1 = y + v
ret2 = y - v
return(list(r1 = ret1, r2 = ret2))
}
Run Code Online (Sandbox Code Playgroud)
这是我在一个语句中添加两列的方法.那个人需要两次打电话给myfun:
DT[,new1:=myfun(y,v)$r1][,new2:=myfun(y,v)$r2]
x y v new1 new2
1: a 1 42 43 -41 …Run Code Online (Sandbox Code Playgroud) 首先:感谢@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,其中名称是动态的.另外,我需要by在添加这些列时使用参数.例如:
test_dtb <- data.table(a = sample(1:100, 100), b = sample(1:100, 100), id = rep(1:10,10))
cn <- parse(text = "blah")
test_dtb[ , eval(cn) := mean(a), by = id]
# Error in `[.data.table`(test_dtb, , `:=`(eval(cn), mean(a)), by = id) :
# LHS of := must be a single column name when with=TRUE. When with=FALSE the LHS may be a vector of column names or positions.
Run Code Online (Sandbox Code Playgroud)
另一种尝试:
cn <- "blah"
test_dtb[ , cn := mean(a), by = id, with …Run Code Online (Sandbox Code Playgroud) 我想同时添加许多新列到data.table基于组的计算.我的数据的工作示例如下所示:
Time Stock x1 x2 x3
1: 2014-08-22 A 15 27 34
2: 2014-08-23 A 39 44 29
3: 2014-08-24 A 20 50 5
4: 2014-08-22 B 42 22 43
5: 2014-08-23 B 44 45 12
6: 2014-08-24 B 3 21 2
Run Code Online (Sandbox Code Playgroud)
现在我想scale和sum许多变量得到如下输出:
Time Stock x1 x2 x3 x2_scale x3_scale x2_sum x3_sum
1: 2014-08-22 A 15 27 34 -1.1175975 0.7310560 121 68
2: 2014-08-23 A 39 44 29 0.3073393 0.4085313 121 68
3: 2014-08-24 …Run Code Online (Sandbox Code Playgroud) 用于:=创建新列是我最喜欢的 data.table 功能之一。我知道有两种使用它一次添加多个列的方法。这是一个简单的例子
dt <- data.table("widths" = seq(2, 10, 2), "heights" = 8:4)
dt
widths heights
1: 2 8
2: 4 7
3: 6 6
4: 8 5
5: 10 4
Run Code Online (Sandbox Code Playgroud)
假设我想添加两列,一列用于面积,另一列用于周长。第一种方法是调用,例如
new_cols <- c("areas", "perimeters")
my_fun <- function(x, y){
areas <- x * y
perimeters <- 2*(x + y)
return(list(areas = areas, perimeters = perimeters))
}
dt[ , (new_cols) := my_fun(widths, heights)]
dt
widths heights areas perimeters
1: 2 8 16 20
2: 4 7 28 22 …Run Code Online (Sandbox Code Playgroud) 我的问题是关于将多列分配给 data.table 时代码的易错性/可维护性。
我有一个返回 data.table 的函数,如下所示:
f <- function(x)
{
# perform some complicated operations on x yielding multiple results
data.table(col1 = my_result_1, col2 = my_result_2)
}
Run Code Online (Sandbox Code Playgroud)
我将此函数应用于另一个 data.table 的行组,结果将添加为新列(或更新列,如果它们已经存在):
dt <- data.table(x = 1 : 4, id = c(1,1,2,2))
# x id
# 1: 1 1
# 2: 2 1
# 3: 3 2
# 4: 4 2
dt[, c('col1', 'col2') := f(x), by = id]
Run Code Online (Sandbox Code Playgroud)
从技术上讲,这很好用。但是,我想知道是否有一种优雅的方法可以避免在f():= 的 LHS 上再次指定生成的列名。
我想计算在整洁的 data.table 中每个组有多少个 TRUE 标记:
DT <- data.table( id = c(1 ,1 ,1 ,2 ,2 ,2 ,2 ,2 )
, marker = c(TRUE,FALSE,FALSE,TRUE,FALSE,TRUE,TRUE,FALSE))
Run Code Online (Sandbox Code Playgroud)
所以我尝试了DT[marker==TRUE, num_markers := .N, by = id],输出:
id marker num_markers
1: 1 TRUE 1
2: 1 FALSE NA
3: 1 FALSE NA
4: 2 TRUE 3
5: 2 FALSE NA
6: 2 TRUE 3
7: 2 TRUE 3
8: 2 FALSE NA
Run Code Online (Sandbox Code Playgroud)
相反,所需的输出是:
id marker num_markers
1: 1 TRUE 1
2: 1 FALSE 1
3: …Run Code Online (Sandbox Code Playgroud) 我正在努力解决我遇到的一个特定问题,并且我已经搜索了stackoverflow并找到了接近但不完全符合我想要的示例.最接近的例子就在这里
这篇文章(这里)也接近但我不能让我的多输出函数与list()一起使用
我想要做的是创建具有按键分组的聚合值(min,max,mean,MyFunc)的表.我还有一些复杂的函数可以返回多个输出.我可以返回单个输出但这意味着多次运行复杂功能并且需要太长时间.
使用Matt Dowle在这篇文章中的例子做了一些改变......
x <- data.table(a=1:3,b=1:6)[]
a b
1: 1 1
2: 2 2
3: 3 3
4: 1 4
5: 2 5
6: 3 6
Run Code Online (Sandbox Code Playgroud)
这是我想要的输出类型.聚合表(此处仅包含均值和总和)
agg.dt <- x[ , list(mean=mean(b), sum=sum(b)), by=a][]
a mean sum
1: 1 2.5 5
2: 2 3.5 7
3: 3 4.5 9
Run Code Online (Sandbox Code Playgroud)
此示例函数f返回3个输出.我的真正功能要复杂得多,而且成分也不能像这样分开.
f <- function(x) {list(length(x), min(x), max(x))}
Run Code Online (Sandbox Code Playgroud)
Matt Dowle对之前帖子的建议很有效,但不生成和聚合表,而是将聚合添加到主表中(在其他情况下也非常有用)
x[, c("length","min", "max"):= f(b), by=a][]
a b length min max
1: 1 1 …Run Code Online (Sandbox Code Playgroud)