library(ordinal)
library(extraDistr)
##
## 次のパッケージを付け加えます: 'extraDistr'
## 以下のオブジェクトは 'package:ordinal' からマスクされています:
##
## dgumbel, pgumbel, qgumbel, rgumbel
library(ggplot2)
set.seed(1234)
# inverse logit function
<- function(x) {
inv_logit 1 / (1 + exp(-x))
}
変量効果(random effect)のある順序ロジスティック回帰(ordered logistic regression)です。Rでは以前はdrmパッケージがあったのですが、現在はCRANから消えてしまっています。そのかわりというわけでもないですが、現在はordinalパッケージのclmm
関数を使うことができます。
データ
まずはパッケージの読み込みと乱数シードの設定をおこない、逆ロジット関数を定義します。
模擬データを生成します。説明変数x
は一様乱数から生成します。10個の群があり、これによる変量効果が加わるとします。ロジットスケールでの傾きをbeta
に代入しておきます。
<- 10
N_group <- N_group * 30
N
<- 1.4
beta <- runif(N, -4, 4)
x <- rep(seq_len(N_group), each = N / N_group)
group <- rnorm(N_group, 0, 1) ranef
目的変数y
は5つのカテゴリーからなる順序尺度変数とします。カテゴリー間のカットポイントの値をcp
に代入しておきます。各カテゴリー以上となる確率を計算しrcat
関数でカテゴリー分布の乱数でy
を生成します。
<- c(0, 0.8, 1.7, 2)
cp <- length(cp) + 1
K <- matrix(0, ncol = K, nrow = N)
p 1] <- 1 - inv_logit(beta * x - cp[1] + ranef[group])
p[, for (k in 2:(K - 1)) {
<- inv_logit(beta * x - cp[k - 1]+ ranef[group]) -
p[, k] inv_logit(beta * x - cp[k] + ranef[group])
}<- inv_logit(beta * x - cp[K - 1] + ranef[group])
p[, K] <- sapply(1:N, function(j) rcat(1, p[j, ])) y
最後にデータフレームにまとめます。
<- data.frame(x = x, y = ordered(y), group = factor(group)) data
データをプロットして確認します。
ggplot(data, aes(x = x, y = y)) +
geom_point(aes(colour = group))
ordinal::clmm
によるロジスティック回帰
clmm関数によるロジスティック回帰です。変量効果を含むモデル式の記法は、lme4::lmer
などと同様です。
<- clmm(y ~ x + (1|group), data = data, link = "logit") fit_clmm
結果
結果を確認します。模擬データを生成した値と近い値が推定されました。
summary(fit_clmm)
## Cumulative Link Mixed Model fitted with the Laplace approximation
##
## formula: y ~ x + (1 | group)
## data: data
##
## link threshold nobs logLik AIC niter max.grad cond.H
## logit flexible 300 -242.25 496.51 295(888) 1.39e-04 6.2e+01
##
## Random effects:
## Groups Name Variance Std.Dev.
## group (Intercept) 0.4011 0.6334
## Number of groups: group 10
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## x 1.285 0.113 11.37 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Threshold coefficients:
## Estimate Std. Error z value
## 1|2 -0.2647 0.2670 -0.992
## 2|3 0.6986 0.2699 2.588
## 3|4 1.6881 0.2902 5.816
## 4|5 1.9510 0.2983 6.541
Stanによるロジスティック回帰
ついでに、Stanでもやってみます。CmdStanRを使用しました。
library(cmdstanr)
## This is cmdstanr version 0.8.1
## - CmdStanR documentation and vignettes: mc-stan.org/cmdstanr
## - CmdStan path: /usr/local/cmdstan
## - CmdStan version: 2.36.0
モデル
Stanのモデルです。model/ordered_logistic_regression.stan
に保存しておきます。
data {
int<lower=0> N;
int<lower=1> N_cat;
int<lower=1> N_group;
vector[N] X;
array[N] int<lower=1, upper=N_cat> Y;
array[N] int<lower=1, upper=N_group> G;
}
parameters {
real beta;
ordered[N_cat-1] c;
vector[N_group] epsilon;
real<lower=0> sigma;
}
transformed parameters {
vector[N] eta;
for (n in 1:N)
eta[n] = beta * X[n] + epsilon[G[n]];
}
model {
Y ~ ordered_logistic(eta, c);
epsilon ~ normal(0, sigma);
sigma ~ normal(0, 10);
}
実行
あてはめを実行します。
<- cmdstan_model("model/ordered_logistic_regression.stan")
stan_model <- stan_model$sample(data = list(N = nrow(data),
stan_fit N_cat = K,
N_group = N_group,
X = data$x,
Y = as.numeric(data$y),
G = as.numeric(data$group)),
iter_sampling = 4000, iter_warmup = 4000,
chains = 4, parallel_chains = 4,
refresh = 0)
結果
結果です。だいたい同様の値が得られました。
$print(variables = c("beta", "c", "sigma"))
stan_fit## variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
## beta 1.33 1.32 0.11 0.11 1.14 1.52 1.00 11640 11798
## c[1] -0.29 -0.28 0.34 0.31 -0.83 0.26 1.00 6522 7122
## c[2] 0.71 0.70 0.34 0.31 0.16 1.26 1.00 6679 7132
## c[3] 1.73 1.72 0.36 0.34 1.16 2.32 1.00 7169 8118
## c[4] 2.03 2.02 0.36 0.34 1.45 2.63 1.00 7152 8065
## sigma 0.84 0.79 0.33 0.29 0.40 1.44 1.00 6022 5595