Lovetoken

저는 개발 취향을 가진 데이터 분석가 Jr. 입니다.

Navigation
 » Home
 » About Me
 » Github

R에서 모델적합에 사용되는 formula 인자식 사용부분에 대한 고찰

06 Dec 2016 » R



R을 이용한 모델링을 할 때 formula 인자값을 어떤 식으로 입력해야 하는지 정리해 볼 필요가 있다.
대표적으로 lm() 함수의 첫 번째 인자에 대한 입력값을 예로 들 수 있을 것이다.
이 인자값에는 약속에 의해 정해진 기호(operator)를 이용하여 모델의 뼈대를 설정할 수 있다.
몇가지의 기호만 알고 이를 조합한다면 일반적인 뼈대를 구성하는데 문제가 생기진 않을 것이다.

(본 글에서 사용될 기초데이터는 mtcars 이다.)

head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1



“~” 기호

기본적으로 formula 인자값의 입력은 종속변수를 앞에 쓰고 독립변수를 뒤에 쓰게 되는데
종속변수와 독립변수를 구분 짓는 기호는 “~” 이다.

lm(mpg ~ wt, data = mtcars)
## 
## Call:
## lm(formula = mpg ~ wt, data = mtcars)
## 
## Coefficients:
## (Intercept)           wt  
##      37.285       -5.344

위의 단순선형회귀적합 코드를 살펴보자.
lm() 함수의 첫 번째 인자입력값을 보면 mpg ~ wt 로 되어있다.
왼쪽 맨 앞의 mpg 는 종속변수로 지정하고, 오른쪽 뒤에 있는 wt 는 독립변수로 지정하겠다는 의미가 된다.



“+” 기호

독립변수를 wt 뿐만 아니라 cyl 변수까지 고려하는 다중회귀분석을 하고 싶다면 “+” 기호를 이용해 고려대상이 되는 변수를 추가시킬 수 있다.

lm(mpg ~ wt + cyl, data = mtcars)
## 
## Call:
## lm(formula = mpg ~ wt + cyl, data = mtcars)
## 
## Coefficients:
## (Intercept)           wt          cyl  
##      39.686       -3.191       -1.508

그런데 만약 자신이 가지고 있는 데이터셋에 종속변수를 설명시킬 독립변수들이 이미 모두 포진되어있는 상태라면, 그리고 그 독립변수들을 모두 고려한 다중회귀적합을 시키고 싶다면 어떻게 해야 할까?

