로지스틱 회귀 모델(Logistic Regression)은 데이터 X의 분류가 Y일 확률을 p, N일 확률을 1-p라 할 때 다음과 같은 선형 모델을 가정한다.
log(p / (1-p)) = β_(0) + β_(1)X
이 식에 대한 가장 단순한 설명은 다음과 같다.
β_(0) + β_(1)X는 (-∞, ∞) 값을 가질 수 있다. 그러나 우리가 예측하고자 하는 p는 분류가 Y일 확률이므로 (0, 1) 값을 가진다. 따라서 이 둘을 맞춰줄 필요가 있다. 이를 위한 첫 번째 단계는 p를 예측하는 것이 아니라 비(오즈odds)를 예측하도록 하는 것이다.
p / (1-p) = β_(0) + β_(1)X (식 10-1)
이 식에서 좌변의 값은 (0, ∞) 값만 가질 수 있다. 반면 우변은 (-∞, ∞)를 가진다. 좌변이 (-∞, ∞) 값을 갖게 하기 위해 log 함수를 취한다. 그 결과 얻어진 log(p / (1-p))를 로짓 함수(logit function)라고 하고, 이를 이용한 결과는 식 9-1이 된다. 선형 모델에 대한 본격적인 설명은 참고자료를 보기 바란다.
로지스틱 회귀 모델은 glm( )함수를 사용해 수행한다.
-glm : 일반화 선형 모델을 생성한다.
glm(
formula, # 모델 포뮬러
data, # 포뮬러를 적용할 데이터
family, # 오차 분포와 링크(link) 함수. 로지스틱 회귀 모델의 경우 "binomial"을 지정한다.
)
-predict.glm : 일반화 선형 모델을 사용한 예측을 수행한다.
predict.glm(
object, # glm 객체
newdata, # 예측을 수행할 대상 데이터
# 예측 결과의 유형을 지정한다. 기본값은 "link"다.
# - link: 선형 독립 변수들의 연산 결과의 크기로 값을 반환한다. 이 값은 로지스틱 회귀 모델의
# 경우 로그 오즈 log(p / (1-p))다.
# - response: 반응 변수(response variable)의 크기로 값을 반환하며 로지스틱 회귀 모델의 경우
# p가 이에 해당한다.
# - terms: 행렬에 모델 포뮬러의 각 변수에 대한 적합된 값을 선형 예측 변수의 크기로 반환한다.
type=c("link", "response", "terms")
)
아이리스 데이터로부터 로지스틱 회귀 모델을 작성해보자. 예측값이 두 분류여야 하므로 virginica, versicolor라는 두 분류만 남긴다.
> d <- subset(iris, Species == "virginica" | Species == "versicolor")
> str(d)
'data.frame': 100 obs. of 6 variables:
$ Sepal.Length: num 7 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 ...
$ Sepal.Width : num 3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 ...
$ Petal.Length: num 4.7 4.5 4.9 4 4.6 4.5 4.7 3.3 4.6 3.9 ...
$ Petal.Width : num 1.4 1.5 1.5 1.3 1.5 1.3 1.6 1 1.3 1.4 ...
$ Species : Factor w/ 3 levels "setosa","versicolor",..: 2 2 2 2 2 2 2 2 2 2 ...
$ Species2 : int 1 2 1 2 1 2 1 2 1 2 ...
위 결과에서 보듯이 subset( )을 적용하고 나면 데이터는 virginica, versicolor만 남도록 잘 걸러지지만 Species는 여전히 3개 레벨을 가질 수 있는 팩터다. 따라서 Species 컬럼에 새로 범주 레벨이 정해지도록 다시 한 번 factor( ) 함수를 거치게 한다.
> d$Species <- factor(d$Species)
> str(d)
'data.frame': 100 obs. of 6 variables:
$ Sepal.Length: num 7 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 ...
$ Sepal.Width : num 3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 ...
$ Petal.Length: num 4.7 4.5 4.9 4 4.6 4.5 4.7 3.3 4.6 3.9 ...
$ Petal.Width : num 1.4 1.5 1.5 1.3 1.5 1.3 1.6 1 1.3 1.4 ...
$ Species : Factor w/ 2 levels "versicolor","virginica": 1 1 1 1 1 1 1 1 1 1 ...
$ Species2 : int 1 2 1 2 1 2 1 2 1 2 ...
그 결과 Species가 2개의 레벨로 잘 정리되었다. 모델은 glm( ) 함수에 family=“binomial”을 지정해 선형 회귀 모델에서 한 것처럼 만든다.
> (m <- glm(Species ~ ., data=d, family="binomial"))
Call: glm(formula = Species ~ ., family = "binomial", data = d)
Coefficients:
(Intercept) Sepal.Length Sepal.Width Petal.Length Petal.Width
-42.0508 -2.4929 -6.6524 9.3069 18.2460
Species2
0.1178
Degrees of Freedom: 99 Total (i.e. Null); 94 Residual
Null Deviance: 138.6
Residual Deviance: 11.89 AIC: 23.89
모델이 적합된 값은 fitted( )를 사용해 알 수 있다.
> fitted(m)[c(1:5, 51:55)]
51 52 53 54 55
1.137650e-05 5.504927e-05 1.131091e-03 5.122874e-05 1.382259e-03
101 102 103 104 105
1.000000e+00 9.996284e-01 9.999988e-01 9.997111e-01 9.999999e-01
로지스틱 회귀 모델은 0 또는 1로 값을 예측하는 모델이다. 위 결과를 보면 virginica에 해당하는 1:5행은 0, versicolor에 해당하는 51:55행은 1로 잘 예측된 것을 알 수 있다.
예측값이 0.5 이하인 경우 virginica, 0.5보다 큰 경우 versicolor라고 하고, 이를 실제 데이터와 비교해보자. 아래 코드에서 as.numeric( )은 팩터를 숫자를 저장한 벡터로 변환한다. R에서 팩터의 레벨은 1, 2, 3, …처럼 1부터 값이 부여되기 시작한다. 따라서 as.numeric( )으로 팩터를 변환한 뒤 1을 빼주어야 로지스틱 회귀 분석의 결과에 맞게 0 또는 1의 값을 갖게 된다.
> f <- fitted(m)
> as.numeric(d$Species)
[1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[35] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[69] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
> ifelse(f> .5, 1, 0)==as.numeric(d$Species) -1
51 52 53 54 55 56 57 58 59 60 61 62
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
63 64 65 66 67 68 69 70 71 72 73 74
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
75 76 77 78 79 80 81 82 83 84 85 86
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE
87 88 89 90 91 92 93 94 95 96 97 98
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
99 100 101 102 103 104 105 106 107 108 109 110
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
111 112 113 114 115 116 117 118 119 120 121 122
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
123 124 125 126 127 128 129 130 131 132 133 134
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE
135 136 137 138 139 140 141 142 143 144 145 146
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
147 148 149 150
TRUE TRUE TRUE TRUE
예측된 분류와 실제 분류가 일치한 경우 TRUE, 일치하지 않은 경우 FALSE가 표시되었다. 눈으로 확인하기에 불편한 점이 있으므로 위 결과의 TRUE 개수를 코드를 사용해 세어보자.
> is_correct <- (ifelse(f > .5, 1, 0) == as.numeric(d$Species) - 1)
> sum(is_correct)
[1] 98
> sum(is_correct) / NROW(is_correct)
[1] 0.98
sum( ) 함수는 TRUE를 1, FALSE를 0으로 취급하므로 sum( )은 전체에서 TRUE의 개수를 반환한다. NROW( )는 데이터의 전체 개수를 반환한다. 따라서 sum(is_correct) / NROW(is_correct)는 정확한 분류의 비율이 되며 이 경우에는 98%였다.
새로운 데이터에 대한 예측은 predict( ) 함수를 사용한다. 이 예에서는 설명의 편의를 위해 미리 테스트할 데이터를 제외시켜놓지 않았기 때문에 모델을 만들 때 사용한 데이터를 재사용한 예를 보인다. 그러나 실제 모델을 만들 때는 9장에서 설명한 것처럼 훈련 데이터와 테스트 데이터가 분리되어 있도록 하는 것이 올바른 방법이다.
type을 response로 지정하고 예측을 수행하면 0 ~ 1 사이의 확률을 구해준다.
> predict(m, newdata=d[c(1, 10, 55),], type="response")
51 60 105
1.137650e-05 1.848877e-05 9.999999e-01
predict( )는 일반 함수Generic Function므로 주어진 인자에 따라 다른 메서드를 호출한다. predict( ) 함수가 호출하는 메서드의 목록은 methods(“predict”)로 볼 수 있으며, glm의 경우 predict.glm( )이 자동으로 호출된다.
로지스틱 회귀 모델에는 이외에도 8장의 선형 회귀에서 살펴본 다양한 함수가 적용 가능하니 확인해보기 바란다.
R을 이용한 데이터 처리&분석 실무 中
'R > R을 이용한 데이터 처리&분석 실무' 카테고리의 다른 글
의사 결정 나무 (0) | 2020.02.12 |
---|---|
다항 로지스틱 회귀 분석 (0) | 2020.02.12 |
모델 평가 방법 - 2 (0) | 2020.02.11 |
모델 평가 방법 (0) | 2020.02.11 |
전처리-2 (0) | 2020.02.10 |