Chapter 6 로지스틱 회귀분석
로지스틱 회귀분석(logistic regression)은 종속변수가 통상 2개의 범주(있음/없음, 불량/양호, 합격/불합격 등)를 다루는 모형을 지칭하나, 3개 이상의 범주를 다루기도 한다. 후자의 경우는 다시 서열형(ordinal) 데이터와 명목형(nominal) 데이터인 경우에 따라 서로 다른 모형이 사용된다.
6.1 필요 R 패키지 설치
본 장에서 필요한 R 패키지들은 아래와 같다.
package | version |
---|---|
tidyverse | 1.3.1 |
stats | 4.1.3 |
nnet | 7.3-16 |
MASS | 7.3-54 |
VGAM | 1.1-5 |
6.2 이분 로지스틱 회귀모형
6.2.1 기본 R 스크립트
<- tribble(
train_df ~id, ~x1, ~x2, ~x3, ~y,
1, 0, 8, 2, "우수",
2, 1, 7, 1, "우수",
3, 0, 9, 0, "우수",
4, 1, 6, 4, "우수",
5, 1, 8, 2, "우수",
6, 0, 7, 3, "우수",
7, 0, 7, 0, "보통",
8, 1, 6, 1, "보통",
9, 0, 7, 2, "보통",
10, 0, 8, 1, "보통",
11, 0, 5, 2, "보통",
12, 1, 8, 0, "보통",
13, 0, 6, 3, "보통",
14, 1, 7, 2, "보통",
15, 0, 6, 1, "보통"
%>%
) mutate(y = factor(y, levels = c("보통", "우수")))
::kable(train_df, booktabs = TRUE,
knitralign = c('r', 'r', 'r', 'r', 'r'),
col.names = c('객체번호', '아침식사여부($x_1$)', '수면시간($x_2$)', '서클활동시간($x_3$)', '범주(y)'),
caption = '우수/보통 학생에 대한 설문조사 결과')
객체번호 | 아침식사여부(\(x_1\)) | 수면시간(\(x_2\)) | 서클활동시간(\(x_3\)) | 범주(y) |
---|---|---|---|---|
1 | 0 | 8 | 2 | 우수 |
2 | 1 | 7 | 1 | 우수 |
3 | 0 | 9 | 0 | 우수 |
4 | 1 | 6 | 4 | 우수 |
5 | 1 | 8 | 2 | 우수 |
6 | 0 | 7 | 3 | 우수 |
7 | 0 | 7 | 0 | 보통 |
8 | 1 | 6 | 1 | 보통 |
9 | 0 | 7 | 2 | 보통 |
10 | 0 | 8 | 1 | 보통 |
11 | 0 | 5 | 2 | 보통 |
12 | 1 | 8 | 0 | 보통 |
13 | 0 | 6 | 3 | 보통 |
14 | 1 | 7 | 2 | 보통 |
15 | 0 | 6 | 1 | 보통 |
Table 6.1와 같이 세 개의 독립변수 \(x_1\), \(x_2\), \(x_3\)와 이분형 종속변수 \(y\)의 관측값(보통 = 0, 우수 = 1)으로 이루어진 15개의 학습표본을 train_df
라는 data frame에 저장한다.
아래와 같이 glm
함수를 이용하여 로지스틱 회귀모형을 간편하게 추정할 수 있다.
<- glm(y ~ x1 + x2 + x3, family = binomial(link = "logit"), data = train_df)
glm_fit
::kable(
knitr%>% broom::tidy(),
glm_fit booktabs = TRUE,
caption = "위 우수/보통 학생 설문조사 데이터에 대한 Logistic Regression 결과"
# caption = "Table \\@ref(tab:binary-logistic-reg-train-data)에 대한 Logistic Regression 결과"
)
term | estimate | std.error | statistic | p.value |
---|---|---|---|---|
(Intercept) | -30.510836 | 18.018256 | -1.693329 | 0.0903929 |
x1 | 2.031278 | 1.983692 | 1.023989 | 0.3058406 |
x2 | 3.470671 | 2.074978 | 1.672631 | 0.0944000 |
x3 | 2.414387 | 1.396372 | 1.729043 | 0.0838015 |
Table 6.2은 추정된 회귀계수 추정치 estmate
과 그 표준오차 std.error
, 표준화(standardized)된 회귀계수값 statistic
(= estmate
/ std.error
), 그리고 귀무가설 \(H_0\): statistic
= 0 에 대한 유의확률 p.value
를 보여준다.
6.2.2 회귀모형
이분 로지스틱 회귀모형은 종속변수가 2가지 범주를 취하는 경우에 사용된다.
\(N\)개의 객체로 이루어진 학습데이터 \(\{(\mathbf{x}_i, y_i)\}_{i = 1, \cdots, N}\)를 아래와 같이 정의하자.
- \(\mathbf{x}_i \in \mathbb{R}^p\): \(p\)개의 독립변수로 이루어진 벡터 (\(\mathbf{x}_i = [x_{i1} \, x_{i2} \, \cdots \, x_{ip}]^\top\))
- \(y_i\): 0 혹은 1의 값을 갖는 이분형 지시변수 (indicator variable)
\(\mathbf{x}_i\) 관측값을 이용하여 \(y_i\)의 기대값 \(P_i\)을 추정하는 모형을 아래와 같이 로지스틱 함수로 정의하자.
\[\begin{eqnarray} P_i &=& P(y_i = 1 \,|\, \mathbf{x}_i)\\ &=& E[y_i | \mathbf{x}_i]\\ &=& \frac{\exp(\beta_0 + \boldsymbol\beta^\top \mathbf{x}_i)}{1 + \exp(\beta_0 + \boldsymbol\beta^\top \mathbf{x}_i)} \tag{6.1} \end{eqnarray}\]
여기에서 \(\boldsymbol\beta \in \mathbb{R}^{p}\)는 \(\mathbf{x}_i\)와 동일한 차원의 벡터이다 (\(\boldsymbol\beta = [\beta_1 \, \beta_2 \, \cdots \, \beta_p]^\top\)).
식 (6.1)는 모든 \(\mathbf{x}_i\)값에 대해 0에서 1 사이의 값을 갖게 되므로 각 범주에 속할 확률을 추정하는 데 적합한 반면, 변수 \(\mathbf{x}\) 및 계수들에 대해 선형이 아니므로 추정이 어렵다. 그러나 아래와 같이 로짓(logit) 변환을 통해 선형회귀식으로 변환할 수 있다.
\[\begin{eqnarray} logit(P_i) &=& \ln \left[ \frac{P_i}{1 - P_i} \right]\\ &=& \ln(\exp(\beta_0 + \boldsymbol\beta^\top \mathbf{x}_i))\\ &=& \beta_0 + \boldsymbol\beta^\top \mathbf{x}_i \tag{6.2} \end{eqnarray}\]
식 (6.2)에서 확률 \(P_i\)는 직접적으로 관측되는 것이 아니고 0 또는 1을 갖는 \(y_i\)가 관측되므로, \(P_i\)를 일종의 잠재변수(latent variable)로 해석할 수 있다.
\[\begin{equation} y_i = \begin{cases} 1 & \text{ if } \beta_0 + \boldsymbol\beta^\top \mathbf{x}_i + \varepsilon_i > 0 \\ 0 & \text{ otherwise } \end{cases} \tag{6.3} \end{equation}\]
식 (6.3)에서 \(\varepsilon_i\)는 표준로지스틱분포(standard logistic distribution)을 따른다.
6.2.3 회귀계수 추정
로지스틱 모형에서 회귀계수의 추정을 위해서 주로 최우추정법(maximum likelihood estimation)이 사용된다. \(N\)개의 객체로 이루어진 학습데이터에 대해 우도함수는 다음과 같다.
\[\begin{equation*} L = \prod_{i = 1}^{N} P_i^{y_i} (1 - P_i)^{1 - y_i} \end{equation*}\]
그리고 우도함수에 자연로그를 취하면 아래와 같이 전개된다.
\[\begin{eqnarray} \log L &=& \sum_{i = 1}^{N} y_i \log P_i + \sum_{i = 1}^{N} (1 - y_i) \log (1 - P_i)\\ &=& \sum_{i = 1}^{N} y_i \log \frac{P_i}{1 - P_i} + \sum_{i = 1}^{N} \log (1 - P_i)\\ &=& \sum_{i = 1}^{N} y_i (\beta_0 + \boldsymbol\beta^\top \mathbf{x}_i) - \sum_{i = 1}^{N} \log (1 + \exp (\beta_0 + \boldsymbol\beta^\top \mathbf{x}_i) )\\ &=& \sum_{i = 1}^{N} y_i \left(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij} \right) - \sum_{i = 1}^{N} \log \left(1 + \exp\left(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij}\right)\right) \tag{6.4} \end{eqnarray}\]
식 (6.4)을 각 회귀계수 \(\beta_0, \beta_1, \cdots, \beta_p\)에 대해 편미분하여 최적해를 얻는다. 이를 위해 주로 뉴턴-랩슨 알고리즘(Newton-Raphson algorithm)이나 quasi-Newton 알고리즘이 사용되나 (전치혁 2012), 본 장에서는 우선 안정성은 떨어지지만 보다 간편한 방법으로 경사하강법(gradient descent)을 소개한다.
6.2.3.1 경사하강법
식 (6.1)과 \(P(y_i = 0 \,|\, \mathbf{x}_i) = 1 - P_i\), 그리고
\[\begin{equation*} \frac{\exp(z)}{1 + \exp(z)} = \frac{1}{1 + \exp(-z)} \end{equation*}\]
임을 고려하면 아래와 같이 범주확률모형을 정의할 수 있다.
\[\begin{equation*} P(y = y_i \,|\, \mathbf{x}_i, \beta_0, \boldsymbol\beta) = \frac{1}{1 + \exp\left((1 - 2y_i)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)} \end{equation*}\]
이에 따라 로그우도함수 (6.4)는 아래와 같이 정리된다.
\[\begin{equation*} \log \prod_{i = 1}^{N} P(y = y_i \,|\, \mathbf{x}_i, \beta_0, \boldsymbol\beta) = - \sum_{i = 1}^{N} \log \left(1 + \exp\left((1 - 2y_i)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)\right) \end{equation*}\]
위 로그우도함수를 최대화하는 문제는 아래 함수를 최소화하는 문제와 동일하다.
\[\begin{equation} f(\beta_0, \boldsymbol\beta) = \sum_{i = 1}^{N} \log \left(1 + \exp\left((1 - 2y_i)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)\right) \tag{6.5} \end{equation}\]
경사하강법에 따라 아래의 과정을 통해 회귀계수를 추정할 수 있다.
- 임의의 값으로 \(\beta_0, \beta_1, \cdots, \beta_j\)의 초기 추정값을 설정한다.
- 식 (6.5)을 각 회귀변수에 대해 편미분한 미분값을 구한다.
- 2의 값에 학습률(step size)을 곱한 만큼 회귀계수 추정값을 이동시킨다. 방향은 미분값의 반대방향.
- 수렴할 때까지 2-3의 과정을 반복한다.
여기에서 식 (6.5)의 각 회귀변수에 대한 편미분식은 아래와 같다.
\[\begin{eqnarray*} \frac{\partial f}{\partial \beta_0} &=& \sum_{i = 1}^{N} (1 - 2y_i) \frac{\exp\left((1 - 2y_i)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)}{1 + \exp\left((1 - 2y_i)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)}\\ &=& \sum_{i = 1}^{N} \frac{1 - 2y_i}{1 + \exp\left((2y_i - 1)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)} \end{eqnarray*}\]
\[\begin{eqnarray*} \frac{\partial f}{\partial \beta_j} &=& \sum_{i = 1}^{N} (1 - 2y_i)x_{ij} \frac{\exp\left((1 - 2y_i)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)}{1 + \exp\left((1 - 2y_i)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)}\\ &=& \sum_{i = 1}^{N} \frac{(1 - 2y_i)x_{ij}}{1 + \exp\left((2y_i - 1)(\beta_0 + \sum_{j = 1}^{p} \beta_j x_{ij})\right)} \end{eqnarray*}\]
따라서, 회귀계수 추정값을 이동시키는 함수 update_beta
를 아래와 같이 구현할 수 있다.
<- function(x, y, beta0 = 0, beta = rep(0, dim(x)[2]), alpha = 0.01) {
update_beta # 변미분식의 분모
<- 1 + exp((2 * y - 1) * (beta0 + (x %*% beta)))
denominator
# intercept 이동량 계산
<- 1 - 2 * y
beta0_numerator = sum(beta0_numerator / denominator)
beta0_update
# intercept 외 회귀계수 이동량 계산
<- sweep(x, MARGIN = 1, STATS = 1 - 2 * y, FUN = "*")
beta_numerator = apply(beta_numerator, MARGIN = 2,
beta_update function(x) sum(x / denominator))
# 회귀계수 이동
<- beta0 - alpha * beta0_update
beta0 <- beta - alpha * beta_update
beta
return(list(beta0 = beta0, beta = beta))
}
위의 함수를 이용하여 아래 estimate_beta
처엄 수렴할 때까지 회귀계수 추정값을 계속 이동시킨다. 본 경사하강법은 학습률 파라미터 alpha
값에 따라 민감한 단점이 있으며, 특히 alpha
값을 크게 설정할 경우에는 추정값이 수렴하지 않고 오히려 실제값에서 계속 멀어지는 현상이 발생하기도 한다. 이러한 단점을 보완하기 위한 여러 방법이 있으나, 본 장에서 자세한 설명은 생략하기로 한다.
<- function(x, y,
caltculate_loglik beta0 = 0,
beta = rep(0, dim(x)[2])) {
sum(y * (beta0 + (x %*% beta))) -
sum(log(1 + exp(beta0 + (x %*% beta))))
}
<- function(x, y,
estimate_beta beta0 = 0,
beta = rep(0, dim(x)[2]),
alpha = 0.01,
conv_threshold = 1e-5,
max_iter = 1e+5) {
<- beta0
new_beta0 <- beta
new_beta <- FALSE
conv
<- 0
i_iter while(i_iter < max_iter) {
<- update_beta(x, y, new_beta0, new_beta, alpha)
res
if(abs(caltculate_loglik(x, y, beta0, beta)
- caltculate_loglik(x, y, res$beta0, res$beta))
< conv_threshold) {
<- TRUE
conv break
}
<- res$beta0
new_beta0 <- res$beta
new_beta
<- i_iter + 1
i_iter
}
return(list(conv = conv, beta0 = new_beta0, beta = new_beta))
}
위에서 정의한 함수를 이용하여 Table 6.1의 학습표본에 대한 로지스틱 회귀모형을 추정해보자.
<- estimate_beta(train_df[, c("x1", "x2", "x3")] %>% as.matrix(),
res $y %>% as.numeric() - 1,
train_dfalpha = 0.015,
conv_threshold = 1e-6)
print(res)
## $conv
## [1] FALSE
##
## $beta0
## [1] -30.39189
##
## $beta
## x1 x2 x3
## 2.022808 3.457019 2.405969
위 회귀계수 추정값은 R 함수 glm
을 이용한 추정값(Table 6.2)과 유사함을 볼 수 있다.
6.2.3.2 반복재가중최소제곱법
R의 glm
함수는 반복재가중최소제곱법(iteratively rewighted least squares; IRLS 혹은 IWLS)을 사용한다. 이는 선형회귀식
\[\begin{equation*} logit(y_i) = \beta_0 + \boldsymbol\beta^\top \mathbf{x}_i + \varepsilon_i \end{equation*}\]
을 추정하는 방법인데, 여기에서 \(y_i\)는 0 혹은 1이므로, \(logit(y_i)\)는 \(-\infty\) 혹은 \(\infty\)가 되어 회귀식을 추정할 수 없다. 따라서, 식 (6.1)에 설명된 로지스틱 함수
\[\begin{equation*} P = \frac{\exp(\beta_0 + \boldsymbol\beta^\top \mathbf{x})}{1 + \exp(\beta_0 + \boldsymbol\beta^\top \mathbf{x})} \end{equation*}\]
와 테일러 급수(Taylor series)를 이용하여 \(logit(y)\)에 대한 근사함수를 아래와 같이 얻는다.
\[\begin{eqnarray*} g(y) &=& logit(P) + (y - P) \frac{\partial logit(P)}{\partial P}\\ &=& \log \frac{P}{1 - P} + (y - P) \left( \frac{1}{P} + \frac{1}{1 - P} \right) \end{eqnarray*}\]
그리고 아래 선형회귀식을 추정한다.
\[\begin{equation*} g(y_i) = \beta_0 + \boldsymbol\beta^\top \mathbf{x}_i + \varepsilon_i \end{equation*}\]
여기에서 오차항 \(\varepsilon_i\)의 분산은 추정된 확률 \(P_i\)에 따라 다르므로, 통상적 최소자승법(ordinary least squares; OLS) 대신 오차항의 분산이 동일해지도록 객체마다 가중치를 부여하는 가중최소자승법(weighted least squares; WLS)을 사용한다. 로지스틱 회귀모형에서 각 객체의 가중치는
\[\begin{equation*} w_i = P_i (1 - P_i) \end{equation*}\]
가중치와 회귀계수 추정값은 상호 영향을 미치므로, 수렴할 때까지 반복적으로 가중치와 회귀계수 추정값을 변화시키면서 최종 추정값을 찾아가는 방법이다.
우선 회귀계수 추정값이 주어졌을 때 각 객체에 대한 확률값 \(P_i\)와 가중치 \(w_i\)를 구하는 함수 calculate_weight
를 아래와 같이 구현해보자.
<- function(x, beta0 = 0,
calculate_weight beta = rep(0, dim(x)[2])) {
# 각 객체의 y값이 1일 확률
<- (1 + exp(- beta0 - (x %*% beta)))^(-1) %>% drop()
P
# 가중치 계산
<- P * (1 - P)
w
return(list(P = P, w = w))
}
그리고 확률추정값과 가중치가 주어졌을 때 회귀계수를 구하는 함수 calculate_beta
를 아래와 같이 구현해보자. 여기서 회귀계수를 구하는 부분은 R의 선형회귀분석함수 lm
을 사용한다.
<- function(x, y, P, w) {
calculate_beta # 추정확률값이 0 이나 1인 경우
# 여전히 logit 함수가 정의되지 않으므로 회귀계수 결정에서 제외
<- 1/P + 1/(1 - P)
logit_derivative <- !is.nan(logit_derivative)
is_good
# 모든 객체에 대한 추정확률이 0 이나 1인 경우 회귀계수 추정 불가능
if(all(!is_good)) return(NULL)
# 테일러 급수 계산
<- log(P[is_good]) -
g_y log(1 - P[is_good]) +
- P[is_good]) * logit_derivative
(y[is_good]
# 가중치최소자승법을 이용한 추정
<- bind_cols(as_tibble(x) %>%
df `colnames<-`(colnames(x)),
tibble(g_y = g_y))
lm(g_y ~ ., data = df, subset = is_good, weights = w)
}
위에서 정의한 두 함수 calculate_weight
과 calculate_beta
를 반복적으로 사용하여 Table 6.1의 학습표본에 대한 로지스틱 회귀모형을 추정해보자. 모든 객체의 가중치 변화량이 1/10000 보다 작을 경우 모형추정이 수렴한 것으로 간주하도록 하자.
<- train_df[, c("x1", "x2", "x3")] %>% as.matrix()
X <- train_df$y %>% as.numeric() - 1
y
<- calculate_weight(X)
weight for(i in 1:10) {
<- calculate_beta(X, y, weight$P, weight$w)
wls_fit
if(is.null(wls_fit)) {break}
<- calculate_weight(x = X,
new_weight beta0 = coef(wls_fit)[1],
beta = coef(wls_fit)[-1])
if(max(abs(new_weight$w - weight$w)) < 1e-4) {break}
<- new_weight
weight
}
coef(wls_fit)
## (Intercept) x1 x2 x3
## -30.510837 2.031278 3.470671 2.414387
위 스크립트를 실행시킨 결과 7번째 반복수행에서 결과가 수렴하였으며, 해당 결과는 glm
함수를 사용하였을 때의 결과 (Table 6.2)과 매우 근사함을 확인할 수 있다.
6.3 명목 로지스틱 회귀모형
6.3.1 기본 R 스크립트
<- tribble(
train_df ~id, ~x1, ~x2, ~y,
1, 0.09, 5.02, 1,
2, 0.1, 5.01, 1,
3, 0.12, 4.94, 1,
4, 0.12, 5.12, 1,
5, 0.12, 5.03, 1,
6, 0.12, 4.94, 2,
7, 0.1, 5.13, 2,
8, 0.1, 4.87, 1,
9, 0.1, 5.13, 2,
10, 0.11, 4.94, 3,
11, 0.11, 4.93, 3,
12, 0.09, 5.02, 3,
13, 0.1, 5.01, 3,
14, 0.09, 4.94, 3,
15, 0.1, 5.12, 2,
16, 0.12, 4.93, 2,
17, 0.1, 5, 1,
18, 0.09, 5.01, 3
%>%
) mutate(y = factor(y, levels = c(1, 2, 3)))
::kable(train_df, booktabs = TRUE,
knitralign = c('r', 'r', 'r', 'r'),
col.names = c('객체번호', '$x_1$', '$x_2$', '불량범주($y$)'),
caption = '공정변수-불량 종류 데이터')
객체번호 | \(x_1\) | \(x_2\) | 불량범주(\(y\)) |
---|---|---|---|
1 | 0.09 | 5.02 | 1 |
2 | 0.10 | 5.01 | 1 |
3 | 0.12 | 4.94 | 1 |
4 | 0.12 | 5.12 | 1 |
5 | 0.12 | 5.03 | 1 |
6 | 0.12 | 4.94 | 2 |
7 | 0.10 | 5.13 | 2 |
8 | 0.10 | 4.87 | 1 |
9 | 0.10 | 5.13 | 2 |
10 | 0.11 | 4.94 | 3 |
11 | 0.11 | 4.93 | 3 |
12 | 0.09 | 5.02 | 3 |
13 | 0.10 | 5.01 | 3 |
14 | 0.09 | 4.94 | 3 |
15 | 0.10 | 5.12 | 2 |
16 | 0.12 | 4.93 | 2 |
17 | 0.10 | 5.00 | 1 |
18 | 0.09 | 5.01 | 3 |
Table 6.3와 같이 두 개의 독립변수 \(x_1\), \(x_2\)에 따라 세 종류의 불량 (\(y = 1, 2, 3\))$이 발생함을 알았다면, 아래와 같이 nnet
패키지의 multinom
함수를 이용하여 공정변수에 따른 불량 종류를 분류하기 위한 로지스틱 회귀모형을 간편하게 추정할 수 있다.
<- nnet::multinom(
multinom_fit ~ x1 + x2,
y data = train_df,
maxit = 1000)
## # weights: 12 (6 variable)
## initial value 19.775021
## iter 10 value 17.825831
## iter 20 value 16.489924
## iter 30 value 16.116751
## iter 40 value 16.044223
## iter 50 value 16.025259
## iter 60 value 16.024629
## iter 70 value 16.016395
## final value 16.015185
## converged
::kable(
knitr%>% broom::tidy(exponentiate = FALSE),
multinom_fit booktabs = TRUE,
caption = '위 공정변수-불량종류 데이터에 대한 Logistic Regression 결과'
# caption = 'Table \\@ref(tab:nominal-logistic-reg-train-data)에 대한 Logistic Regression 결과'
)
y.level | term | estimate | std.error | statistic | p.value |
---|---|---|---|---|---|
2 | (Intercept) | -53.924661 | 45.402992 | -1.1876896 | 0.2349557 |
2 | x1 | 31.545749 | 62.162158 | 0.5074751 | 0.6118215 |
2 | x2 | 9.992311 | 8.479305 | 1.1784352 | 0.2386231 |
3 | (Intercept) | 64.191145 | 57.282533 | 1.1206059 | 0.2624556 |
3 | x1 | -101.817613 | 65.516143 | -1.5540844 | 0.1201643 |
3 | x2 | -10.810865 | 10.915881 | -0.9903795 | 0.3219887 |
multinom
함수는 범주 y
의 값 1, 2, 3중 첫번째 값인 1을 기준범주(reference category)로 사용한다.
6.3.2 기준범주 로짓모형
종속변수가 셋 이상의 범주를 갖고 있으나 자연스러운 순서가 없는 경우, 기준범주 로짓모형이 널리 사용된다.
\(N\)개의 객체로 이루어진 학습데이터 \(\{(\mathbf{x}_i, y_i)\}_{i = 1, \cdots, N}\)를 아래와 같이 정의하자.
- \(\mathbf{x}_i \in \mathbb{R}^p\): \(p\)개의 독립변수로 이루어진 벡터 (\(\mathbf{x}_i = [x_{i1} \, x_{i2} \, \cdots \, x_{ip}]^\top\))
- \(J\): 범주 수
- \(y_i\): 객체 \(i\)에 대한 종속변수값 \(\in \{1, 2, \cdots, J\}\)
각 객체 \(i\)가 각 범주에 해당할 확률을 \(\pi_{ij}\)라 하자.
\[\begin{equation*} \pi_{ij} = P(y_i = j \, | \, \mathbf{x}_i), \, j = 1, \cdots, J \end{equation*}\]
이 때, 모든 \(i\)에 대하여
\[\begin{equation*} \sum_{j = 1}^{J} \pi_{ij} = 1 \end{equation*}\]
이 성립한다. 여기에서 범주 1을 기준 범주(reference category 혹은 baseline category)로 간주하여 범주별로 다음과 같은 회귀모형을 정의한다 (교재 (전치혁 2012)에는 범주 \(J\)를 기준 범주로 간주).
\[\begin{equation*} \log \left( \frac{\pi_{ij}}{\pi_{i1}} \right) = \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i, \, j = 2, \cdots, J \end{equation*}\]
이를 \(\pi_{ij}\)에 대해 풀면, 아래와 같은 해가 얻어진다 (Czepiel 2002).
\[\begin{equation} \begin{split} \pi_{ij} &= \frac{\exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)}{1 + \sum_{j = 2}^{J} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)}, \, j = 2, \cdots, J\\ \pi_{i1} &= \frac{1}{1 + \sum_{j = 2}^{J} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)} \end{split} \tag{6.6} \end{equation}\]
위 모수 추정을 위해 최우추정법을 사용해보자. 우선, 종속변수를 변환한 지시변수를 아래와 같이 정의한다.
\[\begin{equation*} v_{ij} = \begin{cases} 1 & \text{ if } y_i = j\\ 0 & \text{ otherwise } \end{cases} \end{equation*}\]
이를 이용해 우도 함수를
\[\begin{eqnarray*} L &=& \prod_{i = 1}^{n} \prod_{j = 1}^{J} \left( \pi_{ij} \right)^{v_{ij}} \\ &=& \prod_{i = 1}^{n} \pi_{i1}^{1 - \sum_{j = 2}^{J} v_{ij}} \prod_{j = 2}^{J} \left( \pi_{ij} \right)^{v_{ij}}\\ &=& \prod_{i = 1}^{n} \frac{\pi_{i1}}{\pi_{i1}^{\sum_{j = 2}^{J} v_{ij}}} \prod_{j = 2}^{J} \left( \pi_{ij} \right)^{v_{ij}}\\ &=& \prod_{i = 1}^{n} \frac{\pi_{i1}}{\prod_{j = 2}^{J} \pi_{i1}^{v_{ij}}} \prod_{j = 2}^{J} \left( \pi_{ij} \right)^{v_{ij}}\\ &=& \prod_{i = 1}^{n} \pi_{i1} \prod_{j = 2}^{J} \left( \frac{\pi_{ij}}{\pi_{i1}} \right)^{v_{ij}} \end{eqnarray*}\]
와 같이 표현할 수 있으며, 여기에 식 (6.6)을 이용하면 아래와 같이 정리할 수 있다.
\[\begin{eqnarray*} L &=& \prod_{i = 1}^{n} \frac{1}{1 + \sum_{j = 2}^{J} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)} \prod_{j = 2}^{J} \left( \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right) \right)^{v_{ij}}\\ &=& \prod_{i = 1}^{n} \left( 1 + \sum_{j = 2}^{J} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right) \right)^{-1} \prod_{j = 2}^{J} \left( \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right) \right)^{v_{ij}} \end{eqnarray*}\]
이에 따라 로그 우도함수는 다음과 같이 정의된다.
\[\begin{equation} \log L = \sum_{i = 1}^{n} \left( - \log \left( 1 + \sum_{j = 2}^{J} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right) \right) + \sum_{j = 2}^{J} v_{ij} \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right) \right) \tag{6.7} \end{equation}\]
식 (6.7)을 각 계수에 대해 미분하면 아래와 같이 정리된다.
\[\begin{equation} \begin{split} \frac{\partial \log L}{\partial \beta_{0,j}} &= \sum_{i = 1}^{n} v_{ij} - \frac{\exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)}{1 + \sum_{j = 2}^{J} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)}\\ \frac{\partial \log L}{\partial \beta_{k,j}} &= \sum_{i = 1}^{n} v_{ij} x_{ik} - \frac{x_{ik} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)}{1 + \sum_{j = 2}^{J} \exp \left( \beta_{0,j} + \boldsymbol\beta_{j}^\top \mathbf{x}_i \right)}, \, k = 1, \cdots, p \end{split} \tag{6.8} \end{equation}\]
따라서, 명목 로지스틱 회귀분석은 식 (6.8)이 표현하는 \((J - 1) \times (p + 1)\)개의 미분식을 모두 0으로 만드는 계수값을 찾는 문제가 된다. 이에 대한 closed form solution은 존재하지 않으므로, 각종 알고리즘을 이용하여 해를 찾아야 한다. Newton-Raphson method에 의해 해를 찾는 방법은 Czepiel (2002) 에 보다 자세하게 설명되어 있다.
Table 6.3의 학습데이터에 대해 명목 로지스틱 회귀모형을 학습하여 범주를 추정한 결과는 아래와 같다.
<- nnet::multinom(
multinom_fit ~ x1 + x2,
y data = train_df,
maxit = 1000)
## # weights: 12 (6 variable)
## initial value 19.775021
## iter 10 value 17.825831
## iter 20 value 16.489924
## iter 30 value 16.116751
## iter 40 value 16.044223
## iter 50 value 16.025259
## iter 60 value 16.024629
## iter 70 value 16.016395
## final value 16.015185
## converged
<- predict(multinom_fit, train_df, type = "probs") %>%
predict_df as_data_frame() %>%
`colnames<-`(c("p1", "p2", "p3")) %>%
mutate(pred_class = predict(multinom_fit, train_df, type = "class"))
## Warning: `as_data_frame()` was deprecated in tibble 2.0.0.
## Please use `as_tibble()` instead.
## The signature and semantics have changed, see `?as_tibble`.
bind_cols(train_df, predict_df) %>%
select(-x1, -x2) %>%
::kable(
knitrbooktabs = TRUE,
align = c('r', 'r', 'r', 'r', 'r', 'r'),
col.names = c('객체번호', '불량범주 $y_i$',
'$\\pi_{i1}$', '$\\pi_{i2}$', '$\\pi_{i3}$', '추정범주 $\\hat{y}_i$'),
caption = '명목 로지스틱 회귀모형 범주 추정 결과',
digits = 3
)
객체번호 | 불량범주 \(y_i\) | \(\pi_{i1}\) | \(\pi_{i2}\) | \(\pi_{i3}\) | 추정범주 \(\hat{y}_i\) |
---|---|---|---|---|---|
1 | 1 | 0.283 | 0.112 | 0.604 | 3 |
2 | 1 | 0.425 | 0.209 | 0.365 | 1 |
3 | 1 | 0.589 | 0.271 | 0.141 | 1 |
4 | 1 | 0.262 | 0.729 | 0.009 | 2 |
5 | 1 | 0.450 | 0.509 | 0.041 | 2 |
6 | 2 | 0.589 | 0.271 | 0.141 | 1 |
7 | 2 | 0.349 | 0.570 | 0.082 | 2 |
8 | 1 | 0.199 | 0.024 | 0.777 | 3 |
9 | 2 | 0.349 | 0.570 | 0.082 | 2 |
10 | 3 | 0.501 | 0.168 | 0.331 | 1 |
11 | 3 | 0.490 | 0.149 | 0.361 | 1 |
12 | 3 | 0.283 | 0.112 | 0.604 | 3 |
13 | 3 | 0.425 | 0.209 | 0.365 | 1 |
14 | 3 | 0.160 | 0.029 | 0.811 | 3 |
15 | 2 | 0.365 | 0.540 | 0.095 | 2 |
16 | 2 | 0.595 | 0.247 | 0.158 | 1 |
17 | 1 | 0.416 | 0.186 | 0.398 | 1 |
18 | 3 | 0.268 | 0.096 | 0.636 | 3 |
nnet
패키지 외에도 glmnet
, mlogit
, VGAM
등의 R 패키지들을 사용해 명목형 로지스틱 회귀모형을 추정할 수 있다.
::vglm(y ~ x1 + x2,
VGAMdata = train_df,
family = VGAM::multinomial)
##
## Call:
## VGAM::vglm(formula = y ~ x1 + x2, family = VGAM::multinomial,
## data = train_df)
##
##
## Coefficients:
## (Intercept):1 (Intercept):2 x1:1 x1:2
## -64.56378 -118.15274 102.65063 133.29235
## x2:1 x2:2
## 10.86829 20.81307
##
## Degrees of Freedom: 36 Total; 30 Residual
## Residual deviance: 32.03007
## Log-likelihood: -16.01503
##
## This is a multinomial logit model with 3 levels
6.4 서열 로지스틱 회귀모형
본 장에서는 종속변수가 3개 이상의 범주를 가지며, 각 범주 간에 서열이 있는 경우에 대한 로지스틱 회귀모형을 소개한다.
6.4.1 기본 R 스크립트
<- tribble(
train_df ~N, ~L, ~y,
25, 5, 3,
25, 10, 3,
25, 20, 2,
25, 30, 1,
32, 5, 3,
32, 10, 3,
32, 20, 2,
32, 30, 1,
42, 5, 1,
42, 10, 3,
42, 20, 1,
42, 30, 1
%>%
) mutate(y = as.ordered(y))
::kable(train_df, booktabs = TRUE,
knitralign = c('r', 'r', 'r'),
col.names = c('잡음(N)', '손실(L)', '만족도($y$)'),
caption = '성능변수에 따른 통신 만족도')
잡음(N) | 손실(L) | 만족도(\(y\)) |
---|---|---|
25 | 5 | 3 |
25 | 10 | 3 |
25 | 20 | 2 |
25 | 30 | 1 |
32 | 5 | 3 |
32 | 10 | 3 |
32 | 20 | 2 |
32 | 30 | 1 |
42 | 5 | 1 |
42 | 10 | 3 |
42 | 20 | 1 |
42 | 30 | 1 |
Table 6.6은 벨 연구소에서 한 통신장치에 대하여 실시한 조사 결과를 나타낸 것이다. 주요 성능변수인 회선잡음(circuit noise: N)과 소리크기 손실(loudness loss: L)이 이용자의 주관적인 만족도에 미치는 영향을 분석하기 위한 것이다. 만족도는 원결과(Cavanaugh, Hatch, and Sullivan 1976)를 가공하여 다음과 같이 3가지로 분류하였다.
\[\begin{equation*} y = \begin{cases} 1 & \mbox{good}\\ 2 & \mbox{fair}\\ 3 & \mbox{poor} \end{cases} \end{equation*}\]
본 장에서는 두 가지 모형을 다룬다. 우선 누적 로짓모형(cumulative logit model)은 아래와 같이 MASS
패키지의 polr
함수를 사용하여 추정할 수 있다.
::polr(y ~ N + L, data = train_df) %>%
MASS::tidy() broom
##
## Re-fitting to get Hessian
## # A tibble: 4 x 5
## term estimate std.error statistic coef.type
## <chr> <dbl> <dbl> <dbl> <chr>
## 1 N -0.224 0.146 -1.53 coefficient
## 2 L -0.300 0.137 -2.19 coefficient
## 3 1|2 -13.0 6.46 -2.02 scale
## 4 2|3 -11.4 6.17 -1.85 scale
인근범주 로짓모형(adjacent-categories logit model)은 아래와 같이 VGAM
패키지의 vglm
함수를 이용하여 추정할 수 있다.
::vglm(y ~ N + L,
VGAMdata = train_df,
family = VGAM::acat(reverse = TRUE))
##
## Call:
## VGAM::vglm(formula = y ~ N + L, family = VGAM::acat(reverse = TRUE),
## data = train_df)
##
##
## Coefficients:
## (Intercept):1 (Intercept):2 N:1 N:2
## -12.94227208 -6.10597713 0.31431599 0.04643039
## L:1 L:2
## 0.17500408 0.29578067
##
## Degrees of Freedom: 24 Total; 18 Residual
## Residual deviance: 11.67769
## Log-likelihood: -5.838847
##
## This is an adjacent categories model with 3 levels
6.4.2 누적 로짓모형
객체 \(i\)가 범주 \(j\) 이하에 속할 누적확률을 \(\kappa_{ij}\)라 하자.
\[\begin{equation*} \kappa_{ij} = P(y_i \leq j \, | \, \mathbf{x}_i), \, j = 1, \cdots, J \end{equation*}\]
누적 로짓모형은 범주 누적확률의 로짓변환에 대한 선형 회귀모형이다.
\[\begin{equation} \log \left( \frac{\kappa_{ij}}{1 - \kappa_{ij}} \right) = \beta_{0,j} + \boldsymbol\beta^\top \mathbf{x}_i, \, j = 1, \cdots, J - 1 \tag{6.9} \end{equation}\]
식 (6.9)은 독립변수에 대한 계수 \(\boldsymbol\beta\)가 모든 범주에 대해 동일하며 절편(intercept) \(\beta_{0,j}\)만 범주에 따라 다른 비례 승산 모형(proportional odds model)이다. 즉, 범주에 관계없이 각 독립변수가 한 단위 증가할 때마다 로그 승산비는 동일하게 증가한다.
모형의 추정은 6.3.2절과 유사하게 다항분포를 사용한 최우추정법을 사용할 수 있다. 각 객체 \(i\)가 범주 \(j\)에 속할 확률은 아래와 같다.
\[\begin{equation*} \begin{split} \pi_{ij} &= \kappa_{ij} - \kappa_{i,j-1}\\ &= \frac{\exp (\beta_{0,j} + \boldsymbol\beta^\top \mathbf{x}_i)}{1 + \exp (\beta_{0,j} + \boldsymbol\beta^\top \mathbf{x}_i)} - \frac{\exp (\beta_{0,j-1} + \boldsymbol\beta^\top \mathbf{x}_i)}{1 + \exp (\beta_{0,j-1} + \boldsymbol\beta^\top \mathbf{x}_i)}, \, j = 2, \cdots, J - 1\\ & \\ \pi_{i1} &= \kappa_{i1}\\ &= \frac{\exp (\beta_{0,1} + \boldsymbol\beta^\top \mathbf{x}_i)}{1 + \exp (\beta_{0,1} + \boldsymbol\beta^\top \mathbf{x}_i)}\\ & \\ \pi_{iJ} &= 1 - \kappa_{i,J-1}\\ &= 1 - \frac{\exp (\beta_{0,J-1} + \boldsymbol\beta^\top \mathbf{x}_i)}{1 + \exp (\beta_{0,J-1} + \boldsymbol\beta^\top \mathbf{x}_i)} \end{split} \tag{6.10} \end{equation*}\]
로그 우도함수는
\[\begin{equation*} \sum_{i = 1}^{n} \sum_{j = 1}^{J} y_i \log \pi_{ij} \end{equation*}\]
이며, 이에 위에서 정리한 \(\pi_{ij}\)식을 대입하여 전개할 수 있다. 이 로그 우도함수는 concave 함수이므로(Pratt 1981), 각 계수에 대해 편미분하여 0이 되도록 하는 값을 구하는 방식으로 회귀모형을 추정할 수 있다.
<- MASS::polr(y ~ N + L, data = train_df)
polr_fit
print(polr_fit)
## Call:
## MASS::polr(formula = y ~ N + L, data = train_df)
##
## Coefficients:
## N L
## -0.2236292 -0.2998833
##
## Intercepts:
## 1|2 2|3
## -13.03527 -11.39902
##
## Residual Deviance: 12.8825
## AIC: 20.8825
위와 같이 polr
함수 실행 시 얻어지는 각 변수들에 대한 계수들의 부호는 교재(전치혁 2012)의 내용과 반대인데, 이는 polr
함수는 아래와 같은 모형을 추정하기 때문이다.
\[\begin{equation*} \log \left( \frac{\kappa_{ij}}{1 - \kappa_{ij}} \right) = \beta_{0,j} - \boldsymbol\beta^\top \mathbf{x}_i, \, j = 1, \cdots, J - 1 \end{equation*}\]
위 모형에서 polr
함수 실행 결과 추정된 절편값은 \(\beta_{0,1} = -13.0352721\), \(\beta_{0,2} = -11.3990207\) 이며, 두 변수 \(N\), \(L\)에 대한 회귀계수는 각각 -0.2236292, -0.2998833로 추정된다.
추정된 회귀계수를 식 (6.10)에 대입하면 각 객체 \(i\)가 각 범주 \(j\)에 속할 확률을 Table 6.7와 같이 얻을 수 있다. 아래 R 스크립트에서 사용한 predict
라는 함수가 해당 계산을 수행한다.
<- predict(polr_fit, train_df, type = "probs") %>%
predict_df as_data_frame() %>%
`colnames<-`(c("p1", "p2", "p3")) %>%
mutate(pred_class = predict(polr_fit, train_df, type = "class"))
bind_cols(train_df, predict_df) %>%
::kable(
knitrbooktabs = TRUE,
align = c('r', 'r', 'r', 'r', 'r', 'r', 'r'),
col.names = c('잡음(N)', '손실(L)', '실제범주 $y_i$',
'$\\pi_{i1}$', '$\\pi_{i2}$', '$\\pi_{i3}$', '추정범주 $\\hat{y}_i$'),
caption = '위 통신 만족도 데이터에 대한 누적 로짓모형의 추정범주',
# caption = 'Table \\@ref(tab:ordinal-logistic-reg-train-data)에 대한 누적 로짓모형의 추정범주',
digits = 4
)
잡음(N) | 손실(L) | 실제범주 \(y_i\) | \(\pi_{i1}\) | \(\pi_{i2}\) | \(\pi_{i3}\) | 추정범주 \(\hat{y}_i\) |
---|---|---|---|---|---|---|
25 | 5 | 3 | 0.0026 | 0.0107 | 0.9867 | 3 |
25 | 10 | 3 | 0.0116 | 0.0452 | 0.9432 | 3 |
25 | 20 | 2 | 0.1905 | 0.3567 | 0.4528 | 3 |
25 | 30 | 1 | 0.8252 | 0.1352 | 0.0396 | 1 |
32 | 5 | 3 | 0.0124 | 0.0481 | 0.9395 | 3 |
32 | 10 | 3 | 0.0531 | 0.1706 | 0.7763 | 3 |
32 | 20 | 2 | 0.5296 | 0.3230 | 0.1474 | 1 |
32 | 30 | 1 | 0.9576 | 0.0338 | 0.0085 | 1 |
42 | 5 | 1 | 0.1049 | 0.2709 | 0.6241 | 3 |
42 | 10 | 3 | 0.3443 | 0.3852 | 0.2705 | 2 |
42 | 20 | 1 | 0.9133 | 0.0685 | 0.0181 | 1 |
42 | 30 | 1 | 0.9953 | 0.0038 | 0.0009 | 1 |
6.4.3 인근범주 로짓모형
인근범주 로짓모형은 아래와 같이 인접한 두 범주의 확률 비율에 대한 회귀모형이다.
\[\begin{equation} \log \left( \frac{\pi_{ij}}{\pi_{i,j+1}} \right) = \beta_{0,j} + \boldsymbol\beta^\top \mathbf{x}_i, \, j = 1, \cdots, J - 1 \tag{6.11} \end{equation}\]
따라서, \(\pi_{ij}\)간에 다음과 같은 관계식이 성립한다.
\[\begin{equation*} \begin{split} \pi_{ij} &= \exp (\beta_{0,j} + \boldsymbol\beta^\top \mathbf{x}_i) \pi_{i,j+1}\\ &= \pi_{iJ} \exp \left(\sum_{k = j}^{J - 1} \beta_{0,k} + (J - j) \boldsymbol\beta^\top \mathbf{x}_i\right), \, j = 1, \cdots, J-1\\ \sum_{j = 1}^{J} \pi_{ij} &= 1 \end{split} \end{equation*}\]
이를 정리하면
\[\begin{equation} \begin{split} \pi_{ij} &= \frac{\exp \left( \sum_{l = j}^{J - 1} \beta_{0,l} + (J - j) \boldsymbol\beta^\top \mathbf{x}_i \right)}{1 + \sum_{k = 1}^{J - 1} \exp \left( \sum_{l = k}^{J - 1} \beta_{0,l} + (J - k) \boldsymbol\beta^\top \mathbf{x}_i \right)}, \, j = 1, \cdots, J - 1\\ \pi_{iJ} &= \frac{1}{1 + \sum_{k = 1}^{J - 1} \exp \left( \sum_{l = k}^{J - 1} \beta_{0,l} + (J - k) \boldsymbol\beta^\top \mathbf{x}_i \right)} \end{split} \tag{6.12} \end{equation}\]
와 같다. 이는 6.3.2절에서 살펴보았던 명목형 로지스틱 회귀모형에 비해 다소 복잡하지만 비슷한 형태이며, 역시 최우추정법을 이용하여 모형을 추정할 수 있다.
R에서는 VGAM
패키지의 vglm
함수를 이용할 때 파라미터 family
의 값을 VGAM
패키지의 acat
함수를 설정함으로써 인근범주 로짓모형을 추정할 수 있다. 이 때 acat
함수의 parallel
파라미터값을 TRUE
로 설정함으로써 식 (6.11)에서와 같이 비례 승산 모형(proportional odds model)을 정의한다.
<- VGAM::vglm(
vglm_fit ~ N + L,
y data = train_df,
family = VGAM::acat(reverse = TRUE, parallel = TRUE)
)
print(coef(vglm_fit))
## (Intercept):1 (Intercept):2 N L
## -9.0658976 -8.9018134 0.1725867 0.2082167
추정된 모형을 위 식 (6.12)에 대입하면 각 객체 \(i\)가 각 범주 \(j\)에 속할 확률을 추정할 수 있다. VGAM
패키지의 predictvglm
함수가 해당 계산을 수행한다.
<- VGAM::predictvglm(vglm_fit, train_df, "response") %>%
predict_df as_data_frame() %>%
`colnames<-`(c("p1", "p2", "p3")) %>%
mutate(pred_class = ordered(apply(., 1, function(x) which.max(x))))
bind_cols(train_df, predict_df) %>%
::kable(
knitrbooktabs = TRUE,
align = c('r', 'r', 'r', 'r', 'r', 'r', 'r'),
col.names = c('잡음(N)', '손실(L)', '실제범주 $y_i$',
'$\\pi_{i1}$', '$\\pi_{i2}$', '$\\pi_{i3}$', '추정범주 $\\hat{y}_i$'),
caption = '위 통신 만족도 데이터에 대한 인근범주 로짓모형의 추정범주',
# caption = 'Table \\@ref(tab:ordinal-logistic-reg-train-data)에 대한 인근범주 로짓모형의 추정범주',
digits = 4
)
잡음(N) | 손실(L) | 실제범주 \(y_i\) | \(\pi_{i1}\) | \(\pi_{i2}\) | \(\pi_{i3}\) | 추정범주 \(\hat{y}_i\) |
---|---|---|---|---|---|---|
25 | 5 | 3 | 0.0007 | 0.0280 | 0.9713 | 3 |
25 | 10 | 3 | 0.0052 | 0.0751 | 0.9197 | 3 |
25 | 20 | 2 | 0.1804 | 0.3244 | 0.4952 | 3 |
25 | 30 | 1 | 0.7894 | 0.1770 | 0.0337 | 1 |
32 | 5 | 3 | 0.0072 | 0.0874 | 0.9054 | 3 |
32 | 10 | 3 | 0.0474 | 0.2045 | 0.7480 | 3 |
32 | 20 | 2 | 0.5611 | 0.3015 | 0.1375 | 1 |
32 | 30 | 1 | 0.9339 | 0.0626 | 0.0036 | 1 |
42 | 5 | 1 | 0.1393 | 0.3026 | 0.5581 | 3 |
42 | 10 | 3 | 0.4411 | 0.3385 | 0.2204 | 1 |
42 | 20 | 1 | 0.9063 | 0.0867 | 0.0070 | 1 |
42 | 30 | 1 | 0.9881 | 0.0118 | 0.0001 | 1 |
비례 승산 모형(proportional odds model)이 아닌 인근범주 로짓모형은 아래와 같다.
\[\begin{equation} \log \left( \frac{\pi_{ij}}{\pi_{i,j+1}} \right) = \beta_{0,j} + \boldsymbol\beta_j^\top \mathbf{x}_i, \, j = 1, \cdots, J - 1 \tag{6.13} \end{equation}\]
해당 모형은 acat
함수의 parallel
파라미터 값을 FALSE
로 설정함으로써 추정할 수 있다.
<- VGAM::vglm(
vglm_fit ~ N + L,
y data = train_df,
family = VGAM::acat(reverse = TRUE, parallel = FALSE)
)
print(coef(vglm_fit))
## (Intercept):1 (Intercept):2 N:1 N:2
## -12.94227208 -6.10597713 0.31431599 0.04643039
## L:1 L:2
## 0.17500408 0.29578067
<- VGAM::predictvglm(vglm_fit, train_df, "response") %>%
predict_df as_data_frame() %>%
`colnames<-`(c("p1", "p2", "p3")) %>%
mutate(pred_class = ordered(apply(., 1, function(x) which.max(x))))
bind_cols(train_df, predict_df) %>%
::kable(
knitrbooktabs = TRUE,
align = c('r', 'r', 'r', 'r', 'r', 'r', 'r'),
col.names = c('잡음(N)', '손실(L)', '실제범주 $y_i$',
'$\\pi_{i1}$', '$\\pi_{i2}$', '$\\pi_{i3}$', '추정범주 $\\hat{y}_i$'),
caption = '위 통신 만족도 데이터에 대한 인근범주 로짓모형의 추정범주 (비례 승산 모형이 아닌 경우)',
# caption = 'Table \\@ref(tab:ordinal-logistic-reg-train-data)에 대한 인근범주 로짓모형의 추정범주 (비례 승산 모형이 아닌 경우)',
digits = 4
)
잡음(N) | 손실(L) | 실제범주 \(y_i\) | \(\pi_{i1}\) | \(\pi_{i2}\) | \(\pi_{i3}\) | 추정범주 \(\hat{y}_i\) |
---|---|---|---|---|---|---|
25 | 5 | 3 | 0.0004 | 0.0303 | 0.9693 | 3 |
25 | 10 | 3 | 0.0043 | 0.1200 | 0.8757 | 3 |
25 | 20 | 2 | 0.1295 | 0.6313 | 0.2392 | 2 |
25 | 30 | 1 | 0.5365 | 0.4546 | 0.0089 | 1 |
32 | 5 | 3 | 0.0055 | 0.0412 | 0.9533 | 3 |
32 | 10 | 3 | 0.0488 | 0.1517 | 0.7995 | 3 |
32 | 20 | 2 | 0.5924 | 0.3200 | 0.0876 | 1 |
32 | 30 | 1 | 0.9131 | 0.0857 | 0.0012 | 1 |
42 | 5 | 1 | 0.1667 | 0.0536 | 0.7797 | 3 |
42 | 10 | 3 | 0.6335 | 0.0850 | 0.2815 | 1 |
42 | 20 | 1 | 0.9734 | 0.0227 | 0.0039 | 1 |
42 | 30 | 1 | 0.9959 | 0.0040 | 0.0000 | 1 |