web-dev-qa-db-ja.com

テストデータの決定係数

約11000の観測値と143の変数を含むデータセットの75%に線形回帰モデルを当てはめます。

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値を計算したいと思います。それを計算する簡単な方法はありますか?

ありがとうございました

9
H_A

ここにはいくつかの問題があります。まず、これはlm(...)を使用する良い方法ではありません。 lm(...)は、データフレームで使用することを目的としており、式はdfの列を参照します。したがって、データが2つのベクトル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(...)を使用すると、たとえば、行列の乗算をすべて行わずに予測を生成できます。

2番目の問題は、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
_

ただし、これはテストセットでは機能しません(たとえば、モデルから予測を行う場合)。

_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未満の値(この方法で定義した場合)。

たとえば、モデルがテストセットで非常に貧弱な予測子である場合、残差は実際にはテストセットの全変動よりも大きくなる可能性があります。これは、トレーニングセットから派生したモデルを使用するよりも、平均を使用してテストセットがより適切にモデル化されていると言うことと同じです。

(この例のように)ランダムなサンプルを取得するのではなく、データの最初の4分の3をトレーニングセットとして使用していることに気付きました。 yxへの依存性が非線形であり、xが正しい場合、テストセットで負のR-sqを取得できます。

以下のOPのコメントに関して、テストセットでモデルを評価する1つの方法は、モデル内とモデル外の平均二乗誤差(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-)のF分布を持つ必要があります。 2)自由度。 F検定に基づいてMSEが大幅に異なる場合、モデルはテストデータにうまく適合しません。

Test.yとpred.yとxをプロットしましたか?これだけで多くのことがわかります。

21
jlhoward

ベースラインとは何かを覚えておかなければならないので、テストデータのR-2乗を計算するのは少し難しいです。ベースライン予測は、トレーニングデータの平均です。

したがって、上記の@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

5
dmi3kno

関数が必要な場合は、miscToolsパッケージにrSquared関数があります。

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

(アウトオブ)サンプルでR2メジャーを使用すると、R2の解釈の特定の側面が失われます。

  • 等価SSR合計=説明されたSSR + SSRエラー
  • R2がyと予測されたyの間の相関の2乗に等しいという事実
  • 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
0
Matifou