我是数据新手。表,但我需要加速一个dplyr代码,到目前为止,我将处理时间除以20,所以不用说,我想掌握这个库。通过这个介绍,你可以理解处理时间是最重要的。
我必须修改行使用循环,因为一些列是相互连接的。这里不讨论循环的使用问题:我将使用循环,没有其他解决方法,其他原因没有说明。我已经知道我会在我的代码中使用什么来获得所需的结果,因为它显然是最快的,但我知道有一种。sd的方式来做到这一点,这将让我更深入地了解该库,因此我寻求您的建议。
所以,只是要清楚:把这篇文章看作是一个练习,它将帮助我理解使用。sd的微妙之处。我将展示一个简单的表格和一个简单的函数(均值),但这些远非实际数据(我使用自制的窗口均值)。但是如果任何人都能通过使用"mean"得到相同的结果和。sd,那么问题就解决了,我会学到一些我还不知道的东西。对不起,我在这里使用了权威的语气,我只是想说清楚:我想知道我的方法出了什么问题。
非常简化的表和目标如下:
temp <- data.table(a=c(0,10), b=c(15,25))
#initialize 1rst row
temp[1, `:=`(worksA=a, worksB=b)]
#in the (not shown) loop, starting row 2, worksA & worksB update a mean with fresh data:
temp[2, `:=`(worksA=mean(temp$a[1:2]), worksB=mean(temp$b[1:2]))]
这样你就得到了我想要的(但请注意,我将使用自制的"mean")。函数带有滚动窗口,因此实际使用cummean是不行的):
a b worksA worksB
1: 0 15 0 15
2: 10 25 5 20
我的第一个失败是:
temp[2, `:=`(tryA=mean(a[1:2]),tryB=mean(b[1:2]))]
创建NA。我猜我不能使用行选择来通过引用创建列,所以我使用"$"(工作解决方案);但我还是怀疑。sd能起作用,所以试了试。2:
temp[2, c("tryA", "tryB"):=lapply(.SD[1:2], mean), .SDcols=c("a", "b")]
相同。有趣的是,如果使用name .rm:
temp[2, `:=`(tryA=mean(a[1:2], na.rm=TRUE),tryB=mean(b[1:2], na.rm=TRUE))]
或:
temp[2, c("tryA", "tryB"):=lapply(.SD[1:2], mean, na.rm=TRUE), .SDcols=c("a", "b")]
you get try &tryB行2更新值a &B来自同一行,就好像它只计算了第2行值的平均值。关于这件事,我尽量不要在第一个参数上使用行选择(没有"2")第1括号后):
temp[, c("tryA", "tryB"):=lapply(.SD[1:2], mean), .SDcols=c("a", "b")]
当然给出:
a b worksA worksB tryA tryB
1: 0 15 0 15 5 20
2: 10 25 5 20 5 20
。我想要在所有行上打印的值。好一点,但不是我想要的。
Microbenchmark告诉我,我的工作解决方案比lapply函数快近20倍,所以我放弃了。但是,有人能解释为什么我的尝试(除了最后一个,这个是非常清楚的)被错误地编码,以及我如何能够使用用户定义的函数和。sd一次编辑1行吗?
Thanks in advance
您可以使用Reduce
和accumulate=T
选项来生成每列的累积列表:
library(data.table)
temp <- data.table(a=c(0,10), b=c(15,25))
temp[,lapply(.SD, function(x) Reduce(x,f=function(x,y) c(x,y),accumulate=T))]
# a b
# <list> <list>
#1: 0 15
#2: 0,10 15,25
这样你就可以用sapply
对它们应用任何汇总函数(在这个例子中是平均值):
temp[,paste0('works',colnames(temp)):=lapply(.SD, function(x) sapply(Reduce(x,f=function(x,y) c(x,y),accumulate=T),function(x) mean(unlist(x))))][]
#> a b worksa worksb
#> <num> <num> <num> <num>
#> 1: 0 15 0 15
#> 2: 10 25 5 20
或具有递归平均值:
recursive.mean <- function(x) tail(stats::filter(x/2,1/2),1)
temp[,paste0('works',colnames(temp)):=lapply(.SD, function(x) sapply(Reduce(x,f=function(x,y) c(x,y),accumulate=T),function(x) recursive.mean(unlist(x))))][]
# a b worksa worksb
# <num> <num> <num> <num>
#1: 0 15 0.0 3.75
#2: 10 25 2.5 6.25
好吧好吧,来个自我回答怎么样?
不要认为这是自恋的举动,因为我现在明白我的问题是怎么回事了…愚蠢的。这完全是数据的误用。表语言:我想编辑&同时选择
。SD是数据的一个子集,所以temp[2, lapply(.SD[1:2], mean), .SDcols=c("a", "b")]
只能给出NA,因为我要求R从单行数据中返回几行子集(.SD[1:2]
)。表(temp[2,
)。第一部分([2,
)被R认为是一个选择,而不是一个版本。
temp[, lapply(.SD[1:2], mean), .SDcols=c("a", "b")]
给出了我想要的结果,所以这是不可触及的部分,我必须将编辑到表中,该版本请求写在代码的上层,其中"2"应该是。
因此temp[2, c("worksA", "worksB"):=temp[, lapply(.SD[1:2], mean), .SDcols=c("a", "b")]]
完全符合我的意思:第一部分(LHS)要求修改,第二部分(:=
的RHS)是我想要插入的。. sd将返回一个输出,而不是在从中提取的表中编辑自己。太明显了,我的错。
在基准测试中,$ reference比.SD快2.8倍,正如预期的那样:
microbenchmark("$ref"={temp[2, `:=`(worksA=mean(temp$a[1:2]), worksB=mean(temp$b[1:2]))]}, ".SD"={temp[2, c("worksA", "worksB"):=temp[, lapply(.SD[1:2], mean), .SDcols=c("a", "b")]]}, times=10000L)
#Unit: microseconds
# expr min lq mean median uq max neval cld
# $ref 390.601 427.2185 593.3664 479.921 558.4865 38580.97 10000 a
# .SD 1102.362 1224.5490 1681.0160 1373.182 1576.1190 269964.59 10000 b
抱歉大惊小怪,问题解决了,我现在知道更多了(双关语!),让我们回去工作吧。非常感谢大家!