https://www.youtube.com/watch?v=LxHMfr120gU&list=PLY0OaF78qqGAxKX91WuRigHpwBU0C2SB_&index=34
로지스틱 모델의 다수의 예측변수가 포함되어 있어서 과적합이 우려될 때 페널티회귀분석을 수행하여 예측변수의 개수가 축소된 보다 간명한 모델을 만들 수 있음
페널티 회귀분석의 지나치게 많은 예측변수를 갖는 로지스틱회귀모델의 페널티를 부과함
따라서 그 결과로 모델의 설명력에 덜 기여하는 예측변수 회귀계수를 0으로 만들거나 혹은 0에 가깝게 축소함
예측변수 회귀계수를 0으로 만드는 페널티 회귀분석 기법을 라소회귀분석
예측변수 회귀계수를 0에 가깝게 축소하는 페널티 회귀분석 기법을
릿지회귀분석이라고 함
라소회귀분석을 적용해 모델의 설명력에 덜 기여하는 예측변수 회귀계수를 0으로 만든다는 것은 결국 그 회귀계수를 갖는 예측변수를 모델에서 제거하는 것이기 때문에 모델의 복잡성이 줄어듦
예측정확도가 비슷할 경우 일반적으로 예측변수 개수가 작은 간명한 모델이 바람직함
예측변수의 개수가 작다는 것은 모델의 복잡도가 축소된다는 얘기고 그 얘기는 새 데이터에 대한 과적합 위험이 작은 보다 일반화 가능성이 높은 모델을 만들 수가 있다는 뜻이기 때문임
여기서는 라소회귀분석으로 페널티 로지스틱회귀분석을 수행할 것임
라스회귀분석은
기여도가 낮은 예측변수의 회귀계수를 0으로 만들어 예측모델에서 제거하고
그렇게 하여 예측모델 내에는 통계적으로 유의하면서 높은 설명력을 갖는 예측변수만이 포함됨
mlbench패키지 PimaIndiansDiabetes2데이터셋으로 라소회귀분석 기반 페널티 로지스틱회귀분석을 수행하고 성능을 평가해 보겠음
PimaIndiansDiabetes2데이터셋 구조
PimaIndiansDiabetes2데이터셋은 환자의 당뇨병 여부와 관련된 임상데이터 저장
모두 768 개의 관측 값을 포함하고 9개 변수로 구성됨
9개 변수 중 마지막 diabetes변수는
예측모델에 의해 예측하고자하는 결과변수로써
당뇨병 여부를 나타내는 두 개의 범주를 갖고 있음
앞의 8개 변수는 예측변수임. 이 8개 예측변수로 당뇨병 여부를 예측하는 예측모델을 생성할 것임
library(mlbench)
data("PimaIndiansDiabetes2")
str(PimaIndiansDiabetes2)
## 'data.frame': 768 obs. of 9 variables:
## $ pregnant: num 6 1 8 1 0 5 3 10 2 8 ...
## $ glucose : num 148 85 183 89 137 116 78 115 197 125 ...
## $ pressure: num 72 66 64 66 40 74 50 NA 70 96 ...
## $ triceps : num 35 29 NA 23 35 NA 32 NA 45 NA ...
## $ insulin : num NA NA NA 94 168 NA 88 NA 543 NA ...
## $ mass : num 33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 NA ...
## $ pedigree: num 0.627 0.351 0.672 0.167 2.288 ...
## $ age : num 50 31 32 21 33 30 26 29 53 54 ...
## $ diabetes: Factor w/ 2 levels "neg","pos": 2 1 2 1 2 1 2 1 2 2 ...
PimaIndiansDiabetes2데이터셋은 많은 결측값이 포함돼 있어, 이를 제거하는 전처리 작업이 필요함
결측값을 제외하고 PimaIndiansDiabetes3라는 새데이터셋으로 저장함
PimaIndiansDiabetes3 <- na.omit(PimaIndiansDiabetes2)
여기서는 caret패키지 createDataPartition()로 훈련데이터와 테스트데이터를 7대 3의 비율로 분할함
createDataPartition() 인수설명
y: 데이터셋에 포함되어 있는 결과변수를 지정
p: 훈련데이터의 비율 지정. 훈련/테스트데이터 비율을 7대 3으로 하기 때문에 0.7을 지정함
list: 훈련데이터에 대응되는 데이터인덱스가 리스트가 아닌 행렬 구조로 출력되도록 FALSE 지정
library(caret)
set.seed(123)
train <- createDataPartition(y=PimaIndiansDiabetes3$diabetes,
p=0.7, list=FALSE)
head(train, 10)
## Resample1
## [1,] 1
## [2,] 2
## [3,] 3
## [4,] 4
## [5,] 5
## [6,] 6
## [7,] 7
## [8,] 9
## [9,] 11
## [10,] 13
이 인덱스로 훈련/테스트데이터로 분화를 수행함
훈련데이터를 제외한 나머지 데이터는 테스트데이터로 저장함
diabetes.train <- PimaIndiansDiabetes3[train,]
diabetes.test <- PimaIndiansDiabetes3[-train,]
전체 데이터셋으로부터 훈련/테스트데이터가 적절히 잘 분할됐는지 평가하기 위해 두 데이터셋에 포함된 당뇨병 환자 비율을 계산해 보겠음
먼저 훈련데이터에 포함된 당뇨병 환자수와 비율 계산함
table(diabetes.train$diabetes)
##
## neg pos
## 184 91
sum(table(diabetes.train$diabetes))
## [1] 275
prop.table(table(diabetes.train$diabetes))
##
## neg pos
## 0.6690909 0.3309091
결과해석
훈련데이터에는 모두 275개 관측값이 있고 그중 당뇨병 환자는 91명임
비율을 계산하면 당뇨병 환자비율은 약 33% 정도됨
테스트데이터에 대해서도 계산을 해보겠음
table(diabetes.test$diabetes)
##
## neg pos
## 78 39
sum(table(diabetes.test$diabetes))
## [1] 117
prop.table(table(diabetes.test$diabetes))
##
## neg pos
## 0.6666667 0.3333333
결과해석
테스트 데이터에는 117개 관측값이 있고 그중 당뇨병 환자는 39명임
비율로는 약 33% 정도임
훈련 데이터와 테스트데이터 모두 당뇨병 환자를 33%를 포함하고 있음
훈련 데이터와 테스트 데이터에 포함되어 있는 결과 변수의 당뇨병 환자 비율이 모두 동일하기 때문에 전체 데이터셋으로부터 “모델생성을 위한 훈련데이터와 테스트를 위한 테스트데이터가 잘 분할됐다”고 판단할 수 있음
createDataPartition()이 이처럼 훈련/테스트데이터셋에 포함된 당뇨병 환자 비율이 동일하도록 작업함
createDataPartition()는 전체 데이터셋을 훈련/테스트데이터셋으로 분할할 때 전체 데이터셋에 포함된 결과변수의 범주비율이 훈련/테스트 데이터셋에서도 동일하게 유지되도록 생성함
그래서 훈련/테스트데이터셋에 포함된 당뇨병 환자 비율 33%는 전체 데이터셋의 당뇨병 환자 비율이기도 함
훈련/테스트데이터셋이 준비됐으므로 페널티 회귀분석으로 예측모델 생성 후 모델성능을 평가할 것임
페널티 회귀분석에서는 예측오차를 최소화하는 최적의 \(\lambda\)를 먼저 결정해야 함. \(\lambda\)는 페널티 크기를 지정해 줌
glmnet패키지 cv.glmnet() 교차검증을 통해 최적의 \(\lambda\)를 산출함
cv.glmnet() 인수설명
1st: 예측변수 행렬 지정
2nd: 결과변수 벡터 지정
family: 결과변수 확률분포 지정. 여기서는 현재 현재 이항 로지스틱회귀분석을 수행하기 때문에 “binomial” 지정
\(\alpha\): 라소회귀분석을 바탕으로 한 페널티 회귀분석을 수행할 예정이기 때문에 1을 지정함. 0을 지정하면 릿지회귀분석을 수행함
cv.glmnet()은 포뮬러 형식의 모델 설정을 지원하지않아 예측변수/결과변수를 각각 별도 지정해야 함
예측변수는 행렬 형식, 결과변수는 벡터 형식으로 지정돼야 함
예측변수로 숫자만 취할 수 있어 데이터셋에 범주형 변수가 있으면 사전에 더미변수로 변환해야 함
model.matrix()로 이러한 데이터 전처리 작업을 쉽게 수행할 수 있음
model.matrix() 인수설명
1st: 포뮬러 형식으로 결과변수와 예측변수 간 관계를 지정함
2nd: 사용할 데이터셋을 지정함
model.matrix()는
모델에 투입할 예측변수 행렬을 생성하고
범주형 변수를 더미변수로 자동으로 변환해 줌
x <- model.matrix(diabetes ~ ., diabetes.train)
head(x)
## (Intercept) pregnant glucose pressure triceps insulin mass pedigree age
## 4 1 1 89 66 23 94 28.1 0.167 21
## 5 1 0 137 40 35 168 43.1 2.288 33
## 7 1 3 78 50 32 88 31.0 0.248 26
## 9 1 2 197 70 45 543 30.5 0.158 53
## 14 1 1 189 60 23 846 30.1 0.398 59
## 15 1 5 166 72 19 175 25.8 0.587 51
첫 번째 열이 불필요하여 첫 번째 열(Intercept)을 제거하는 추가작업을 수행하겠음
결과변수 벡터를 별도로 생성해 y변수에 저장
결과변수는 범주형 변수이기 때문에 숫자 형식으로 변환함
사건발생과 미발생을 1과 0으로 코딩되도록 범주형 변수를 변환해 y 변수에 저장함
x <- model.matrix(diabetes ~ ., diabetes.train)[,-1]
y <- ifelse(diabetes.train$diabetes=="pos", 1, 0)
library(glmnet)
set.seed(123)
diabetes.cv <- cv.glmnet(x=x, y=y, family="binomial")
diabetes.cv$lambda.min
## [1] 0.01087884
diabetes.cv$lambda.1se
## [1] 0.05805712
coef(diabetes.cv, diabetes.cv$lambda.min)
## 9 x 1 sparse Matrix of class "dgCMatrix"
## s1
## (Intercept) -9.23133474
## pregnant 0.01006916
## glucose 0.03446189
## pressure .
## triceps 0.02678380
## insulin 0.00147175
## mass 0.04309304
## pedigree 1.14386810
## age 0.03039017
coef(diabetes.cv, diabetes.cv$lambda.1se)
## 9 x 1 sparse Matrix of class "dgCMatrix"
## s1
## (Intercept) -5.6548824026
## pregnant .
## glucose 0.0276723503
## pressure .
## triceps 0.0137868666
## insulin 0.0001604243
## mass 0.0120567460
## pedigree 0.3234881011
## age 0.0137023590
비교결과
lambda.min의 \(\lambda\)를 사용한 경우, 7개의 예측변수를 갖는 회귀모델이 구축됐음
lambda.1se의 \(\lambda\)를 사용한 경우, 그보다 작은 6개의 예측변수를 갖는 회귀모델이 생성돼 모델의 복잡성이 다소 줄어들었음
glmnet() 인수
예측모델은 glmnet()으로 생성. 조금 전 사용한 cv.glmnet()와 대부분의 인수를 공유함
x, y: 각각 예측변수 행렬과 결과변수 벡터를 지정함
family: 결과변수에는 확률분포인 binomial 지정
alpha: 1을 지정해 라소회귀분석 수행
lambda: 교차검증 객체에서 추출한 예측오차를 최소화하는 \(\lambda\)인 lambda.min원소에 있는 값을 지정
diabetes.gnet1 <- glmnet(x=x, y=y,
family="binomial",
alpha=1,
lambda=diabetes.cv$lambda.min)
diabetes.test.x <- model.matrix(diabetes ~ ., diabetes.test)[,-1]
이어서 predict()로 테스트 데이터에 대한 예측확률 계산
predict() 인수설명
1st: 예측모델을 지정함
newx: 테스트 데이터로부터 생성한 예측변수 행렬을 지정함
type: response를 지정해 확률로 결과값이 출력되도록 함
diabetes.pred1 <- predict(diabetes.gnet1,
newx=diabetes.test.x,
type="response")
이어서 예측확률 0.5를 기준으로 당뇨병 여부를 판정함
diabetes.pred1 <- ifelse(diabetes.pred1 > 0.5, "pos", "neg")
table(diabetes.test$diabetes, diabetes.pred1,
dnn=c("Actual", "Predicted"))
## Predicted
## Actual neg pos
## neg 69 9
## pos 20 19
결과해석: 대각선에 있는 수치는 실제 판정결과와 예측모델의 예측결과가 일치하는 케이스 갯수임
예측정확도 계산
mean(diabetes.test$diabetes==diabetes.pred1)
## [1] 0.7521368
diabetes.gnet2 <- glmnet(x=x, y=y,
family="binomial",
alpha=1,
lambda=diabetes.cv$lambda.1se)
# 이어서 model.matrix()로 테스트 데이터셋에 포함된 예측변수 행렬 생성
diabetes.test.x <- model.matrix(diabetes ~ ., diabetes.test)[,-1]
# 이어서 predict()로 테스트 데이터에 대한 예측확률 계산
diabetes.pred2 <- predict(diabetes.gnet2,
newx=diabetes.test.x,
type="response")
# 이어서 예측확률 0.5를 기준으로 당뇨병 여부를 판정함
diabetes.pred2 <- ifelse(diabetes.pred2 > 0.5, "pos", "neg")
# table()로 실제 판정결과와 예측모델에 의한 예측결과 비교
table(diabetes.test$diabetes, diabetes.pred2,
dnn=c("Actual", "Predicted"))
## Predicted
## Actual neg pos
## neg 71 7
## pos 22 17
# 예측정확도 계산
mean(diabetes.test$diabetes==diabetes.pred2) # 예측 정확도는 75.2%로 선출되었음
## [1] 0.7521368
결과해석
간명도를 높인 예측모델의 경우 예측정확도는 75.2%로 계산됨
우연히도 앞서 예측오차를 최소화하는 \(\lambda\)를 이용한 예측정확도와 동일한 값이
산출됨
diabetes.logit <- glm(diabetes ~ .,
data=diabetes.train,
family=binomial(link="logit"))
diabetes.logit.pred <- predict(diabetes.logit,
newdata=diabetes.test,
type="response")
diabetes.logit.pred <- ifelse(diabetes.logit.pred > 0.5, "pos", "neg")
table(diabetes.test$diabetes, diabetes.logit.pred,
dnn=c("Actual", "Predicted"))
## Predicted
## Actual neg pos
## neg 66 12
## pos 20 19
mean(diabetes.test$diabetes==diabetes.logit.pred)
## [1] 0.7264957
결과해석
예측정확도는 72.6%로 산출되었음
예측모델의 모든 예측변수를 투입했음에도 불구하고 앞서 생성한 2개의 페널티 로지스틱회귀모델의 예측정확도에 비해서 더 낮게 계산됨
따라서 여기에서는
모델이 간명도 관점에서 뿐만 아니라
모델의 예측정확도 관점에서도
일반적인 이항 로지스틱회귀분석을 이용한 예측모델보다 페널티 회귀분석을 이용한 예측모델이 더 우수하다고 판단내릴 수 있음
앞서 생성한 두 개의 페널티 로지스틱회귀모델의 예측정확도가 모두 동일했음
따라서 투입된 예측변수의 개수를 고려할 때 lambda.1se에
포함된 \(\lambda\)를
이용한 페널티 로지스틱회귀모델이 3개의 모델을 가운데는 일반화 관점에서
가장 우수한 모델이라고 얘기할 수 있음