mb7*_*744 7 r spline predict lm
我感兴趣的是lm函数的一些令人不安的行为以及predict.lmR中的相关函数.splines基础包提供了bs生成b样条展开的函数,然后可以使用lm多功能线性模型拟合函数来拟合样条模型.
这些lm和predict.lm函数具有很多内置的便利性,可以利用公式和术语.如果调用bs()嵌套在lm调用内,则用户可以提供单变量数据predict,并且此数据将自动扩展为适当的b样条基础.然后将照常预测这种扩展的数据矩阵.
library(splines)
x <- sort(runif(50, 0, 10))
y <- x^2
splineModel <- lm(y ~ bs(x, y, degree = 3, knots = c(3, 6)))
newData <- data.frame(x = 4)
prediction <- predict(splineModel, newData) # 16
plot(x, y)
lines(x, splineModel$fitted.values, col = 'blue3')
points(newData$x, prediction, pch = 3, cex = 3, col = 'red3')
legend("topleft", legend = c("Data", "Fitted Values", "Predicted Value"),
pch = c(1, NA, 3), col = c('black', 'blue3', 'red3'), lty = c(NA, 1, NA))
Run Code Online (Sandbox Code Playgroud)
如我们所见,这完美地运作:
当使用::运算符明确指示bs函数是从splines包的命名空间导出时,会发生异常.以下代码段除了该更改外完全相同:
library(splines)
x <- sort(runif(50, 0, 10))
y <- x^2
splineModel <- lm(y ~ splines::bs(x, y, degree = 3, knots = c(3, 6)))
newData <- data.frame(x = 4)
prediction <- predict(splineModel, newData) # 6.40171
plot(x, y)
lines(x, splineModel$fitted.values, col = 'blue3')
points(newData$x, prediction, pch = 3, cex = 3, col = 'red3')
legend("topleft", legend = c("Data", "Fitted Values", "Predicted Value"),
pch = c(1, NA, 3), col = c('black', 'blue3', 'red3'), lty = c(NA, 1, NA))
Run Code Online (Sandbox Code Playgroud)
如果splines从不library首先使用包附加在第二个片段中,则会产生完全相同的结果.我想不出另一种情况,即在::已经加载的包上使用运算符会改变程序行为.
使用其他函数(splines如自然样条基础实现)会产生相同的行为ns.有趣的是,在这两种情况下,"y hat"或拟合值都是合理的并且相互匹配.据我所知,拟合的模型对象除属性名称外是相同的.
我无法确定此行为的来源.虽然这可能看起来像一个错误报告,但我的问题是
predict.lm但不能确定分歧发生的地方.所以问题是模型需要跟踪用原始数据计算的结,并在预测新数据时使用这些值.这通常发生在model.frame()呼叫内部的lm()呼叫中.该bs()函数返回一个类,"bs"在创建model.frame时,将调度该列splines:::makepredictcall.bs以尝试捕获边界结.(你可以看到函数makepredictcall中的model.frame.default调用.)
但是,如果我们比较结果
splineModel1 <- lm(y ~ bs(x, y, degree = 3, knots = c(3, 6)))
attr(terms(splineModel1), "predvar")
# list(y, bs(x, degree = 3L, knots = c(3, 6), Boundary.knots = c(0.275912734214216,
# 9.14309860439971), intercept = FALSE))
splineModel2 <- lm(y ~ splines::bs(x, y, degree = 3, knots = c(3, 6)))
attr(terms(splineModel2), "predvar")
# list(y, splines::bs(x, y, degree = 3, knots = c(3, 6)))
Run Code Online (Sandbox Code Playgroud)
请注意第二个如何捕获Boundary.knots.这是因为splines:::makepredictcall.bs实际查看调用名称的功能
function (var, call) {
if (as.character(call)[1L] != "bs")
return(call)
...
}
Run Code Online (Sandbox Code Playgroud)
当您splines::bs在公式中使用时,则as.character(call)[1L]返回"splines::bs"不匹配的内容,"bs"以便不会发生任何事情.我不清楚为什么这个检查在那里.似乎方法调度应该足以假设它是一个bs对象.
在我看来,这似乎不是想要的行为,可能应该修复.但是,bs()如果不加载包,则不应该真正调用该函数,因为makepredictcall.bs不会导入类似函数,因此会破坏对这些对象的自定义调度.