如何将复杂的模型输出整齐地应用到 data.table 的一个因素

how to apply complex model outputs neatly to data.table by a factor

我在 data.table 对象上使用 R 中的 normalmixEM 函数(算法)。

这是一个简单的程序,运行 它可以完整地 table。这会输出一个 mixEM 列表对象,其中 $posterior 项是最感兴趣的。我可以像这样使用 cbind 以一种公认的有点笨拙的方式将其映射回数据:

library(data.table)
library(ggplot2)
library(mixtools)
set.seed(100)

faithfulDT <- data.table(faithful)
faithfulDT[, factorAB := rep(c('a', 'b'), .N)]
# Make some data

qplot(data = faithfulDT, x = eruptions, fill = factor) + facet_grid(factor ~.)
# graph the distribution

faithfulMix <- faithfulDT[, normalmixEM(eruptions)]
cbind(faithfulDT, data.table(faithfulMix$posterior)) # to join posterior probabilities to values. I'm ASSUMING this is the best way to do it?
plot(faithfulMix, whichplots = 2)
# model and graph without factorAB

但是,我正在努力将 data.table 的 by 参数有效地包含在此工作流程中。我的objective是运行一个normalmixEM函数byfactorAB。实际上,我想 运行 数据子集上的两个分离的孤立模型,然后根据它的基础,在它的末尾的两列中将每个值交给一个 data.table 'split-apply-combine' 策略。

library(data.table)
library(ggplot2)
library(mixtools)
set.seed(100)

faithfulDT <- data.table(faithful)
faithfulDT[, factorAB := rep(c('a', 'b'), .N)]
# Make some data

qplot(data = faithfulDT, x = eruptions, fill = factor) + facet_grid(factor ~.)
# graph the distribution

faithfulMix <- faithfulDT[, normalmixEM(eruptions)]
cbind(faithfulDT, data.table(faithfulMix$posterior)) # to join posterior probabilities to values. I'm ASSUMING this is the best way to do it?
plot(faithfulMix, whichplots = 2)
# model and graph without factorAB

faithfulMixAB <- faithfulDT[, normalmixEM(eruptions), by = factorAB]
# model and graph with factorAB - attempt by

faithfulMixAB <- faithfulDT[, normalmixEM(.SD$eruptions), by = factorAB]
# model and graph with factorAB - attempt by and .SD

faithfulMixAB <- faithfulDT[, normalmixEM(.SD), by = factorAB, .SDcols = "eruptions"]
# model and graph with factorAB - attempt by and .SD and .SDcols

faithfulMixAB <- faithfulDT[, lapply(.SD, normalmixEM), by = factorAB, .SDcols = "eruptions"]
# model and graph by factorAB - lapply
faithfulMixAB
# partial success?

faithfulMixABAssign <- faithfulDT[, mixMDL := lapply(.SD, normalmixEM), by = factorAB, .SDcols = "eruptions"]
# model and graph by factorAB - lapply and try to assign
faithfulMixABAssign
# even more partial success?

显然,我在这里成功地设法解决了一个似乎具有正确数字但在很大程度上是任意位置的解决方案。

在包含 factorAB 拆分的情况下,我在这个工作流程中遗漏了什么,它会整理输出?显然我需要为工作的 cbind 部分找到一个替代品,但是我当前的输出一开始就是一团糟。我可以改进 faithfulmixAB 的输出来促进这一点吗?可能完全跳过这个并直接从函数 运行ning 中分配后验值 data.table?


编辑

在@eddi 和朋友 IRL 的帮助下,我现在的情况是:

faithfulDT[, mixPostFull.1 := normalmixEM(eruptions)$posterior[,1]]
faithfulDT[, mixPostFull.2 := normalmixEM(eruptions)$posterior[,2]]

表示 运行 在不拆分因子的情况下模型的后两列。并且:

faithfulDT[, mixPostAB.1 := normalmixEM(eruptions)$posterior[,1], by = factorAB]
faithfulDT[, mixPostAB.2 := normalmixEM(eruptions)$posterior[,2], by = factorAB]

它有两列,但确实按因子拆分,这实际上是我想要做的。

认为需要这两个东西,因为后验对象实际上是 2 个向量,一个表示记录在 1 和组中的概率,另一个表示它在第二个。

Eddi,您当前的答案有 2 列,但我认为它们与上面列出的不一致。如果有的话,值略有不同:

eruptions waiting factorAB mixPostFull.1 mixPostFull.2  mixPostAB.1  mixPostAB.2
  1:     3.600      79        a  5.376906e-10  1.000000e+00 1.581467e-11 1.000000e+00
  2:     1.800      54        b  9.999998e-01  1.723648e-07 1.000000e+00 2.112761e-09
  3:     3.333      74        a  1.755506e-06  9.999982e-01 1.405098e-07 9.999999e-01
  4:     2.283      62        b  9.999406e-01  5.939085e-05 9.999974e-01 2.599843e-06
  5:     4.533      85        a  2.215050e-25  1.000000e+00 3.658846e-29 1.000000e+00
 ---                                                                                 
268:     4.117      81        b  6.337730e-18  1.000000e+00 9.658721e-10 1.000000e+00
269:     2.150      46        a  9.999912e-01  8.828998e-06 9.999828e-01 1.724380e-05
270:     4.417      90        b  3.320219e-23  1.000000e+00 1.461450e-12 1.000000e+00
271:     1.817      46        a  9.999998e-01  2.012672e-07 9.999995e-01 4.981589e-07
272:     4.467      74        b  3.912776e-24  1.000000e+00 4.818983e-13 1.000000e+00

我真正需要的是一种不必 运行 模型两次的方法。我很确定我可以在某个地方捏造':=',但我现在没有时间。待会return到吧

一段时间后 所以我在之前忽略了我不能仅仅重新 运行 模型来获得第二列,因为除了显然效率很低之外,由于算法的性质,除非我设置种子,因为每个 运行 有一个不同的起点,所以它会选择一个与下一个 运行 略有不同的答案。

我想你正在寻找这样的东西:

faithfulDT[, {
               result = as.vector(normalmixEM(eruptions)$posterior);
               faithfulDT[, paste0('result.', factorAB) := result];
               NULL
             }
           , by = factorAB]
faithfulDT
#     eruptions waiting factorAB     result.a     result.b
#  1:     3.600      79        a 1.581719e-11 1.000000e+00
#  2:     1.800      54        b 1.405263e-07 9.999974e-01
#  3:     3.333      74        a 3.660230e-29 9.531090e-01
#  4:     2.283      62        b 5.986926e-33 3.630698e-05
#  5:     4.533      85        a 9.999983e-01 6.384911e-12
# ---                                                     
#268:     4.117      81        b 6.545978e-07 1.000000e+00
#269:     2.150      46        a 2.342451e-06 1.562445e-06
#270:     4.417      90        b 1.000000e+00 1.000000e+00
#271:     1.817      46        a 1.724380e-05 1.000000e+00
#272:     4.467      74        b 4.981589e-07 1.000000e+00

经过评论和 OP 中的讨论,结果是想要的答案是:

faithfulDT[, c('mixAB.1', 'mixAB.2') := as.data.table(normalmixEM(eruptions)$posterior)
           , by = factorAB]