测试数据的R平方

时间:2014-09-05 17:33:04

标签: 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值。有没有简单的方法来计算它?

谢谢

4 个答案:

答案 0 :(得分:18)

这里有几个问题。首先,这不是使用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,])

现在fit拥有基于训练集的模型。以这种方式使用lm(...)可以让您在没有所有矩阵乘法的情况下生成预测。

第二个问题是R平方的定义。 conventional definition是:

  

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

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

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

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

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

我注意到您使用数据的前四分之三作为训练集,而不是随机抽样(如本例所示)。如果yx的依赖性是非线性的,并且x的顺序是正确的,那么您可以使用测试集获得负R-sq。

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

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

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

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

答案 1 :(得分: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

更新:miscTools::rSquared()函数假设R-squared是在计算模型的同一数据集上计算的,因为它计算

yy <- y - mean(y)

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

答案 2 :(得分:2)

如果您想要一个功能,miscTools包有一个rSquared功能。

require(miscTools)
r2 <- rSquared(ytest, resid = ytest-yhat)

答案 3 :(得分:0)

在样本(超出样本)上使用R2度量时,您会松开对R2解释的某些方面:

  • 等效SSR总数= SSR解释+ SSR错误
  • R2等于y与预测y之间的相关性的平方的事实
  • R2在[0,1]中的事实

如果要使用R,建议使用函数modelr::rsquare。请注意,这使用的是测试样本中的SSR总数,而不是训练样本中的SSR(某些人似乎主张)。

在这里我以一个示例为例,我们的火车数据只有3个点,因此存在模型存在错误的高风险,因此样本外性能也很差。事实上,您可以看到R2是负面的!

library(modelr)

train <- mtcars[c(1,3,4),]
test  <- mtcars[-c(1,3,4),]

mod <- lm(carb ~ drat, data = train)

计算火车数据:

## train
y_train <- train$carb
SSR_y_train <- sum((y_train-mean(y_train))^2)

cor(fitted(mod), y_train)^2
#> [1] 0.2985092
rsquare(mod, train)
#> [1] 0.2985092
1-sum(residuals(mod)^2)/SSR_y_train
#> [1] 0.2985092

根据测试数据进行计算:

## test
pred_test <- predict(mod, newdata = test)
y_test <- test$carb
SSR_y_test <- sum((y_test-mean(y_test))^2)

cor(pred_test, y_test)^2
#> [1] 0.01737236
rsquare(mod, test)
#> [1] -0.6769549

1- 28* var(pred_test-y_test)/SSR_y_train
#> [1] -19.31621
1- 28* var(pred_test-y_test)/SSR_y_test
#> [1] -0.6769549