我想将一个lm
对象持久化到一个文件并将其重新加载到另一个程序中.我知道我可以通过saveRDS
/ 写入/读取二进制文件来做到这一点readRDS
,但我希望有一个ASCII文件而不是二进制文件.在更一般的层面上,我想知道为什么我在dput
输出中阅读的习语一般不符合我的预期.
下面是简单拟合的示例,以及模型的成功和不成功的重新创建:
dat_train <- data.frame(x=1:4, z=c(1, 2.1, 2.9, 4)) fit <- lm(z ~ x, dat_train) rm(dat_train) # Just to make sure fit is not dependent upon `dat_train existence` dat_score <- data.frame(x=c(1.5, 3.5)) ## This works (of course) predict(fit, dat_score) # 1 2 # 1.52 3.48
保存到二进制文件工作:
## http://stackoverflow.com/questions/5118074/reusing-a-model-built-in-r saveRDS(fit, "model.RDS") fit2 <- readRDS("model.RDS") predict(fit2, dat_score) # 1 2 # 1.52 3.48
这样做(dput
它在R会话中不是文件):
fit2 <- eval(dput(fit)) predict(fit2, dat_score) # 1 2 # 1.52 3.48
但是,如果我将文件保存到磁盘,我无法弄清楚如何恢复正常形状:
dput(fit, file = "model.R") fit3 <- source("model.R")$value # Error in is.data.frame(data): object 'dat_train' not found predict(fit3, dat_score) # Error in predict(fit3, dat_score): object 'fit3' not found
试图明确表示eval
不起作用:
## http://stackoverflow.com/questions/9068397/import-text-file-as-single-character-string dput(fit, file="model.R") fit4 <- eval(parse(text=paste(readLines("model.R"), collapse=" "))) # Error in is.data.frame(data): object 'dat_train' not found predict(fit4, dat_score) # Error in predict(fit4, dat_score): object 'fit4' not found
在上面的两种情况中,我都希望fit3
并且fit4
两者都能工作,但是它们不会重新编译成lm
我可以使用的对象predict()
.
任何人都可以告诉我如何将模型保存到具有类似structure(...)
ASCII结构的文件中,然后将其重新读回作为lm
我可以使用的对象predict()
?为什么我目前的方法不起作用?
步骤1:
您需要控制解析选项:
dput(fit, control = c("quoteExpressions", "showAttributes"), file = "model.R")
您可以阅读有关所有可能选项的更多信息?.deparseOpts
.
"quoteExpressions"包含所有调用/表达式/语言quote
,以便在以后重新解析它们时不会对它们进行求值.注意:
source
正在解析;
call
拟合的"lm"对象中的字段是一个调用:
fit$call # lm(formula = z ~ x, data = dat_train)
因此,如果没有"quoteExpressions",R将尝试lm
在解析期间评估调用.如果我们对它进行评估,那么它就是拟合线性模型,而R将旨在找到dat_train
,这将在您的新R会话中不存在.
"showAttributes"是另一个强制选项,因为"lm"对象具有类属性.你当然不想丢弃所有的类属性,只导出一个简单的"列表"对象,对吧?此外,"lm"对象中的许多元素,如model
(模型框架),qr
(紧凑的QR矩阵)和terms
(术语信息)等都具有属性.你想要保留所有这些.
如果未设置control
,则默认设置为:
control = c("keepNA", "keepInteger", "showAttributes")
将会被使用.如你所见,没有"quoteExpressions",所以你会遇到麻烦.
你也可以指定"keepInteger"和"keepNA",但我不认为需要"lm"对象.
第2步:
上面的步骤将source
正常工作.您可以恢复您的模型:
fit1 <- source("model.R")$value
但是,它还没有为像summary
和predict
工作这样的通用功能做好准备.为什么?
关键问题是terms
对象fit1
并不是一个真正的"术语"对象,而只是一个公式(它甚至不是一个公式,而只是一个没有"公式"类的"语言"对象!).只是比较fit$terms
和fit1$terms
,你会看到其中的差别.不要惊讶; 我们之前设置了"quoteExpressions".虽然这对于防止评估肯定是有帮助的call
,但它有副作用terms
.所以我们需要尽可能地重建terms
.
幸运的是,它足以做到:
fit1$terms <- terms.formula(fit1$terms)
虽然这仍然无法恢复所有信息fit$terms
(如缺少变量类),但它很容易成为有效的"术语"对象.
为什么"条款"对象至关重要?因为所有通用功能都依赖于它.你可能不需要了解更多,因为它真的是技术性的,所以我会停在这里.
完成后,我们可以成功使用predict
(summary
也是):
predict(fit1) ## no `newdata` given, using model frame `fit1$model` # 1 2 3 4 #1.03 2.01 2.99 3.97 predict(fit1, dat_score) ## with `newdata` # 1 2 #1.52 3.48
结论说:
虽然我已经向您展示了如何让事情发挥作用,但我并不建议您这样做.将模型拟合到大型数据集时,"lm"对象将非常大,例如residuals
,fitted.values
是长矢量,qr
并且model
是巨大的矩阵/数据帧.所以想想这个.