测试数据的R平方

H_A*_*H_A 9 r linear-regression

我在75%的数据集上拟合了一个线性回归模型,包括~11000个观测值和143个变量:

gl.fit <- lm(y[1:ceiling(length(y)*(3/4))] ~ ., data= x[1:ceiling(length(y)*(3/4)),]) #3/4 for training

,我的R ^ 2为0.43.然后,我尝试使用其余数据预测我的测试数据:

ytest=y[(ceiling(length(y)*(3/4))+1):length(y)] x.test <- cbind(1,x[(ceiling(length(y)*(3/4))+1):length(y),]) #The rest for test yhat <- as.matrix(x.test)%*%gl.fit$coefficients #Calculate the predicted values

我现在想计算测试数据的R ^ 2值.有没有简单的方法来计算?

谢谢

jlh*_*ard 21

这里有几个问题.首先,这不是一个好用的方法lm(...).lm(...)用于与数据框一起使用,公式表达式引用df中的列.因此,假设你的数据在两个矢量xy,

set.seed(1)    # for reproducible example
x <- 1:11000
y <- 3+0.1*x + rnorm(11000,sd=1000)

df <- data.frame(x,y)
# training set
train <- sample(1:nrow(df),0.75*nrow(df))   # random sample of 75% of data

fit <- lm(y~x,data=df[train,])
Run Code Online (Sandbox Code Playgroud)

现在fit有基于训练集的模型.lm(...)例如,使用这种方式可以生成没有所有矩阵乘法的预测.

第二个问题是R平方的定义.在传统的定义是:

1 - SS.residuals/SS.total

对于训练集和训练集,

SS.total = SS.regression + SS.residual

所以

SS.regression = SS.total - SS.residual,

因此

R.sq = SS.regression/SS.total

所以R.sq是由模型解释的数据集中的可变性部分,并且总是在0和1之间.

你可以在下面看到这个.

SS.total      <- with(df[train,],sum((y-mean(y))^2))
SS.residual   <- sum(residuals(fit)^2)
SS.regression <- sum((fitted(fit)-mean(df[train,]$y))^2)
SS.total - (SS.regression+SS.residual)
# [1] 1.907349e-06
SS.regression/SS.total     # fraction of variation explained by the model
# [1] 0.08965502
1-SS.residual/SS.total     # same thing, for model frame ONLY!!! 
# [1] 0.08965502          
summary(fit)$r.squared     # both are = R.squared
# [1] 0.08965502
Run Code Online (Sandbox Code Playgroud)

但这不适用于测试集(例如,当您从模型进行预测时).

test <- -train
test.pred <- predict(fit,newdata=df[test,])
test.y    <- df[test,]$y

SS.total      <- sum((test.y - mean(test.y))^2)
SS.residual   <- sum((test.y - test.pred)^2)
SS.regression <- sum((test.pred - mean(test.y))^2)
SS.total - (SS.regression+SS.residual)
# [1] 8958890

# NOT the fraction of variability explained by the model
test.rsq <- 1 - SS.residual/SS.total  
test.rsq
# [1] 0.0924713

# fraction of variability explained by the model
SS.regression/SS.total 
# [1] 0.08956405
Run Code Online (Sandbox Code Playgroud)

在这个人为的例子中没有太大区别,但很可能有一个R平方.值小于0(以这种方式定义).

例如,如果模型是具有测试集的非常差的预测器,则残差实际上可能大于测试集中的总变化.这相当于说使用它的平均值比使用从训练集派生的模型更好地建模测试集.

我注意到你使用数据的前四分之三作为训练集,而不是随机抽样(如本例所示).如果yon 的依赖性x是非线性的,并且x它们是有序的,那么你可以得到一个带有测试集的负R-sq.

关于下面的OP评论,使用测试集评估模型的一种方法是通过比较模型内和模型外均方误差(MSE).

mse.train <- summary(fit)$sigma^2
mse.test  <- sum((test.pred - test.y)^2)/(nrow(df)-length(train)-2)
Run Code Online (Sandbox Code Playgroud)

如果我们假设训练和测试集都是正态分布,具有相同的方差并且具有遵循相同模型公式的均值,那么该比率应该具有带有(n.train-2)和(n.test-)的F分布. 2)自由度.如果MSE基于F检验显着不同,则该模型不能很好地拟合测试数据.

你有没有绘制你的test.y和pred.y vs x?仅这一点就会告诉你很多.


dmi*_*kno 5

在测试数据上计算R平方有点棘手,因为您必须记住基线是多少。基线预测是训练数据的平均值。

因此,在上面扩展@jlhoward提供的示例:

SS.test.total      <- sum((test.y - mean(df[train,]$y))^2)
SS.test.residual   <- sum((test.y - test.pred)^2)
SS.test.regression <- sum((test.pred - mean(df[train,]$y))^2)
SS.test.total - (SS.test.regression+SS.test.residual)
# [1] 11617720 not 8958890

test.rsq <- 1 - SS.test.residual/SS.test.total  
test.rsq
# [1] 0.09284556 not 0.0924713

# fraction of variability explained by the model
SS.test.regression/SS.test.total 
# [1] 0.08907705 not 0.08956405
Run Code Online (Sandbox Code Playgroud)

更新:miscTools::rSquared()函数假设R平方是在计算模型的同一数据集上计算得出的

yy <- y - mean(y)
Run Code Online (Sandbox Code Playgroud)

第184行的幕后花絮:https//github.com/cran/miscTools/blob/master/R/utils.R

  • 您在文献中是否有任何使用训练集平均值作为参考点的参考?直觉上它似乎很有说服力,但没有多少人使用它...... (2认同)