测试数据的R平方

hsvhsicv  于 2024-01-03  发布在  其他
关注(0)|答案(5)|浏览(99)

我在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值,有什么简单的方法吗?
谢谢你

yzuktlbb

yzuktlbb1#

这里有几个问题。首先,这不是使用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.残差/SS.总
对于训练集,* 和仅训练集 *,
SS.total = SS.回归+ SS.残差
所以
SS.回归= SS.total- SS.残差,
并且因此
R.sq = SS.回归/SS.总
所以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)


如果我们假设训练集和测试集都是正态分布,具有相同的方差,并且均值遵循相同的模型公式,那么比率应该具有F分布,自由度为(n.train-2)和(n.test-2)。如果基于F检验,MSE显著不同,那么模型不能很好地拟合测试数据。
你有没有画出你的test.y和pred.y与x的关系图??单凭这一点就能告诉你很多。

ctzwtxfj

ctzwtxfj2#

在测试数据上计算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平方是在相同的数据集上计算的,模型是在该数据集上训练的,因为它计算

yy <- y - mean(y)


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

cgh8pdjw

cgh8pdjw3#

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

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

字符串

bbuxkriu

bbuxkriu4#

当您在样本(外)上使用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

6qftjkof

6qftjkof5#

model_1 = sm.OLS(df['ExpirationMonth'], 
                 sm.add_constant(df[['Salerank', 
                                     'X2013USSales', 
                                     'X2013WorldSales', 
                                     'ProfitMargin', 
                                     'NumStores', 
                                     'RewardSize']])).fit()

r_squared_1 = model_1.rsquared
print(f"Model 1 R-squared: {r_squared_1}")

字符串

相关问题