12

好吧,这很奇怪。我怀疑这是内部的一个错误data.table,但如果有人能解释为什么会发生这种情况,那将会很有用 - 究竟在update做什么?

我正在使用list(list())里面的技巧data.table来存储拟合的模型。当您为不同的分组创建一系列lm对象,然后创建update这些模型时,所有模型的模型数据将成为最后一个分组的模型数据。这似乎是一个参考挂在某个应该制作副本的地方,但我找不到在哪里,也无法在 and 之外复制lmupdate

具体例子:

从 iris 数据开始,首先使三个物种的样本量不同,然后lm为每个物种拟合一个模型,更新这些模型:

set.seed(3)
DT = data.table(iris)
DT = DT[rnorm(150) < 0.9]
fit = DT[, list(list(lm(Sepal.Length ~ Sepal.Width + Petal.Length))),
          by = Species]
fit2 = fit[, list(list(update(V1[[1]], ~.-Sepal.Length))), by = Species]

原始数据表中每个物种的数量不同

DT[,.N, by = Species]
#       Species  N
# 1:     setosa 41
# 2: versicolor 39
# 3:  virginica 42

第一次拟合证实了这一点:

fit[, nobs(V1[[1]]), by = Species]
#       Species V1
# 1:     setosa 41
# 2: versicolor 39
# 3:  virginica 42

但更新后的第二次拟合显示所有模型的 42

fit2[, nobs(V1[[1]]), by = Species]
#       Species V1
# 1:     setosa 42
# 2: versicolor 42
# 3:  virginica 42

我们还可以查看包含用于拟合的数据的模型属性,并看到所有模型确实都在使用最终组数据。问题是这是怎么发生的?

head(fit$V1[[1]]$model)
#   Sepal.Length Sepal.Width Petal.Length
# 1          5.1         3.5          1.4
# 2          4.9         3.0          1.4
# 3          4.7         3.2          1.3
# 4          4.6         3.1          1.5
# 5          5.0         3.6          1.4
# 6          5.4         3.9          1.7
head(fit$V1[[3]]$model)
#   Sepal.Length Sepal.Width Petal.Length
# 1          6.3         3.3          6.0
# 2          5.8         2.7          5.1
# 3          6.3         2.9          5.6
# 4          7.6         3.0          6.6
# 5          4.9         2.5          4.5
# 6          7.3         2.9          6.3
head(fit2$V1[[1]]$model)
#   Sepal.Length Sepal.Width Petal.Length
# 1          6.3         3.3          6.0
# 2          5.8         2.7          5.1
# 3          6.3         2.9          5.6
# 4          7.6         3.0          6.6
# 5          4.9         2.5          4.5
# 6          7.3         2.9          6.3
head(fit2$V1[[3]]$model)
#   Sepal.Length Sepal.Width Petal.Length
# 1          6.3         3.3          6.0
# 2          5.8         2.7          5.1
# 3          6.3         2.9          5.6
# 4          7.6         3.0          6.6
# 5          4.9         2.5          4.5
# 6          7.3         2.9          6.3
4

1 回答 1

6

这不是答案,但评论太长了

对于.Environment每个生成的模型,术语组件都是相同的

e1 <- attr(fit[['V1']][[1]]$terms, '.Environment')
e2 <- attr(fit[['V1']][[2]]$terms, '.Environment')
e3 <- attr(fit[['V1']][[3]]$terms, '.Environment')
identical(e1,e2)
## TRUE
identical(e2, e3)
## TRUE

似乎对于按组进行的每次评估(这是有效的)data.table都使用相同的内存位(我的非技术术语)。j但是,当update被调用时,它正在使用它来重新调整模型。这将包含最后一组的值。

所以,如果你捏造这个,它会起作用的

fit = DT[, { xx <-list2env(copy(.SD))

             mymodel <-lm(Sepal.Length ~ Sepal.Width + Petal.Length)
             attr(mymodel$terms, '.Environment') <- xx
             list(list(mymodel))}, by= 'Species']





lfit2 <- fit[, list(list(update(V1[[1]], ~.-Sepal.Width))), by = Species]
lfit2[,lapply(V1,nobs)]
V1 V2 V3
1: 41 39 42
# using your exact diagnostic coding.
lfit2[,nobs(V1[[1]]),by = Species]
      Species V1
1:     setosa 41
2: versicolor 39
3:  virginica 42

不是一个长期的解决方案,但至少是一种解决方法。

于 2013-03-13T04:07:53.380 回答