前から言っているように仕事の業務で、重回帰分析を用いた解析を行っているのですが、ときどき予測値がありえない値になってしまうことがあります。具体的にいうと、マイナスの値にはならないのに、予測値がマイナスの数値をだしてしまうということです。
で、上からマイナスの場合は特定の値、例えば0にするようにということでした(実際にはもっと複雑なことを言われたのですが、ここでは単純に0とします)。まあ、それは想定内の指示だったのですが、ちょっと想定外だったのが、解析したときに予測値がマイナスの値になったものを0にして自由度調整済み決定係数を算出してほしいとのことでした。
普段、自由度調整済み決定係数はsummary関数で求めているわけですが、予測値を変更するとなると自分で求めなければいけません。
というわけで、今回は決定係数、自由度調整済み決定係数の求め方について勉強したことを書いていこうと思います。
使うデータは相変わらず、下記のニコニコ動画から取得したデータ。
nico
まずは、前準備。
> nico <- read.table("http://am-yu.net/wp-content/uploads/2013/11/nico1.txt", sep="\t", header=T) > nico.lm <- lm(mylist~view+comment, data=nico) > summary(nico.lm) Call: lm(formula = mylist ~ view + comment, data = nico) Residuals: Min 1Q Median 3Q Max -105235 -3818 -266 1998 186886 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -1.204e+03 1.519e+02 -7.927 2.52e-15 *** view 2.297e-02 1.741e-04 131.970 < 2e-16 *** comment -2.344e-03 2.819e-04 -8.316 < 2e-16 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 11300 on 8997 degrees of freedom Multiple R-squared: 0.6639, Adjusted R-squared: 0.6638 F-statistic: 8885 on 2 and 8997 DF, p-value: < 2.2e-16 > summary(nico.lm)$r.squared [1] 0.6638783 > summary(nico.lm)$adj.r.squared [1] 0.6638036 > summary(predict(nico.lm)) Min. 1st Qu. Median Mean 3rd Qu. Max. -27260 2564 6489 11350 15820 382100
データを取得して、解析しました。普段、コメント数とマイリスト数から再生数を予測するような解析をしていますが、今回はコメント数と再生数からマイリスト数を予測する解析をしていくことにします。
決定係数は0.6638783、自由度調整済み決定係数は0.6638036となりました。予測値をsummary関数でみてみると、どうやら値の低い予測値はマイナスの値になっているようです。
それでは、以下、自力で二つの決定係数を求めることに。
決定係数
決定係数 – Wikipedia
決定係数と自由度調整済み決定係数の求め方は、上記Wikipediaのページに書いてあります。これを参考に算出してみることに。
どうやら、1から、『残差二乗和』から『実測値と実測値の平均の二乗の和』を割った値を引いたものが決定係数らしい。
残差と実測値の平均を求めることができたら簡単に計算できそうなので下記のようにやってみました。
> nico.lm.rsquared <- 1-sum(residuals(nico.lm)^2)/sum((nico$mylist-mean(nico$mylist))^2) > nico.lm.rsquared [1] 0.6638783
0.6638783とでました。この計算方法であっているようです。
自由度調整済み決定係数
自由度調整済み決定係数の求め方も先ほど記したWikipediaのページに書いてあります。
ただ、正直ぱっと見何をやっているのかよく分かりませんので、もう少し整理してみます。
ここで仮に説明変数の数をp、標本数の数をn、決定係数をR2とすると、自由度調整済み決定係数は下記のようになります。
((n-1)*R2-p)/(n-1-p)
というわけで、自由度調整済み決定係数も求めてみます。なお、説明変数の数はlmオブジェクトのrankというラベルから1を引いたものにあたり、標本数はnrow関数で取得できるので、以下のようにすると自由度調整済み決定係数も求められます。
> nico.lm.adj.rsquared <- ((nrow(nico)-1)*nico.lm.rsquared-(nico.lm$rank-1))/((nrow(nico)-1)-(nico.lm$rank-1)) > nico.lm.adj.rsquared [1] 0.6638036
というわけで、自由度調整済み決定係数も求めることができました。
では、試しに、予測値がマイナスになっているものは0にして決定係数を求めてみようと思います。
まず、予測値がマイナスになっているものは0にしたベクトルを作成。
> nico.mylist.predict <- ifelse(predict(nico.lm)<0, 0, predict(nico.lm)) > summary(nico.mylist.predict) Min. 1st Qu. Median Mean 3rd Qu. Max. 0 2564 6489 11430 15820 382100
つづいて、実測値と上記で作成した予測値の二つを含んだデータフレームを作成。
> nico.dataframe <- data.frame(mylist=nico$mylist, predict=nico.mylist.predict) > head(nico.dataframe) mylist predict 1 138031 243265.56 2 82675 88473.21 3 37145 84453.03 4 72711 83595.51 5 2049 74470.67 6 65855 72099.15
5番目の予測値がおかしい気がしますが、他はまああってそうです。
では、決定係数を求めてみることに。
> nico.dataframe.rsquared <- 1-sum((nico.dataframe$mylist-nico.dataframe$predict)^2)/sum((nico.dataframe$mylist-mean(nico.dataframe$mylist))^2) > nico.dataframe.rsquared [1] 0.664791
決定係数は0.664791となり、少し増えました。
ここまでくれば後は同じなのですが、一応自由度調整済み決定係数も求めると下記のようになりました。
> nico.dataframe.adj.rsquared <- ((nrow(nico.dataframe)-1)*nico.dataframe.rsquared-(nico.lm$rank-1))/((nrow(nico.dataframe)-1)-(nico.lm$rank-1)) > nico.dataframe.adj.rsquared [1] 0.6647165
もちろん、自由度調整済み決定係数も増えています。
はたしてこれは、自由度調整済み決定係数といってしまっていいのかという疑問はありますが・・・。
実は、重回帰分析のやり方についてもlm関数を使わないでできないものかと勉強がてら調べてみたのですが、まだちょっとよく分かってません。想像以上に複雑でして・・・。
重回帰分析の仕組みをもっと分かるようになれば、何か新しい発見がある気もするのだけれども・・・。
コメント