변수 선택
주어진 데이터의 변수 중 모델링에 가장 적합한 변수만 택하는 과정을 변수 선택(Variable Selection) 또는 피처 선택(Feature Selection)이라 한다.
변수 선택 방법은 특정 모델링 기법에 의존하지 않고 데이터의 통계적 특성(예를 들면, 상호 정보량Mutual Information이나 상관 계수)으로부터 변수를 택하는 필터 방법(Filter Method)과 변수의 일부만을 모델링에 사용하고 그 결과를 확인하는 작업을 반복하면서 변수를 택해나가는 래퍼 방법(Wrapper Method), 모델 자체에 변수 선택이 포함된 임베디드 방법(Embedded Method)(예를 들면, LASSO)으로 분류된다.
여기서는 필터 방법 중 대표적인 몇 가지 기법을 살펴본다.
0에 가까운 분산(Near Zero Bariance)
변수를 선택하는 기법 중 가장 단순한 방법은 변숫값의 분산을 보는 것이다. 예를 들어, 데이터 1,000개가 있는데 이 중 990개에서 변수 A의 값이 0, 10개에서 변수 A의 값이 1이라고 하자. 그러면 변수 A는 서로 다른 관찰을 구분하는 데 별 소용이 없다. 따라서 데이터 모델링에서도 그리 유용하지 않다. 이런 변수는 분산이 0에 가까우며, caret 패키지에서는 nearZeroVar( ) 함수를 사용해 이런 변수들을 쉽게 제거할 수 있게 해주고 있다.
-caret::nearZeroVar : 데이터에서 분산이 0에 가까운 변수를 찾는다.
caret::nearZeroVar(
x, # 숫자를 저장한 행렬 또는 메트릭스(Metrics). 또는 숫자만 저장된 데이터 프레임
# 변수에서 가장 많이 관찰되는 값의 개수와 두 번째로 많이 관찰되는 값의 개수의 비에 대한 컷오프
freqCut=95/5,
uniqueCut=10, # 전체 데이터의 개수와 서로 다른 값의 개수의 비에 대한 컷오프
# FALSE면 분산이 거의 0인 변수의 위치가 반환되고,
# TRUE면 변수에 대한 정보가 저장된 데이터 프레임이 반환된다.
saveMetrics=FALSE
)
분산이 거의 0인 경우로는 변수에 저장된 서로 다른 값의 개수가 1인 경우를 들 수 있다. 또, freqCut과 uniqueCut이 만족되지 않을 경우에도 분산이 거의 0인 경우로 본다.
반환 값은 saveMetrics 인자에 대한 설명을 참고하기 바란다.
mlbench 패키지의 콩(Soybean) 질병 데이터에 nearZeroVar( )를 적용해보자. 콩 질병 데이터에는 질병 분류를 저장한 Class 변수와 콩에 대해 조사한 35개 변수가 저장되어 있다.
> library(caret) > library(mlbench) > data(Soybean) > nearZeroVar(Soybean, saveMetrics=TRUE) freqRatio percentUnique zeroVar nzv Class 1.010989 2.7818448 FALSE FALSE date 1.137405 1.0248902 FALSE FALSE plant.stand 1.208191 0.2928258 FALSE FALSE precip 4.098214 0.4392387 FALSE FALSE temp 1.879397 0.4392387 FALSE FALSE hail 3.425197 0.2928258 FALSE FALSE crop.hist 1.004587 0.5856515 FALSE FALSE area.dam 1.213904 0.5856515 FALSE FALSE sever 1.651282 0.4392387 FALSE FALSE seed.tmt 1.373874 0.4392387 FALSE FALSE germ 1.103627 0.4392387 FALSE FALSE plant.growth 1.951327 0.2928258 FALSE FALSE leaves 7.870130 0.2928258 FALSE FALSE leaf.halo 1.547511 0.4392387 FALSE FALSE leaf.marg 1.615385 0.4392387 FALSE FALSE leaf.size 1.479638 0.4392387 FALSE FALSE leaf.shread 5.072917 0.2928258 FALSE FALSE leaf.malf 12.311111 0.2928258 FALSE FALSE leaf.mild 26.750000 0.4392387 FALSE TRUE stem 1.253378 0.2928258 FALSE FALSE lodging 12.380952 0.2928258 FALSE FALSE stem.cankers 1.984293 0.5856515 FALSE FALSE canker.lesion 1.807910 0.5856515 FALSE FALSE fruiting.bodies 4.548077 0.2928258 FALSE FALSE ext.decay 3.681481 0.4392387 FALSE FALSE mycelium 106.500000 0.2928258 FALSE TRUE int.discolor 13.204545 0.4392387 FALSE FALSE sclerotia 31.250000 0.2928258 FALSE TRUE fruit.pods 3.130769 0.5856515 FALSE FALSE fruit.spots 3.450000 0.5856515 FALSE FALSE seed 4.139130 0.2928258 FALSE FALSE mold.growth 7.820896 0.2928258 FALSE FALSE seed.discolor 8.015625 0.2928258 FALSE FALSE seed.size 9.016949 0.2928258 FALSE FALSE shriveling 14.184211 0.2928258 FALSE FALSE roots 6.406977 0.4392387 FALSE FALSE |
위 표에서 nzv 컬럼은 Near Zero Variance를 뜻하므로, nzv 컬럼에 TRUE로 표시된 변수들을 제거하면 된다.
nearZeroVar( ) 호출 시 saveMetrics를 지정하지 않으면 분산이 0에 가까운 변수에 해당하는 컬럼 번호를 곧바로 출력해준다. 따라서 이를 사용해 손쉽게 분산이 0에 가까운 컬럼들을 제거할 수 있다.
> nearZeroVar(Soybean) [1] 19 26 28 > mySoybean <- Soybean[, -nearZeroVar(Soybean)] |
상관 계수
변수 간 높은 상관 계수가 존재한다는 것은 두 변수가 같이 커지거나 작아지는 경향이 있다는 의미다. 선형 모델, 신경망 등의 기계 학습 모델은 상관 계수가 큰 예측 변수들이 있을 경우 성능이 떨어지거나 모델이 불안정해진다. 또, 기계 학습이란 결국 모델의 파라미터(parameter)를 측정하는 작업인데, 상관 계수가 높은 변수가 여럿 존재하면 파라미터 수가 불필요하게 증가하여 차원 저주(Curse of Dimensionality)에 빠질 우려가 있다.
상관관계가 높은 변수들이 있다면 이들을 주성분 분석과 같은 방법을 사용해 서로 독립된 차원으로 변환하거나, 상관 계수가 큰 변수들을 제거해 버릴 수 있다. 다음은 상관 계수가 높은 변수들을 찾는 함수를 정리한 것이다.
-caret::findCorrelation : 상관 계수가 높은 변수들을 찾는다.
caret::findCorrelation(
x, # 상관 계수 행렬
cutoff=.90 # 상관 계수에 대한 컷오프
)
-FSelector::linear.correlation : 피어슨 상관 계수를 고려한 변수의 가중치(weight)를 계산한다.
FSelector::linear.correlation(
formula, # 모델에 대한 포뮬러 표현
data # 포뮬러를 적용할 데이터
)
-FSelector::rank.correlation : 스피어만 상관 계수를 고려한 변수의 가중치를 계산한다.
FSelector::rank.correlation(
formula, # 모델에 대한 포뮬러 표현
data # 포뮬러를 적용할 데이터
)
-FSelector::cutoff.k : 순위가 매겨진 속성으로부터 k 번째 등수까지를 선택한다.
FSelector::cutoff.k(
# 순위를 첫 번째 컬럼, 변수명을 행 이름(rownames)에 저장한 데이터 프레임
# linear.correlation() 함수나 rank.correlation() 함수의 반환 값으로 지정하면 된다.
attrs,
k # 양의 정수
)
FSelector::cutoff.k.percent(
attrs,
k # 0 ~ 1 사이의 값
)
caret의 findCorrelation( )의 동작 방식은 다음과 같다. 상관 계수 행렬을 입력으로 받아 상관 계수가 cutoff를 넘는 변수 쌍 A, B를 찾는다. (2) A와 B 중 둘을 제외한 다른 변수와의 상관 계수가 큰 변수 하나를 삭제한다. (3) 1 ~ 2를 계속 반복하면서 상관 계수가 높은 변수들을 제거해나간다.
4가지 종류의 자동차에 대한 속성을 나열한 데이터인 mlbench의 Vehicle에 대해 findCorrelation( )을 적용해보자. 다음 코드에서 subset( )은 분류에 해당하는 Class 컬럼을 제거하는 목적으로 사용되었고, cor( )은 상관 계수 행렬을 계산하는 함수다.
> library(mlbench) > library(caret) > data("Vehicle") > findCorrelation(cor(subset(Vehicle, select=-c(Class)))) [1] 3 8 11 7 9 2 |
실행 결과 3, 8, 11, 7, 9, 2번째 컬럼의 상관 계수가 높은 것으로 나타났다. 상관 계수 값들이 어떤지 직접 살펴보면 대부분 0.7을 넘는 상당히 큰 값임을 알 수 있다.
> cor(subset(Vehicle,select=-c(Class)))[c(3,8,11,7,8,2),c(3,8,11,7,9,2)] D.Circ Elong Sc.Var.Maxis Scat.Ra Pr.Axis.Rect Circ D.Circ 1.0000000 -0.9123072 0.8644323 0.9072801 0.8953261 0.7984920 Elong -0.9123072 1.0000000 -0.9383919 -0.9733853 -0.9505124 -0.8287548 Sc.Var.Maxis 0.8644323 -0.9383919 1.0000000 0.9518621 0.9382664 0.8084963 Scat.Ra 0.9072801 -0.9733853 0.9518621 1.0000000 0.9920883 0.8603671 Elong -0.9123072 1.0000000 -0.9383919 -0.9733853 -0.9505124 -0.8287548 Circ 0.7984920 -0.8287548 0.8084963 0.8603671 0.8579253 1.0000000 |
따라서 이들 변수를 제거하여 상관 계수가 낮은 변수들만 사용하도록 할 수 있다.
> myVehicle<-Vehicle[,-c(3,8,11,7,9,2)] |
caret::findCorrelation( )이 제거해야 할 변수들을 알려준다면, FSelector 패키지에는 선택해야 할 변수들을 알려주는 함수들이 있다. linear.correlation( )과 rank.correlation( )은 상관 계수로부터 변수의 중요도를 구하는 함수로, 각각 피어슨 상관 계수(Pearson Correlation)와 스피어만 상관 계수(Spearman’s Correlation)를 사용한다. 이들 함수는 예측 대상이 되는 분류와 예측 변수 간의 상관 계수를 계산하고 상관 계수가 높은 변수들을 사용하도록 추천한다.
다음은 mlbench의 Ozone 데이터에서 예측 대상이 되는 변수인 V4와 나머지 변수들 간의 피어슨 상관 계수를 구하고, 피어슨 상관 계수의 절댓값으로 변수의 중요도를 평가한 예다. V1, V2, V3은 팩터형 변수므로 계산에서 제외되었다.
> install.packages("FSelector") > library(FSelector) > library(mlbench) > data(Ozone) > (v <- linear.correlation(V4 ~ ., + data=subset(Ozone, select=-c(V1, V2, V3)))) attr_importance V5 0.58414447 V6 0.00468138 V7 0.44356639 V8 0.76986408 V9 0.72317299 V10 0.58026757 V11 0.22990285 V12 0.73194978 V13 0.41471463 |
실행 결과 V8, V12, V9 등이 V4와 상관 계수가 큰 것으로 보인다. cutoff.k( )를 사용하면 V4와 상관 계수 값이 큰 변수들을 손쉽게 찾을 수 있다. 다음은 상관 계수가 큰 변수 3개를 찾은 예다.
> cutoff.k(v, 3) [1] "V8" "V12" "V9" |
카이 제곱 검정
7.4.3절에서 카이 제곱 검정을 사용한 변수 간 독립 여부 판단에 대해 살펴보았다. 마찬가지 방법을 예측 대상이 되는 분류와 변수 간에 수행하여 변수와 분류 간의 독립성을 검정해볼 수 있다. 만약 둘 간의 관계가 독립이라면 해당 변수는 모델링에 적합하지 않은 것으로 볼 수 있다. 반대로 독립이 아니라면 모델링에 중요한 변수로 볼 수 있다. 카이 제곱 검정을 사용한 변수 선택에는 FSelector::chi.squared( )를 사용한다.
-FSelector::chi.squared : 카이 제곱 검정을 사용한 독립성 검정으로 변수의 가중치를 계산한다.
FSelector::chi.squared(
formula, # 모델에 대한 포뮬러 표현
data # 포뮬러를 적용할 데이터
)
다음은 mlbench의 Vehicle 데이터에 대해 FSelector의 chi.squared( )로 변수들의 중요도를 평가하고 그중 세 개의 변수를 선택한 예다.
> library(FSelector) > library(mlbench) > data(Vehicle) > (cs <- chi.squared(Class ~., data=Vehicle)) attr_importance Comp 0.3043172 Circ 0.2974762 D.Circ 0.3587826 Rad.Ra 0.3509038 Pr.Axis.Ra 0.2264652 Max.L.Ra 0.3234535 Scat.Ra 0.4653985 Elong 0.4556748 Pr.Axis.Rect 0.4475087 Max.L.Rect 0.3059760 Sc.Var.Maxis 0.4338378 Sc.Var.maxis 0.4921648 Ra.Gyr 0.2940064 Skew.Maxis 0.3087694 Skew.maxis 0.2470216 Kurt.maxis 0.3338930 Kurt.Maxis 0.2732117 Holl.Ra 0.3886266 > cutoff.k(cs, 3) [1] "Sc.Var.maxis" "Scat.Ra" "Elong" |
모델을 사용한 변수 중요도 평가
caret의 varImp( )는 모델로부터 변수 중요도를 계산한다. 이 함수가 변수의 중요도를 평가하는 자세한 방법은 인자에 주어진 모델에 따라 다르다. 모델별 중요도 계산 방식은 도움말 ?varImp에 설명되어 있으니 참고하기 바란다.
-caret::varImp : 회귀, 분류 모델을 위한 변수 중요도를 계산한다.
caret::varImp(
object # 회귀 또는 분류 모델
)
rpart 패키지(‘10.3 의사 결정 나무’ 절 참고)를 사용해 mlbench의 유방암 데이터 BreastCancer에 대한 의사 결정 나무를 만든 다음, 그로부터 변수의 중요성을 계산하는 예를 보자. varImp는 의사 결정 나무의 노드에서 가지가 나뉠 때의 손실 함수loss function 감소량을 각 변수에 더하는 방법으로 변수 중요도를 평가한다.
> library(mlbench) > library(rpart) > library(caret) > data(BreastCancer) > m <- rpart(Class ~., data=BreastCancer) > varImp(m) Overall Bare.nuclei 203.7284 Bl.cromatin 197.9057 Cell.shape 216.3834 Cell.size 222.9401 Id 307.8953 Cl.thickness 0.0000 Marg.adhesion 0.0000 Epith.c.size 0.0000 Normal.nucleoli 0.0000 Mitoses 0.0000 |
실행 결과 Bare.Nuclei, Bl.cromatin 등의 순으로 변수의 중요도가 높게 평가되었다.
이제 변수 선택을 하는 방법들이 어떻게 사용되는지 감을 잡았으리라 생각한다. 추가적인 부분은 caret의 변수 선택 매뉴얼과 FSelector 패키지의 참조 매뉴얼등을 참고하기 바란다.
R을 이용한 데이터 처리&분석 실무 中
'R > R을 이용한 데이터 처리&분석 실무' 카테고리의 다른 글
모델 평가 방법 - 2 (0) | 2020.02.11 |
---|---|
모델 평가 방법 (0) | 2020.02.11 |
전처리-1 (0) | 2020.02.09 |
데이터 탐색 (0) | 2020.02.09 |
변수 선택 (0) | 2020.02.08 |