패키지 dplyr 02: 수정
dplyr
의 방식 : 수정
새로운 열 추가
- 새로운 열을 추가하고자 한다면
mutate
함수를 사용한다. 열이름은 정하거나 생략할 수 있다. 여러 열을 함께 추가할 수도 있다.
library(dplyr)
data(mtcars)
tb = as_tibble(mtcars)
tb2 <- tb %>% select(hp, cyl, qsec) %>% slice(1:3)
tb2 %>% mutate(hp/cyl)
## # A tibble: 3 x 4 ## hp cyl qsec `hp/cyl` ## <dbl> <dbl> <dbl> <dbl> ## 1 110 6 16.5 18.3 ## 2 110 6 17.0 18.3 ## 3 93 4 18.6 23.2
tb2 %>% mutate(hpPerCyl = hp/cyl)
## # A tibble: 3 x 4 ## hp cyl qsec hpPerCyl ## <dbl> <dbl> <dbl> <dbl> ## 1 110 6 16.5 18.3 ## 2 110 6 17.0 18.3 ## 3 93 4 18.6 23.2
tb2 %>% mutate(hpPerCyl = hp/cyl, V2 = hp*qsec)
## # A tibble: 3 x 5 ## hp cyl qsec hpPerCyl V2 ## <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 110 6 16.5 18.3 1811. ## 2 110 6 17.0 18.3 1872. ## 3 93 4 18.6 23.2 1731.
tb2 %>% mutate(hp/cyl)
를 결과를 보면 열이름이hp/cyl
로 되어 있다.hp/cyl
과 같은 열이름은hp 나누기 cyl
과 구분할 수 없기 때문에 잘 쓰이지 않는다. 하지만hp/cyl
을 열이름으로 정해줄 수 있으며, 이를 사용하려면 다음과 같이를 사용하여 열이름을 감싸준다. (다음 예에서
mutate의 결과는 따로 변수에 담아야 함을 주의하자.)
tb2$`hp/cyl`
## Warning: Unknown or uninitialised column: 'hp/cyl'.
## NULL
tb3 <- tb2 %>% mutate(hp/cyl)
tb3$`hp/cyl`
## [1] 18.33333 18.33333 23.25000
- 다음과 같은 데이터프레임의 전통적 방법과 비교해보자.
tb$V2 = with(tb, hp*qsec)
tb[c('V1', 'V2')] = data.frame(tb$hp/tb$cyl, tb$hp*tb$qsec)
정렬하기
- 패키지
dplyr
은 데이터 프레임을 정렬하는 직관적인 방법을 제공한다. 만약tb
의cyl
열을 기준으로 정렬을 하고 싶다면,tb %>% arrange(cyl)
라고 쓴다. 내림차순 정렬은tb %>% arrange(desc(cyl))
라고 쓴다. - 기존의 방법과 비교해 보자.
dplyr 의 함수 |
기존의 방법 |
---|---|
tb %>% arrange(cyl) |
tb[order(tb$cyl), ] |
tb %>% arrange(desc(cyl)) |
tb[order(tb$cyl, decreasing = T), ] |
- 만약
cyl
의 올림차순,hp
의 내림차순으로 정렬하고 싶다면arrange()
와desc()
를 사용하면 다음과 같이 간단하게 쓸 수 있다. 기존의 방법으로는tb[order(tb$cyl, -tb$qsec),]
로 쓸 수 있다.[d2]
[d2]:다른 방법으로는 tb[order(tb$cyl, tb$qsec, decreasing = c(F, T))]]
로 쓸 수 있다. 만약 tb$cyl
이나 tb$qsec
가 문자열이었다면 이 방법을 서야 한다.
tb3 %>% arrange(cyl, desc(qsec))
## # A tibble: 3 x 4 ## hp cyl qsec `hp/cyl` ## <dbl> <dbl> <dbl> <dbl> ## 1 93 4 18.6 23.2 ## 2 110 6 17.0 18.3 ## 3 110 6 16.5 18.3
요약하기
summarise
함수[d1]는 데이터 프레임의 내용을 몇 개의 요약값으로 정리할 수 있게 도와준다. 만약tb
의hp
열의 평균을 구하고 싶다면 다음의 방법을 사용한다.
tb %>% summarise(mean(hp))
## # A tibble: 1 x 1 ## `mean(hp)` ## <dbl> ## 1 147.
tb %>% summarize(V1 = mean(hp))
## # A tibble: 1 x 1 ## V1 ## <dbl> ## 1 147.
tb %>% summarise(hpMean = mean(hp), qsecMedian =median(qsec))
## # A tibble: 1 x 2 ## hpMean qsecMedian ## <dbl> <dbl> ## 1 147. 17.7
[d1]: summarize
라고 쓸 수도 있다
- 결과는 티블 형식이다.(
# A Tibble: 1 x 1
를 주목하자.) 새로이 생성된 티블의 열이름은 새롭게 설정하지 않는다면summarsize( )
괄호 안의 수식이 그대로 지정된다(예.mean(hp
). 여러 열을 사용할 수도 있고, 여러 열을 생성할 수도 있다.
tb %>% summarise(newVar1 = mean(hp) + median(qsec))
## # A tibble: 1 x 1 ## newVar1 ## <dbl> ## 1 164.
tb %>% summarise(newVar1 = mean(hp), newVar2 = median(qsec))
## # A tibble: 1 x 2 ## newVar1 newVar2 ## <dbl> <dbl> ## 1 147. 17.7
- 그리고 새롭게 생성된 열은 바로 다음 열에서 활용할 수도 있다(
newVar3 = newVar1 + newVar2
). 이는 데이터 프레임에는 사용이 불가능하다.
tb %>% summarise(newVar1 = mean(hp), newVar2 = median(qsec), newVar3 = newVar1 + newVar2)
## # A tibble: 1 x 3 ## newVar1 newVar2 newVar3 ## <dbl> <dbl> <dbl> ## 1 147. 17.7 164.
data.frame(mean(tb$hp), median(tb$qsec), newVar1+newVar2)
## Error in data.frame(mean(tb$hp), median(tb$qsec), newVar1 + newVar2): object 'newVar1' not found
집단별로 나누기
- 요약하는 함수
summarise
는 그 자체로도 의미가 있지만 집단을 나누는 함수group_by
와 함께 자주 쓰인다. 함수group_by
는 특정한 열의 값에 따라 티블(또는 데이터 프레임)을 나누는 역할을 한다. 다음의 예를 보자.
tb3 %>% group_by(cyl)
## # A tibble: 3 x 4 ## # Groups: cyl [2] ## hp cyl qsec `hp/cyl` ## <dbl> <dbl> <dbl> <dbl> ## 1 110 6 16.5 18.3 ## 2 110 6 17.0 18.3 ## 3 93 4 18.6 23.2
tb3_grp <- tb3 %>% group_by(cyl)
class(tb3_grp)
## [1] "grouped_df" "tbl_df" "tbl" "data.frame"
group_by
의 결과는 그룹이 나눠진 티블로 데이터 프레임과도 호환이 된다(group_by
의 결과에서# Groups: cyl [2]
를 주목하자). 집단이 나눠진 티블은 특히summarise
함수와do
함수와 함께 사용된다.
집단별로 요약하기
group_by
와summarise
함수를%>%
로 연결하여 주어진 티블을 집단별로 요약할 수 있다. 예를 들어tb
(mtcars
)에서 자동 기어(automatic)와 수동 기어(manual)로 집단을 나눈 뒤, 0.25 마일 가속 시간(qsec
)의 평균을 구하고자 한다면 다음의 명령을 활용할 수 있다.
tb %>% group_by(am) %>% summarise(mean(qsec))
## # A tibble: 2 x 2 ## am `mean(qsec)` ## <dbl> <dbl> ## 1 0 18.2 ## 2 1 17.4
- 그 결과는 위에서 확인할 수 있다. 수동(
am
= 0)일 때, 0.25 마일 가속 시간 평균은 18.2초이고, 자동(am
=1)일 때, 0.25 마일 가속 시간 평균은 17.4초임을 확인할 수 있다.
집단별로 나눈 티블에 대해 함수 적용하기
- 앞에서 요약을 하기 위해 사용한
summarise( )
의 괄호 안에 쓰이는 함수는 결과로 하나의 값을 반환해야 한다. 만약range( )
처럼 두 개의 값 (최소값과 최대값)을 반환하는 경우에는 다음과 같이 에러가 발생한다. 그리고head
처럼 데이터 프레임을 입력으로 받아 데이터 프레임을 반환하는 함수도 쓸 수 없다.
tb %>% summarise(range(hp))
## Error in summarise_impl(.data, dots): Column `range(hp)` must be length 1 (a summary value), not 2
- 집단별로 나눠진 티블(데이터테이블)에 대해 함수를 적용하여 데이터테이블이 반환되는 경우에는
do( )
함수를 쓸 수 있다. 다음의 예를 보자.
tb %>% group_by(am) %>% do(head(., n=2))
## # A tibble: 4 x 13 ## # Groups: am [2] ## mpg cyl disp hp drat wt qsec vs am gear carb V2 ## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1 2138. ## 2 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2 2978. ## 3 21 6 160 110 3.9 2.62 16.5 0 1 4 4 1811. ## 4 21 6 160 110 3.9 2.88 17.0 0 1 4 4 1872. ## # ... with 1 more variable: V1 <dbl>
- 위의 예에서
tb
는 열am
의 값에 따라 두 데이터 프레임을 나눠진 후, 각 데이터 프레임에head(., n=2)
가 적용된다. 이렇게 생성된 두 데이터 프레임이 합쳐져서 결과 데이터 프레임이 생성된다. - 집단 별로 적용되는 함수는 결과가 데이터 프레임이어야 함을 유의하자. 예를 들어
summary
함수는 데이터 프레임을 입력으로 받지만 결과는 데이터 프레임이 아니다. 하지만summary()
결과는as.data.frame
을 활용하여 쉽게 데이터 프레임으로 바꿀 수 있다.
tb %>% group_by(am) %>% do(summary(.))
## Error: Results 1, 2 must be data frames, not table
tb %>% group_by(am) %>%
do(as.data.frame(summary(.))) %>%
slice(1:3)
## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
## Warning in bind_rows_(x, .id): binding character and factor vector, ## coercing into character vector ## Warning in bind_rows_(x, .id): binding character and factor vector, ## coercing into character vector
## # A tibble: 6 x 4 ## # Groups: am [2] ## am Var1 Var2 Freq ## <dbl> <fct> <fct> <chr> ## 1 0 "" " mpg" "Min. :10.40 " ## 2 0 "" " mpg" "1st Qu.:14.95 " ## 3 0 "" " mpg" "Median :17.30 " ## 4 1 "" " mpg" "Min. :15.00 " ## 5 1 "" " mpg" "1st Qu.:21.00 " ## 6 1 "" " mpg" "Median :22.80 "
패키지 dplyr
을 활용하여 데이터 가공하기 종합
- 앞에서 소개한 함수들을 사용하여 주어진 데이터 프레임 tb에서 필요한 부분을 선별하고 집단별로 나눈 후 가공하는 절차는 보통 다음의 순서를 따른다.
tb %>% select() %>% filter() %>% group_by() %>%
summarise()
, do()
, arrange(, .by_group=T)
Leave a comment