Wrangle factor with forcats

Tidyverse forcats manipulate data

forcats 패키지로 범주형 데이터를 조작합니다.

유충현 https://choonghyunryu.github.io (한국알사용자회)
2022-02-28

들어가기

범주형 데이터라 부르고 factor라 읽는다.
forcats 패키지는 R에서 조작하는 것이 까다롭다는 factor의 조작에 날개를 달아줍니다.


왜 factor인가?

성별을 나타내는 gender는 두 가지로 다음처럼 표현이 가능합니다. 어느 가족의 성별 데이터를 가정합니다.

family <- c("father", "mother", "child", "child")
gender <- c("male", "female", "male", "male")
age <- c(52, 49, 22, 18)

gender
[1] "male"   "female" "male"   "male"  

그런데, 어떤 R 사용자는 다음과 같이 데이터를 코딩합니다. 범주형 데이터를 문자인 character가 아닌 factor로 코딩하는 겁니다.

family <- factor(c("father", "mother", "child", "child"))
gender <- factor(c("male", "female", "male", "male"))
age <- c(52, 49, 22, 18)

gender
[1] male   female male   male  
Levels: female male

R을 사용하는 초보자들은 factor를 다루는 것을 불편해 합니다. 그리고 질문을 합니다.

왜 굳이 factor를 만듭니까? character로 사용해도 충분하지 않나요? 나는 이제껏 character로 사용해도 문제가 없었습니다.


R은 factor에 대해서 많은 유용한 기능을 제공하고 있습니다. 예를 들면, 가족의 성별의 구성을 시각화할 경우에 아래처럼 그저 plot() 함수만 호출하면 됩니다. summary() 함수는 알아서 돗수분포표를 계산해줍니다. character는 지원하지 않는 기능입니다.

summary(gender)
female   male 
     1      3 
plot(gender)
plot(family)

레벨 변경 함수

position factor에서의 “father”, “mother”, “child”를 레벨(levels)라 합니다. 쉽게 이야기하면 범주의 종류인 셈입니다. 여기서는 범주의 종류인 레벨을 변경할 때 사용하는 함수를 다룹니다.

다음과 같은 함수를 익히게 됩니다.

함수 이름 기능
fct_recode 매뉴얼로 levels을 변경함
fct_collapse 매뉴얼로 levels을 정의된 그룹으로 축소함
fct_other levels을 “other”로 교체

fct_recode

가족을 나타내는 family의 레벨이 “father”, “mother”, “son”, “daughter”입니다. 이 영문 레벨을 한글 레벨로 고치고 싶습니다.

fct_recode() 함수는 레벨을 쉽게 재정의할 수 있습니다.

library(forcats)

family <- factor(c("father", "mother", "son", "daughter"))
family
[1] father   mother   son      daughter
Levels: daughter father mother son
fct_recode(family, 아빠 = "father", 엄마 = "mother", 자녀 = "son", 자녀 = "daughter")
[1] 아빠 엄마 자녀 자녀
Levels: 자녀 아빠 엄마

fct_collapse, fct_other

fct_collapse(), fct_other() 함수도 fct_recode() 함수와 유사한 기능을 가지고 있습니다. fct_recode() 함수로도 가능한 기능이지만, 몇 개의 레벨을 합쳐서 하나의 레벨을 만들어줍니다.


Hands-on 1

  1. 데이터 분석 과정에서 family의 레벨인 “son”, “daughter”을 “child”로 합치고 싶습니다.
    1. fct_recode() 함수를 이용하세요.
    2. fct_collapse() 함수를 이용하세요.
    3. fct_other() 함수를 이용하세요.


힌트

    • fct_recode() 함수에서 “child”로 변경하는 작업이 두 번 이루어집니다.
    • fct_other() 함수의 other_level 인수를 사용해서 레벨을 “child”로 조정합니다.

purrr

다음은 변수를 minmax로 표준화하는 purrr 패키지 구문입니다.

family <- factor(c("father", "mother", "son", "daughter"))

# 1.1
fct_recode(family, child = "son", child = "daughter")
[1] father mother child  child 
Levels: child father mother
# 1.2
fct_collapse(family, child = c("son", "daughter"))
[1] father mother child  child 
Levels: child father mother
# 1.3
fct_other(family, keep = c("father", "mother"), other_level = "child")
[1] father mother child  child 
Levels: father mother child

레벨 순서 변경 함수

앞의 예제에서 fct_recode(), fct_collapse() 함수와 fct_other() 함수로 변경한 레벨의 순서가 다름을 발견할 수 있습니다. 명목척도가 코딩된 범주형 데이터인 factor는 큰 문제가 없으나, 서열척도가 코딩된 범주형 데이터인 ordered factor의 경우는 문제가 발생할 수 있습니다.

다음과 같은 함수가 레벨의 순서를 바꿔줍니다.

