繁体   English   中英

测试数据的 R 平方

[英]R-squared on test data

我在 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

我得到了 0.43 的 R^2。 然后我尝试使用其余数据预测我的测试数据:

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 值。 有什么简单的计算方法吗?

谢谢

这里有几个问题。 首先,这不是使用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平方的定义。 传统的定义是:

1 - SS.residuals/SS.total

对于训练集和训练集 ONLY

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-sq。 值小于 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.test- 2) 自由度。 如果基于 F 检验的 MSE 有显着差异,则模型不能很好地拟合测试数据。

您是否绘制了 test.y 和 pred.y 与 x 的关系图? 仅此一项就会告诉你很多。

在测试数据上计算 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

如果你想要一个函数, miscTools包有一个rSquared函数。

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

当您在(外)样本上使用 R2 度量时,您会失去对 R2 解释的某些方面:

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

如果你想使用 R,我会推荐函数modelr::rsquare 请注意,这使用来自测试样本的 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM