패키지 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