함수 이름 기능
fct_relevel 매뉴얼로 levels의 순서를 변경함
fct_infreq 돗수의 크기로 levels의 순서를 변경함
fct_rev levels의 순서를 역순으로 변경함
fct_reorder 다른 변수의 정렬 순서로 levels의 순서 변경함

fct_relevel

앞의 예제에서 fct_recode()의 결과의 레벨 순서 “child”, “father”, “mother”은 알파벳 순서로 만들어진 것입니다. 이것을 fct_relevel() 함수를 이용해서 “father”, “mother”, “child”로 변경해 보겠습니다.

family2 <- fct_recode(family, child = "son", child = "daughter")
family2
[1] father mother child  child 
Levels: child father mother
fct_relevel(family2, "father", "mother", "child")
[1] father mother child  child 
Levels: father mother child

fct_rev

fct_rev() 함수는 레벨의 순서를 역방향으로 바꿔주기 때문에, “child”, “father”, “mother” 순서가 “mother”, “father”, “child” 순서로 변경됩니다.

family2 <- fct_recode(family, child = "son", child = "daughter")
family2
[1] father mother child  child 
Levels: child father mother
fct_rev(family2)
[1] father mother child  child 
Levels: mother father child

fct_infreq

앞에서 plot(gender)로 그림 돗수분포 시각화는 돗수의 무관하게 출력되었습니다. 그런데, 이제는 돗수가 제일 큰 레벨이 왼쪽에 출력되도록 레벨의 순서를 변경하려 합니다.

gender
[1] male   female male   male  
Levels: female male
gender2 <- fct_infreq(gender)
gender2
[1] male   female male   male  
Levels: male female
plot(gender2)

fct_reorder

forcats 패키지에는 사회조사 샘플 데이터를 gss_cat라는 이름의 데이터 프레임으로 제공하고 있습니다.

응답자의 결혼상태별로 일 평균 TV 시청시간을 막대 그래프로 그렸습니다.

library(dplyr)
library(ggplot2)

gss_cat %>% 
  group_by(marital) %>% 
  summarise(tvhours = mean(tvhours, na.rm = TRUE)) %>% 
  ggplot(aes(x = marital, y = tvhours)) +
  geom_col() + 
  coord_flip()


Hands-on 2

  1. 데이터 해석의 용이성을 위해서 TV 시청시간의 크기별로 결혼상태의 레벨 순서를 조정해서 시각화하세요.
    1. fct_reorder() 함수를 이용하세요.
    2. mutate() 함수를 이용하세요.


힌트

mutate() 함수를 사용한다는 것은, 데이터 집계 후 레벨의 순서를 바꾼다는 의미입니다.

purrr

다음은 변수를 minmax로 표준화하는 purrr 패키지 구문입니다.

gss_cat %>% 
  group_by(marital) %>% 
  summarise(tvhours = mean(tvhours, na.rm = TRUE)) %>% 
  mutate(marital = fct_reorder(marital, tvhours)) %>%
  ggplot(aes(x = marital, y = tvhours)) +
  geom_col() + 
  coord_flip()


솔루션

fct_reorder() 함수를 사용하여 시각화에서의 범주 순서를 바꾸는 경우는 자주 발생하는 사례이니, 꼭 기억하시기 바랍니다.


기타 함수

levels를 추가/삭제하거나 여러 개의 factor를 병합하는 함수도 제공합니다.

다음과 같은 함수가 레벨의 순서를 바꿔줍니다.

함수 이름 기능
fct_drop 사용하지 않는 levels를 제거함
fct_expand 새로운 levels를 추가함
fct_c 서로 다른 factor의 levels를 병합함

fct_drop

fct_drop() 함수는 불필요한 레벨을 삭제해 줍니다..

f <- factor(c("a", "b"), levels = c("a", "b", "c"))
f
[1] a b
Levels: a b c
[1] a b
Levels: a b

fct_expand

fct_expand() 함수는 데이터로는 포함되어 있지 않는 새로운 레벨을 추가해 줍니다. 이 기능을 데이터를 모델링하기 위해서 테스트 셋과 트레이닝 셋을 나눌 때, 어느 한 쪽의 데이터 셋에서 특정 레벨이 누락되는 것을 막아줍니다.

gender <- factor(c("male", "male", "male", "male"))
gender
[1] male male male male
Levels: male
fct_expand(gender, "female")
[1] male male male male
Levels: male female

fct_c

fct_c() 함수는 factor를 결합하고, 레벨을 합쳐줍니다.

fa <- factor(c("a", "b"))
fb <- factor("x")

fct_c(fa, fb)
[1] a b x
Levels: a b x

Citation

For attribution, please cite this work as

유충현 (2022, Feb. 28). Dataholic: Wrangle factor with forcats. Retrieved from https://choonghyunryu.github.io/2022-02-27-forcats

BibTeX citation

@misc{유충현2022wrangle,
  author = {유충현, },
  title = {Dataholic: Wrangle factor with forcats},
  url = {https://choonghyunryu.github.io/2022-02-27-forcats},
  year = {2022}
}