팩터 자료 다루기
팩터 자료형
<출처: Youtube/Datacamp>
팩터형은 범주형 데이터를 저장하는 데 사용한다. 범주형 데이터는 순위를 정할 수 있는 순위형 데이터와 순위가 없는 범주형 데이터로 나뉠 수 있듯이 R의 팩터형 데이터도 순위가 있는 순위형(ordered
)과 순위가 없는 팩터형(factor
)으로 나뉜다. 일단 팩터형과 순위형 벡터를 만드난 방법은 다음과 같다.
x <- factor(c('A', 'B', 'A', 'A', 'C', 'B'))
x
## [1] A B A A C B ## Levels: A B C
class(x)
## [1] "factor"
팩터 벡터를 출력하면 언뜻 보기에 문자열처럼 보이지만 문자열 벡터와 달리 "
(따옴표)가 없다. 그리고 Levels:
를 통해 특정한 수준의 값을 가질 수 있는 팩터형임을 알려준다. class()
함수를 통해 벡터의 클래스를 확인할 수도 있다.
x <- ordered(c('High', 'Medium', 'Low', 'Medium', 'Low'),
levels=c('Low', 'Medium', 'High'))
x
## [1] High Medium Low Medium Low ## Levels: Low < Medium < High
class(x)
## [1] "ordered" "factor"
순위형 벡터는 ordered()
함수를 사용한다. 이때 순위는 levels=
를 통해 낮은 순위부터 높은 순위까지의 범주를 지정해준다. 순위형 벡터의 출력 결과는 팩터형 벡터의 출력 결과와 거의 비슷하지만 Levels:
에 부등호(<
)를 통해 범주 사이의 순위를 알려준다. 순위형 벡터는 factor
형의 모든 특징을 갖고, ordered
형의 특징(범주 사이의 순위)를 추가된다.
팩터형의 중요성
팩터형은 데이터 분석에 있어서 중요한 역할을 한다. 특히 어떤 변수가 팩터형이냐 연속형이냐에 따라서 분석 결과가 판이하게 달라질 수 있다. 다음은 변수 x
에 1
, 2
, 3
중 하나의 값이 들어 있다. 이때 변수 x
를 연속형으로 놓고 분석할 때와 범주형으로 놓고 분석할 때 결과가 달라짐을 확인할 수 있다.
n = 30
x <- sample(1:3, n, replace=TRUE); x
## [1] 2 1 1 3 2 1 2 3 1 1 3 3 1 1 3 2 2 3 2 1 2 2 3 1 1 3 3 1 3 3
y <- ifelse(x>2, x + rnorm(n), rnorm(n)-x)
lm(y ~ x)
## ## Call: ## lm(formula = y ~ x) ## ## Coefficients: ## (Intercept) x ## -3.421 1.838
x <- as.factor(x)
lm(y~x)
## ## Call: ## lm(formula = y ~ x) ## ## Coefficients: ## (Intercept) x2 x3 ## -0.6444 -1.6830 3.6753
앞의 두 분석 결과의 차이는 다음과 같이 시각적으로 나타낼 수 있다. 좀 더 자세한 내용은 데이터 분석 관련 도서나 이 책의 다음 시리즈인 <
R로 하는 빅데이터 분석: 통계 분석과 기계 학습>
을 참조하자.
데이터 전처리에 있어서 팩터형
하지만 팩터형은 데이터를 전처리하기에 까다롭다는 단점이 있다. 그래서 몇몇 분석가들은 데이터 전처리를 할 때에는 문자열형으로 유지를 하다가 분석 직전에 팩터형으로 변환하라고 조언한다. 구체적으로 팩터형은 쉽게 새로운 범주를 추가하거나, 범주가 다른 두 팩터를 합칠 수 없다. 아래는 팩터형 fac1
의 경우 기존의 수준인 b
를 5번째 원소로 추가하는 것은 가능하지만 새로운 수준 c
를 6번째 원소를 추가할 수 없음을 보여준다.[1]
fac1 <- factor(c('a', 'b', 'b', 'a'))
fac1[5] <- 'b'
fac1[6] <- 'c'
## Warning in `[<-.factor`(`*tmp*`, 6, value = "c"): invalid factor level, NA ## generated
fac1
## [1] a b b a b <NA> ## Levels: a b
[1]: 이런 문제점 때문에 data.frame을 생성하거나 화일에서 불러올 때 straingsAsFactors=FALSE
로 놓기를 권장하기도 한다.
다음의 예는 두 팩터형 벡터를 합칠 때의 문제점을 보여준다.
fac1
## [1] a b b a b <NA> ## Levels: a b
fac2 <- factor(c('a', 'b', 'c', 'c', 'b'))
c(fac1, fac2)
## [1] 1 2 2 1 2 NA 1 2 3 3 2
c(fac1, fac2)
를 통해 팩터형 두 벡터 fac1
와 fac2
를 합친 결과는 생뚱맞게 1
, 2
등의 숫자이다. 이것은 팩터형 데이터 내부적으로 정수로 표기되기 때문이다. 어쨋든 우리가 원했던 결과가 아님은 분명하다.
이런 문제점을 해결하기 위해 Hadley는 forcats
라는 패키지를 만들었다. 여기서는 이 패키지를 활용하여 팩터형 데이터를 다루는 방법을 설명한다. 이에 대한 대안은 앞에서 말했듯이 팩터형 데이터를 모두 문자열로 바꾼 후 전처리를 하는 것이다. 문자열의 경우에는 새로운 수준을 도입하거나 수준이 다른 두 자료를 합치는 데에 아무런 문제가 없다.[2]
str1 <- c('a', 'b', 'b', 'a')
str1[5] <- 'c'
str1
## [1] "a" "b" "b" "a" "c"
str2 <- c('a', 'd', 'd', 'c')
c(str1, str2)
## [1] "a" "b" "b" "a" "c" "a" "d" "d" "c"
[2]: 만약 주어진 자료가 팩터형이라면 as.character()
함수를 통해 일단 문자형으로 바꾼 후 원하는 작업을 실시한다. 특히 범주가 숫자인 팩터형 벡터를 수치형 벡터로 변환할 때 주의해야 한다. as.numeric(x)
는 거의 항상 틀린 방법이다. as.numeric(as.character(x))
로 해야 한다. 예를 들어 수준이 1
, 10
, 100
인 팩터형에 대해 as.numeric()
을 하면 결과가 1
, 10
, 100
이 되리라 예상하지만 결과는 1
, 2
, 3
이 된다. 반면 as.character()
를 하면 결과는 "1"
, "10"
, "100"
이다.
forcats
패키지
forcats
패키지는 FOR CATegorical data(?)란 의미인 듯 하다. 이 패키지의 함수는 크게 다음과 같이 분류할 수 있다.
- 팩터형의 수준 순서를 바꾸는 함수
- 수준을 합치거나 이름을 바꾸는 함수
- 새로운 수준을 추가하는 함수
- 그 밖의 함수
팩터형의 수준 순서 바꾸기
fct_relevel()
함수를 사용하여 수준의 순서를 지정해 줄 수 있다. 순서가 지정된 수준 외에는 기존의 순서가 유지된다.
library(forcats)
x <- as.factor(x)
x
## [1] 2 1 1 3 2 1 2 3 1 1 3 3 1 1 3 2 2 3 2 1 2 2 3 1 1 3 3 1 3 3 ## Levels: 1 2 3
fct_relevel(x, '3', '2', '1')
## [1] 2 1 1 3 2 1 2 3 1 1 3 3 1 1 3 2 2 3 2 1 2 2 3 1 1 3 3 1 3 3 ## Levels: 3 2 1
fac2
## [1] a b c c b ## Levels: a b c
fct_relevel(fac2, 'b', 'a')
## [1] a b c c b ## Levels: b a c
- 사실 순위가 없는 팩터의 경우에 순서는 데이터 분석에서 큰 영향을 미치지 못한다. 하지만 자료를 보기 싶게 출력할 때에는 도움을 줄 수 있다. 다음의 코드에서
fct_infreq
는 범주를 출현 빈도순서로 배치함으로써table()
의 결과를 좀 더 읽기 쉽게 해준다.
x <- factor(unlist(strsplit(
'wzwzzwzwzcczwzdzczwzwzdzdddzdyydddddwzwwwdddzzddddzdzzd',''
)))
table(x)
## x ## c d w y z ## 3 20 11 2 19
x <- fct_infreq(x)
table(x)
## x ## d z w c y ## 20 19 11 3 2
팩터의 범주 순서를 바꾸는 함수는 이 밖에도 fct_reorder()
, fct_reorder2()
등이 있다.
수준을 합치거나 이름을 바꾸는 함수
팩터의 범주 이름을 바꾸고 싶다면 fct_recode()
함수를 사용한다. 앞에서 의미 모를 문자로 이루어졌던 팩터형 벡터 x
의 범주 이름을 다음과 같이 의미있는 단어로 바꿀 수 있다.
# dog=개, zebra=얼룩말, whimbrel=중부리도요, catfish = 메기, yak=야크
x2 <- fct_recode(x,
"dog"="d", "zebra"="z", "whimbrel"="w",
"catfish"="c", "yak"="y")
x2
## [1] whimbrel zebra whimbrel zebra zebra whimbrel zebra ## [8] whimbrel zebra catfish catfish zebra whimbrel zebra ## [15] dog zebra catfish zebra whimbrel zebra whimbrel ## [22] zebra dog zebra dog dog dog zebra ## [29] dog yak yak dog dog dog dog ## [36] dog whimbrel zebra whimbrel whimbrel whimbrel dog ## [43] dog dog zebra zebra dog dog dog ## [50] dog zebra dog zebra zebra dog ## Levels: dog zebra whimbrel catfish yak
- 만약 비슷한 범주를 모아 한 범주로 묶고 싶다면
fct_collapse()
함수를 사용한다.
x3 <- fct_collapse(x2,
"mammals"=c("dog", "zebra", "yak"),
"birds"="whimbrel",
"fish"="catfish")
x3
## [1] birds mammals birds mammals mammals birds mammals birds ## [9] mammals fish fish mammals birds mammals mammals mammals ## [17] fish mammals birds mammals birds mammals mammals mammals ## [25] mammals mammals mammals mammals mammals mammals mammals mammals ## [33] mammals mammals mammals mammals birds mammals birds birds ## [41] birds mammals mammals mammals mammals mammals mammals mammals ## [49] mammals mammals mammals mammals mammals mammals mammals ## Levels: mammals birds fish
- 마지막으로 범주의 갯수가 너무 많으면 데이터 분석 결과의 신뢰도가 낮아질 수 있다. 이럴 때에는 비율이 작은 범주를 하나의 범주로 묶는 것이 좋다. 다음의 코드는 팩터형 벡터
x2
에서 가장 적은 비율을 차지하는 범주whimbrel
,catfish
,yak
를Others
로 묶어준다.
x4 <- fct_lump(x2); x4
## [1] Other zebra Other zebra zebra Other zebra Other zebra Other Other ## [12] zebra Other zebra dog zebra Other zebra Other zebra Other zebra ## [23] dog zebra dog dog dog zebra dog Other Other dog dog ## [34] dog dog dog Other zebra Other Other Other dog dog dog ## [45] zebra zebra dog dog dog dog zebra dog zebra zebra dog ## Levels: dog zebra Other
새로운 수준을 추가하는 함수
-
fct_expand()
는 주어진 팩터에 새로운 범주를 추가한다. -
fct_c()
는 두 팩터 벡터를 합쳐서 새로운 팩터형 벡터를 만들어준다.
fac1; fac2
## [1] a b b a b <NA> ## Levels: a b
## [1] a b c c b ## Levels: a b c
c(fac1, fac2)
## [1] 1 2 2 1 2 NA 1 2 3 3 2
fct_c(fac1, fac2)
## [1] a b b a b <NA> a b c c b ## Levels: a b c
- 이 글은 “R로 하는 빅데이터 분석: 데이터 전처리와 시각화"의 일부를 발췌한 것입니다.
Leave a comment