lm(mpg ~ cyl + disp + hp + drat + wt + qsec + vs + am + gear + carb, data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ cyl + disp + hp + drat + wt + qsec + vs + 
##     am + gear + carb, data = mtcars)
## 
## Coefficients:
## (Intercept)          cyl         disp           hp         drat  
##    12.30337     -0.11144      0.01334     -0.02148      0.78711  
##          wt         qsec           vs           am         gear  
##    -3.71530      0.82104      0.31776      2.52023      0.65541  
##        carb  
##    -0.19942

이런 식으로 고려대상이 되는 독립변수의 명칭을 모두 적은 다음
사이사이에 “+” 기호를 무식하게 넣어주어야 하는 상황이다.
하지만 위의 코딩은 매우 비효율적 🙄 손이 아파질 수 있다.



“.” 기호

이를 대비해 특수하게 약속된 “.” 기호를 이용하면 좋다.

lm(mpg ~ ., data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ ., data = mtcars)
## 
## Coefficients:
## (Intercept)          cyl         disp           hp         drat  
##    12.30337     -0.11144      0.01334     -0.02148      0.78711  
##          wt         qsec           vs           am         gear  
##    -3.71530      0.82104      0.31776      2.52023      0.65541  
##        carb  
##    -0.19942

“.” 기호는 “전부” 의 의미를 가진다.
위의 코드는 종속변수로 이미 배정된 mpg 이외의 모든 변수를 독립변수로 고려하라 라는 의미가 된다.



“-” 기호

“+” 기호의 반대는 “-” 이다. 의미 역시 반대이다.
고려대상에서 추가하는 “+” 와 다르게 “-” 는 고려대상에서 제외시킨다.
“.” 기호를 통해 모든 독립변수를 배정했는데, 여기서 cyl 변수만은 독립변수에서 제외하고 싶을 경우

lm(mpg ~ . - cyl, data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ . - cyl, data = mtcars)
## 
## Coefficients:
## (Intercept)         disp           hp         drat           wt  
##    10.96007      0.01283     -0.02191      0.83520     -3.69251  
##        qsec           vs           am         gear         carb  
##     0.84244      0.38975      2.57743      0.71155     -0.21958

이렇게 “-” 기호를 활용하면 된다.

한 가지 덧붙이자면 회귀적합시 기본적으로 절편(intercept)을 고려하는 회귀적합을 하게 되는데, 절편이 0인 모델로 적합하고 싶은 경우 절편항을 제외시켜야 할 것이다.
“-” 기호를 아래와 같이 이용하면 된다.

lm(mpg ~ . - 1, data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ . - 1, data = mtcars)
## 
## Coefficients:
##      cyl      disp        hp      drat        wt      qsec        vs  
##  0.35083   0.01354  -0.02055   1.24158  -3.82613   1.19140   0.18972  
##       am      gear      carb  
##  2.83222   1.05426  -0.26321

결과를 확인해 보면 항시 언급되었던 절편항 “(Intercept)” 이 없어진 것을 확인할 수 있다.
참고로 아래와 같이 해도 절편항을 제외한다.

lm(mpg ~ . + 0, data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ . + 0, data = mtcars)
## 
## Coefficients:
##      cyl      disp        hp      drat        wt      qsec        vs  
##  0.35083   0.01354  -0.02055   1.24158  -3.82613   1.19140   0.18972  
##       am      gear      carb  
##  2.83222   1.05426  -0.26321



“:” 기호

회귀적합에서 상호작용에 대해 고려한다면 “:” 기호를 이용하여 상호작용항을 부여할 수 있다.
만약 종속변수 mpg 에 대해 설명하는 독립변수를 wt, cyl 2개 설정하고,
이 두 변수의 상호작용까지 고려하고자 한다면 이렇게 하면 된다.

lm(mpg ~ wt + cyl + wt:cyl, data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ wt + cyl + wt:cyl, data = mtcars)
## 
## Coefficients:
## (Intercept)           wt          cyl       wt:cyl  
##     54.3068      -8.6556      -3.8032       0.8084

그런데 고려대상인 독립변수가 3개 이상, 그리고 독립변수의 조합별 상호작용을 고려하게 된다면 골치가 아플 수 있다.
예를 들어 mpg 에 대해 설명하는 독립변수를 wt, cyl, gear 3개이고, 3개의 모든 조합에 대해 상호작용을 고려한다면 formula 인자값이 아래처럼 매우 길게 된다.

lm(mpg ~ wt + cyl + gear + wt:cyl + wt:gear + cyl:gear + wt:cyl:gear, data = mtcars)
## 
## Call:
## lm(formula = mpg ~ wt + cyl + gear + wt:cyl + wt:gear + cyl:gear + 
##     wt:cyl:gear, data = mtcars)
## 
## Coefficients:
## (Intercept)           wt          cyl         gear       wt:cyl  
##     47.3853     -10.4502      -0.8957       2.2704       0.5459  
##     wt:gear     cyl:gear  wt:cyl:gear  
##      0.3527      -0.8794       0.1001



“*” 기호

상호작용항을 고려하되 각 개별항과 상호작용항이 될 수 있는 모든 조합을 알아서 배정시키는
약속된 기호가 바로 “*” 이다.

lm(mpg ~ wt * cyl * gear, data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ wt * cyl * gear, data = mtcars)
## 
## Coefficients:
## (Intercept)           wt          cyl         gear       wt:cyl  
##     47.3853     -10.4502      -0.8957       2.2704       0.5459  
##     wt:gear     cyl:gear  wt:cyl:gear  
##      0.3527      -0.8794       0.1001

위의
mpg ~ wt * cyl * gear

mpg ~ wt + cyl + gear + wt:cyl + wt:gear + cyl:gear + wt:cyl:gear
와 동일한 것이다.
따라서 실행된 코드의 출력결과도 비교해 보면 같은 것을 확인할 수 있다.



I() 함수

만약 분석자 나름대로 다변수들의 정보를 하나로 압축시킨 파생변수로 회귀적합을 하고 싶다면 어떻게 해야 할까?
예를 들어 hp 변수값과 루트를 씌운 wt변수값을 더하고 carb 변수의 값을 뺀 값을 독립변수로 설정하여 단순회귀적합을 하고 싶다고 가정해보자. (일부러 의미 없이 복잡하게 설정해 봄)

일단 떠오르는 방법은 mtcars 에 새로운 변수열을 만들어 위의 상황대로

hp + sqrt(wt) - carb

를 계산한 새로운 변수를 만들어 이 변수열과 회귀적합을 하면 될 것이다.
하지만 I() 함수를 알게 된다면 새로운 변수를 직접 만들 필요가 없다. 이렇게 하면 된다.

lm(mpg ~ I(hp + sqrt(wt) - carb), data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ I(hp + sqrt(wt) - carb), data = mtcars)
## 
## Coefficients:
##             (Intercept)  I(hp + sqrt(wt) - carb)  
##                30.20584                 -0.06945

그런데 한 가지 의문이 생길 수 있다.
만약 I() 함수를 이용하지 않고 formulahp + sqrt(wt) - carb 의 날것의 형태로 입력하면 되지 않을까? 라는 의문이다.
실행해보면 다음과 같다.

lm(mpg ~ hp + sqrt(wt) - carb, data = mtcars)  
## 
## Call:
## lm(formula = mpg ~ hp + sqrt(wt) - carb, data = mtcars)
## 
## Coefficients:
## (Intercept)           hp     sqrt(wt)  
##    50.42823     -0.02908    -14.70273

우리가 줄곧 배운 formula 의 입력값은 특정한 기호에 의해 약속된 문법을 따른다.
따라서 hp + sqrt(wt) - carb 의 형태는 우리가 원하는 파생변수를 만들어 적합시키지 않는다.

hp 값에 sqrt(wt) 값이 더해진 후 carb 변수값이 차감된 것을 원하지만,
독립변수에 hp, sqrt(wt) 가 따로따로 고려되고 carb 변수가 독립변수로 제외됨을 명시할 뿐이다.

다시 I() 함수를 이용한 결과로 돌아가 보면 I() 의 쓰임은 결국 formula 인자의 약속된 문법을 escape 하는 역할로 볼 수도 있겠다.

formula 인자에 입력할 값의 사용방법과 기호의 의미를 정리해 보았다.
위의 내용 외에도 더 많은 팁과 기호들의 조합을 생각해 볼 수 있을 것이다.