패키지 dplyr 03: 편의 기능
dplyr : 부가 기능
- 만일 동일한 함수를 여러 열에 동일하게 적용해야 한다고 생각해보자. 여기서 여러 열은 모든 열일 수도 있고, 미리 정해진 일부 열일 수도 있고, 특정 조건을 만족하는 열일 수도 있다.
그 밖의 편의 기능: _all, _at, _if와 vars(), funs()
- 앞서 새로운 열을 만들 때
mutate함수를 사용했다. 예를 들어mtcars의qsec열에 지수함수exp를 적용하여 새로운 열을 생성한다면 다음과 같다.
library(dplyr)
mtcars %>% mutate(exp(qsec)) %>% head
## mpg cyl disp hp drat wt qsec vs am gear carb exp(qsec) ## 1 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 14076257 ## 2 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 24642915 ## 3 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 120842669 ## 4 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 277130757 ## 5 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 24642915 ## 6 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 604553060
- 만약 모든 열에 대해 지수 함수
exp를 적용해야 한다면 어떻게 해야 하나? 크게
다를 것이 없다. 단지 손이 힘들 뿐.[3]
[3]: 저자는 다음의 코드를 활용했다. coln0 <- colnames(mtcars); coln <- colnames(mtcars); substr(coln, 1,1) = toupper(substr(coln, 1, 1)); coln <- paste('exp', coln, sep=''); paste('mutate(', paste(coln, "=exp(", coln0,")", sep='', collapse=', '), ')', sep='')
mtcars %>% mutate(expMpg=exp(mpg), expCyl=exp(cyl), expDisp=exp(disp), expHp=exp(hp), expDrat=exp(drat), expWt=exp(wt), expQsec=exp(qsec), expVs=exp(vs), expAm=exp(am), expGear=exp(gear), expCarb=exp(carb)) %>% head(n=3)
## mpg cyl disp hp drat wt qsec vs am gear carb expMpg expCyl ## 1 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 1318815734 403.42879 ## 2 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 1318815734 403.42879 ## 3 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 7978370264 54.59815 ## expDisp expHp expDrat expWt expQsec expVs expAm ## 1 3.069850e+69 5.920972e+47 49.40245 13.73572 14076257 1.000000 2.718282 ## 2 3.069850e+69 5.920972e+47 49.40245 17.72542 24642915 1.000000 2.718282 ## 3 8.013164e+46 2.451246e+40 46.99306 10.17567 120842669 2.718282 2.718282 ## expGear expCarb ## 1 54.59815 54.598150 ## 2 54.59815 54.598150 ## 3 54.59815 2.718282
- 물론 이것도 한 방법이지만 처음 이 코드를 본 사람은 꽤나 어리둥절할 것이다. 하지만 이 코드가 수행하는 일은 ‘모든 열에 대해 지수함수
exp를 적용하라’이다. 개념적으로는 꽤나 단순한 것이다.dplyr에서는 이렇게 모든 열에 동일한 함수를 적용하는 경우을 위해mutate_all이라는 함수를 마련해 놓았다.mutate_all함수를 쓴다면 위의 코드는 다음과 같이 단순해 진다.
mtcars %>% mutate_all(exp) %>% head(n=3)
## mpg cyl disp hp drat wt ## 1 1318815734 403.42879 3.069850e+69 5.920972e+47 49.40245 13.73572 ## 2 1318815734 403.42879 3.069850e+69 5.920972e+47 49.40245 17.72542 ## 3 7978370264 54.59815 8.013164e+46 2.451246e+40 46.99306 10.17567 ## qsec vs am gear carb ## 1 14076257 1.000000 2.718282 54.59815 54.598150 ## 2 24642915 1.000000 2.718282 54.59815 54.598150 ## 3 120842669 2.718282 2.718282 54.59815 2.718282
- 하지만 두 코드는 완전히 동일하지는 않다.
mutate의 경우 기존의 열이 보존되지만,mutate_all의 경우 기존의 열에 함수가 적용된 결과가 덮어씌워진다. 어쨋든mutate_all의_all은 모든 열에 적용됨을 시사한다._all는dplyr의 거의 모든 함수의 뒤에 붙어서 새로운 함수를 나타낸다. 그리고 열을 선택하는 방법을 나타내는 접미사는_all이외에도_at과_if가 있다. - 다음의 표를 보자.
_all |
_at |
_if |
|
|---|---|---|---|
select |
select_all |
select_at |
select_if |
mutate |
mutate_all |
mutate_at |
mutate_if |
transmute |
transmute_all |
transmute_at |
transmute_if |
group_by |
group_by_all |
group_by_at |
group_by_if |
summarise |
summarise_all |
summarise_at |
summarise_if |
- 먼저
mutate를 활용해서_at과_if를 설명해보자._at의 경우는 함수를 적용할 열의 이름이 변수(문자열 벡터)에 저장되어 있는 경우에 쓸 수 있다. 다음의 예제를 보자.
coln = c('cyl', 'disp', 'drat', 'carb')
mtcars %>% mutate_at(coln, exp) %>% head(n=3)
## mpg cyl disp hp drat wt qsec vs am gear ## 1 21.0 403.42879 3.069850e+69 110 49.40245 2.620 16.46 0 1 4 ## 2 21.0 403.42879 3.069850e+69 110 49.40245 2.875 17.02 0 1 4 ## 3 22.8 54.59815 8.013164e+46 93 46.99306 2.320 18.61 1 1 4 ## carb ## 1 54.598150 ## 2 54.598150 ## 3 2.718282
- 다른 열은 모두 보존이 되었고, 문자열 벡터의 원소
cyl,disp,drat에 해당하는 열에 지수함수exp가 적용되었다. 그런데 생각해보면 열을 선택하는 명령은 따로 존재하지 않는가? 다음의 예와 비교를 해보자.
mtcars %>% select(starts_with('c'), starts_with('d')) %>% mutate_all(exp) %>% head(n=3)
## cyl carb disp drat ## 1 403.42879 54.598150 3.069850e+69 49.40245 ## 2 403.42879 54.598150 3.069850e+69 49.40245 ## 3 54.59815 2.718282 8.013164e+46 46.99306
- 결과는 거의 똑같다.
select의 경우는 열 이름을 따옴표 안에 쓰지 않아도 되고,starts_with,ends_with와 같은 함수도 쓸 수 있다는 장점이 있다. 만약mutate_at함수에서select와 같은 방법으로 열을 선택하려면vars라는 함수를 쓸 수 있다.
mtcars %>% mutate_at(vars(starts_with('c'), starts_with('d')), exp) %>% head(n=3)
## mpg cyl disp hp drat wt qsec vs am gear ## 1 21.0 403.42879 3.069850e+69 110 49.40245 2.620 16.46 0 1 4 ## 2 21.0 403.42879 3.069850e+69 110 49.40245 2.875 17.02 0 1 4 ## 3 22.8 54.59815 8.013164e+46 93 46.99306 2.320 18.61 1 1 4 ## carb ## 1 54.598150 ## 2 54.598150 ## 3 2.718282
- 마지막
mutate_if는 특정한 조건을 만족하는 열만을 선택해서 함수를 적용한다. 만약 열의 총합이 100 미만이 열에 대해서만 지수 함수exp를 적용하고 싶다면 다음과 같이 쓸 수 있다.
mtcars %>% mutate_if(function(x) sum(x)<100, exp) %>% head(n=3)
## mpg cyl disp hp drat wt qsec vs am gear carb ## 1 21.0 6 160 110 3.90 2.620 16.46 1.000000 2.718282 4 54.598150 ## 2 21.0 6 160 110 3.90 2.875 17.02 1.000000 2.718282 4 54.598150 ## 3 22.8 4 108 93 3.85 2.320 18.61 2.718282 2.718282 4 2.718282
- 이때 한 가지 문제는 열의 이름이 보존되어 있기 때문에 지수 함수가 어떤 열에 적용되었는지 쉽게 알기 힘들다는 단점이 있다. 만약 새로운 열을 생성하면서 함수가 적용되지 않는 열은 제거하고 싶다면
transmute함수를 사용한다. 다음의 예를 보면transmute의 역할을 쉽게 이해할 수 있을 것이다.
mtcars %>% transmute(expCarb = exp(carb)) %>% head(n=3)
## expCarb ## 1 54.598150 ## 2 54.598150 ## 3 2.718282
mtcars %>% transmute_if(function(x) sum(x)<100, exp) %>% head(n=3)
## vs am carb ## 1 1.000000 2.718282 54.598150 ## 2 1.000000 2.718282 54.598150 ## 3 2.718282 2.718282 2.718282
- 그리고
transmute_all의 결과를 예상해보면mutate_all과 동일할 것이다. transmute_if에서 두 번째 인자(transmute_if(function(x) ...)는transmute_if(., function(x) ...)dptj.가 생략된 형태로 두 번째 인자는function(x) ...이다)는 열 벡터를 입력하면 참 또는 진리값을 출력하는 함수이고, 이 함수를 통해 어떤 열에 함수를 적용할지가 결정된다. 이때 미리 마련된 함수가 있지 않다면function(x) ...과 같은 부분이 추가될 것인데,dplyr에서는 이 부분을 간단하게 만들 수 있는 방법이 있다. 다음의 예를 보자.
mtcars %>% transmute_if(function(x) sum(x)<100, exp) %>% head(n=3)
## vs am carb ## 1 1.000000 2.718282 54.598150 ## 2 1.000000 2.718282 54.598150 ## 3 2.718282 2.718282 2.718282
mtcars %>% transmute_if(funs(sum(.) <100), exp) %>% head(n=3)
## vs am carb ## 1 1.000000 2.718282 54.598150 ## 2 1.000000 2.718282 54.598150 ## 3 2.718282 2.718282 2.718282
vars는 열을 선택할 때 편의를 제공하고,funs는 함수를 만들 때 편의를 제공하는 함수라고 생각하면 편하다. 다음의 예를 보자 그 의미를 파악해보자.
mtcars %>% mutate_if(funs(sum(.) >= 100), funs(paste(.,"+",sep=""))) %>% head(n=3)
## mpg cyl disp hp drat wt qsec vs am gear carb ## 1 21+ 6+ 160+ 110+ 3.9+ 2.62+ 16.46+ 0 1 4+ 4 ## 2 21+ 6+ 160+ 110+ 3.9+ 2.875+ 17.02+ 0 1 4+ 4 ## 3 22.8+ 4+ 108+ 93+ 3.85+ 2.32+ 18.61+ 1 1 4+ 1
mtcars %>% transmute_at(vars(starts_with('d')), exp) %>% head(n=3)
## disp drat ## 1 3.069850e+69 49.40245 ## 2 3.069850e+69 49.40245 ## 3 8.013164e+46 46.99306
Leave a comment