为啥在分组 data.table 中的 lm 上使用更新会丢失其模型数据?
Posted
技术标签:
【中文标题】为啥在分组 data.table 中的 lm 上使用更新会丢失其模型数据?【英文标题】:Why is using update on a lm inside a grouped data.table losing its model data?为什么在分组 data.table 中的 lm 上使用更新会丢失其模型数据? 【发布时间】:2013-02-12 08:35:44 【问题描述】:好吧,这很奇怪。我怀疑这是 data.table
内部的一个错误,但如果有人能解释为什么会发生这种情况会很有用 - update
到底在做什么?
我在data.table
中使用list(list())
技巧来存储拟合模型。当您为不同的分组创建一系列 lm
对象,然后为这些模型创建 update
时,所有模型的模型数据将成为最后一个分组的模型数据。这似乎是一个参考挂在某个应该制作副本的地方,但我找不到在哪里,我无法在 lm
和 update
之外复制它。
具体例子:
从鸢尾花数据开始,首先让三个物种的样本量不同,然后为每个物种拟合一个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
【问题讨论】:
这个行为可以用这个更简单地重新创建:m1 <- fit$V1[[2]]; m2 <- update(m1, .~.)
; m1
和 m2
然后是不同的。也许这将有助于弄清楚。
谢谢,我已经尝试了很长时间来简化这一点
你读过***.com/questions/13690184 - 它可能是相关的。
@hadley 谢谢 - 它看起来确实相关。如果更新正在“全局”范围内寻找对象,那么我想知道当它在 data.table
内时它在哪里寻找。值得注意的是,它没有捕获整个 data.table 列 - 仅捕获最后一组。
我仔细看了一遍,但我也很困惑。目前已将其归档为bug#2590,并将再次使用它。顺便说一句,很好的发现,以及很好的问题布局。
【参考方案1】:
这不是一个答案,但评论太长了
术语组件的.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
不是一个长期的解决方案,但至少是一种解决方法。
【讨论】:
以上是关于为啥在分组 data.table 中的 lm 上使用更新会丢失其模型数据?的主要内容,如果未能解决你的问题,请参考以下文章
如何根据每周日期创建移动平均线,按data.table中的多列分组?
为啥 jquery.animate 在 textarea 上使闪烁的光标消失?