鉴于以下data.table
dt
:
i a b
1: 1 1 NA
2: 2 1 NA
3: 2 2 2
4: 3 1 1
5: 3 2 2
6: 3 3 NA
7: 4 1 NA
8: 4 2 2
9: 4 3 3
10: 4 4 NA
我想使用Welford's Method和a
包工具计算按b
列分组的列i
和RStorm
的运行差异。我按照page 4 of RStorm's vignette上的示例进行了操作并阅读了introductory paper on RStorm,但我无法弄清楚如何使其发挥作用。这是我的代码:
library(RStorm)
dt = data.table(i=c(1,2,2,3,3,3,4,4,4,4), a=c(1,1:2,1:3,1:4), b=c(NA,NA,2,1,2,NA,NA,2,3,NA)
in_cols = c('a','b')
out_cols <- paste0(in_cols, '.var.Welford')
## Calculaing variance using Welford's method
## See: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
## See: "RStorm: Developing and Testing Streaming Algorithms in R", R Journal Vol 6/1
var.Welford <- function(x, ...) {
x <- as.numeric(x[1])
params <- GetHash("params2")
if (!is.data.frame(params)) {
params <- list()
params$M <- params$S <- params$n <- 0
}
x <- ifelse(is.na(x), params$M, x)
n <- params$n + 1
delta <- (x - params$M)
M <- params$M + ( delta / (n + 1) )
S <- params$S + delta*(x - M)
SetHash("params2", data.frame(n=n,M=M,S=S))
var <- ifelse(n > 1, S / (n-1), 0)
TrackRow("var.Welford", data.frame(var = var))
}
computeVarWelford <- function(x) {
topology <- Topology(as.data.frame(x=as.data.frame(x)))
topology <- AddBolt(topology, Bolt(var.Welford, listen = 0))
result <- RStorm(topology)
# GetTrack('var.Welford', result)
result$track$var.Welford
}
## Execute:
dt[, eval(out_cols) := lapply(.SD, function(x) {return(as.list(computeVarWelford(x))[1])})
, by=i, .SDcols = in_cols]
执行上述行会将dt
转换为:
i a b a.var.Welford b.var.Welford
1: 1 1 NA 0 0
2: 2 1 NA 0,2 0.000000,2.666667
3: 2 2 2 0,2 0.000000,2.666667
4: 3 1 1 0.0,2.0,2.5 0,2,1
5: 3 2 2 0.0,2.0,2.5 0,2,1
6: 3 3 NA 0.0,2.0,2.5 0,2,1
7: 4 1 NA 0.000000,2.000000,2.500000,3.333333 0.000000,2.666667,3.375000,2.250000
8: 4 2 2 0.000000,2.000000,2.500000,3.333333 0.000000,2.666667,3.375000,2.250000
9: 4 3 3 0.000000,2.000000,2.500000,3.333333 0.000000,2.666667,3.375000,2.250000
10: 4 4 NA 0.000000,2.000000,2.500000,3.333333 0.000000,2.666667,3.375000,2.250000
从结果可以清楚地看出,每个(列,组)对的整个差异列表都被复制到该(列,组)对的每个元素中,而不是被映射到该(列,组)对的所有元素。这就是我真正想要的:
i a b a.var.Welford b.var.Welford
1: 1 1 NA 0 0
2: 2 1 NA 0 0
3: 2 2 2 2 2.666667
4: 3 1 1 0.0 0
5: 3 2 2 2.0 2
6: 3 3 NA 2.5 1
7: 4 1 NA 0.000000 0.000000
8: 4 2 2 2.000000 2.666667
9: 4 3 3 2.500000 3.375000
10: 4 4 NA 3.333333 2.250000
我真的希望有一个简单的解决办法,但我还没有能够解决我的生活。每当我尝试我认为应该工作的东西时,我最终都会从data.table
说
j = list(...)中的所有项目都应该是原子矢量或列表。如果你是 尝试类似j = list(.SD,newcol = mean(colA))然后使用:= by 而不是(快得多),或之后cbind或合并。
我理解这意味着我在FUN
代码中尝试的任何lapply(.SD, FUN)
的返回值的维度与data.table
期望的维度不对应该组的专栏。
非常感谢任何和所有帮助。
编辑:好的解决方案非常简单。我觉得我好笨。但是,以后是谁可能需要它的答案
## Make sure to use [[]] at the end. My problem came entirely down to using [].
dt[, eval(out_cols) := lapply(.SD, function(x) {return(as.list(computeVarWelford(x))[[1]])})
, by=i, .SDcols = in_cols]
这就像一个魅力。我得到了我需要的东西:
i a b a.var.Welford b.var.Welford
1: 1 1 NA 0.000000 0.000000
2: 2 1 NA 0.000000 0.000000
3: 2 2 2 2.000000 2.666667
4: 3 1 1 0.000000 0.000000
5: 3 2 2 2.000000 2.000000
6: 3 3 NA 2.500000 1.000000
7: 4 1 NA 0.000000 0.000000
8: 4 2 2 2.000000 2.666667
9: 4 3 3 2.500000 3.375000
10: 4 4 NA 3.333333 2.250000
答案 0 :(得分:0)
编辑:我不再需要下面的黑客解决方案了。这是解决此问题的代码(注意[[]]而不是[]修复):
dt[, eval(out_cols) := lapply(.SD, function(x) {return(as.list(computeVarWelford(x))[[1]])})
, by=i, .SDcols = in_cols]
老人:好的,所以我找到了让它最终运作的方法。但我觉得这很难看。我现在要接受这个作为我的答案,但是如果有人有更好的解决方案,我很乐意听到它,并且如果它比我的好,那就接受它作为这个问题的答案。
解决方案:
out_cols_fixed <- paste0(out_cols, '.fixed')
dt[,eval(out_cols_fixed) := lapply(.SD, function(x) { return(x[1][[1]]) }), by=i, .SDcols = out_cols]
dt[,eval(out_cols) := NULL]
setnames(dt, old = out_cols_fixed, new = out_cols)
根据需要dt
的结果:
i a b a.var.Welford b.var.Welford
1: 1 1 NA 0.000000 0.000000
2: 2 1 NA 0.000000 0.000000
3: 2 2 2 2.000000 2.666667
4: 3 1 1 0.000000 0.000000
5: 3 2 2 2.000000 2.000000
6: 3 3 NA 2.500000 1.000000
7: 4 1 NA 0.000000 0.000000
8: 4 2 2 2.000000 2.666667
9: 4 3 3 2.500000 3.375000
10: 4 4 NA 3.333333 2.250000
我首先尝试了以下内容,但它没有用。任何人都可以解释原因吗?
dt[,eval(out_cols) := lapply(.SD, function(x) { return(x[1][[1]]) }), by=i, .SDcols = out_cols]
我在运行上面一行时遇到以下错误:
[.data.table
(dt ,,:=
(eval(out_cols),lapply(.SD, function(x){:RHS的类型('double')必须与LHS('list')匹配。至 检查和胁迫会以最快的速度影响性能 案例。更改目标列的类型,或强制RHS of:=你自己(例如使用1L代替1)