可視化で理解しない「負の二項分布」
匿名知的集団であるホクソエムの親分が可視化で理解する「負の二項分布」 - ほくそ笑むで言及している負の二項分布ですが、シンクロニシティというか、同じ匿名知的集団ホクソエムなので当たり前と言えば当たり前なのですが、私も負の二項分布、特に負の二項分布のパラメータを推定するための関数であるglm.nb関数の挙動を調べる必要があったのでまとめる。数式変形も大体理解しているが、参考テキストや資料によって表記のギリシア文字のぶれがあるので、その辺どれを使うのがいいのか決めてからまとめたい。
ダミーデータの作成
glm.nb関数に食わせるためのダミーデータをrnegbin関数(負の二項分布に従う乱数を生成)作成する。もちろんシードは71だ。
ここで
- 負の二項分布の平均はexp(3.7*x+2)、形状パラメータは10.7
と適当に設定している。このあたりのパラメータの呼称が混乱の原因になるように思うが、ここでは
でいう`shape parameter`を用いて書いた形で議論する(そのほうがおいおいGamma–Poisson mixtureとしての負の二項分布としての見通しがよくなる)。
set.seed(71) size <- 10^4 x <- -(1:size)/size shape <- 10.7 mu <- exp(3.7*x+2) y1 <- sapply(mu, function(m)rnegbin(1, mu=m, theta=shape))
モデルの推定
負の二項分布に従うモデルのフィッティングを行うためにglm.nb関数で推定を実施する。表記法は(g)lm関数などと同様formula式でOK。
> library("MASS") > model_glmnb <- glm.nb(y1 ~ x) > summary(model_glmnb) Call: glm.nb(formula = y1 ~ x, init.theta = 9.775593004, link = log) Deviance Residuals: Min 1Q Median 3Q Max -3.1997 -0.9142 -0.4375 0.5292 3.6430 Coefficients: Estimate Std. Error z value Pr(>|z|) (Intercept) 2.02512 0.01309 154.7 <2e-16 *** x 3.76445 0.03668 102.6 <2e-16 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 (Dispersion parameter for Negative Binomial(9.7756) family taken to be 1) Null deviance: 24389 on 9999 degrees of freedom Residual deviance: 10194 on 9998 degrees of freedom AIC: 29351 Number of Fisher Scoring iterations: 1 Theta: 9.776 Std. Err.: 0.746 2 x log-likelihood: -29345.396
ここまでの使い方は適当にググるとでてくるのだが、問題はこの結果の解釈で、それについてはあまり言及されていない気がするので詳細に書くと。。。
- 切片(Intercept)のはおおよそ: 2.02512
- 特徴量(説明変数)xの係数: 3.76445
- Theta(shape変数の値): 9.776
と読む。この係数(2.02512、3.76445、9.776)は元のダミーデータを設定した際の値がほぼ再現されており、良い推定を与えていることがわかる。
また、ここで推定されているもの(predict, fitted関数でとれるもの)は、(lm関数などの結果から類推できるが、)上でいう負の二項分布の平均値(mu)の推定値になる。実際、モデルオブジェクトに入っている値は以下のようにexp(係数×データ)で計算されるもので、上で書いたmuの定義exp(3.7*x+2)そのものになっている。以下では同じ答え(推定値)を出す三通りの方法+厳密な値(私が指定)を算出している。推定値と厳密な値も当然近しいものになる。
> head(fitted(model_glmnb, x)) 1 2 3 4 5 6 7.574199 7.571348 7.568499 7.565650 7.562803 7.559956 > head(model_glmnb$fitted.values) 1 2 3 4 5 6 7.574199 7.571348 7.568499 7.565650 7.562803 7.559956 > head(as.numeric(exp(cbind(1, x) %*% beta))) [1] 7.574199 7.571348 7.568499 7.565650 7.562803 7.559956 > head(mu) [1] 7.386323 7.383590 7.380859 7.378128 7.375399 7.372671
元のデータの復元
ここから先は上述の親分のブログにあるように、元のデータと同じようにサンプリングされたデータを
- ガンマ分布からサンプリングする
- ポアソン分布からサンプリングする
という手順で再現する。そして、その頻度分布が近しいものですねと、ただしくサンプリングされていますねということをチェックする。
まずは、実際に設定したパラメータを用いてサンプリングする。ここで、scale=m/shapeと設定しているが、これは数式変形をがんばると見えてくるところだ。
lambda <- sapply(mu, function(m){rgamma(1, shape=shape, scale=m/shape)}) y2 <- sapply(lambda, function(l)rpois(1, l)) plot(density(y1), col="red") lines(density(y2), col="blue")
同様の作業を推定したモデルで実行すると
beta <- model_glmnb$coefficients theta <- model_glmnb$theta lambda <- sapply(model_glmnb$fitted.values, function(m){rgamma(1, shape=theta, scale=m/theta)}) y3 <- sapply(lambda, function(l)rpois(1, l)) hist(y1, breaks=0:max(y1, y3), col="red") hist(y3, breaks=0:max(y1, y3), col="blue", add=TRUE)