2.7 요인(factor)과 테이블(table)

  • 요인(factor) 데이터 타입은 통계학에서 범주형 변수(categorical variable)을 표현하기 위한 R의 데이터 타입으로 범주형 자료는 크게 명목형(nominal)과 순서형(ordinal) 으로 구분
  • 테이블(table) 객체는 factor 객체에 대한 빈도를 나타내기 위해 사용

범주형 자료

  • 데이터가 사전에 정해진 특정 유형으로만 분류되는 경우: 성별, 인종, 혈액형 등
  • 범주형 자료는 명목형과 순서형으로 구분 가능
  • 순서형 자료 예: 성적, 교육수준, 선호도, 중증도 등

2.7.1 요인(factor)

  • 범주형 자료를 표현하기 위한 R의 객체 클래스
  • Factor는 정수형 벡터를 기반으로 levels (수준) 이라는 속성이 추가된 객체임
  • 숫자 또는 문자로 표현 되었다 하더라도 범주형으로 이해
  • Factor는 level에 해당하는 값만 가질 수 있는 벡터로 간주
  • Factor 생성 함수
# factor 정의 함수
factor(data, # factor로 표현하고자 하는 값. 주로 문자형
       levels, # 요인의 수준, 미리 정한 값
       labels, # 수준에 대한 레이블링
       ordered # 순서형 자료 표시 여부
               # TRUE/FALSE, default = FALSE
       )

  • 수치형을 factor로 만들어도 처음 입력 값은 문자형으로 변하고 level 값으로 치환
  • 대신 (1, 2, 3)이 중심값이 됨 \(\rightarrow\) 정수형 벡터임
score <- rep(c(4:6), each = 4)
fscore <- factor(score)

typeof(fscore) # factor의 기본 데이터 타입
[1] "integer"
attributes(fscore) # factor의 속성
$levels
[1] "4" "5" "6"

$class
[1] "factor"
# factor의 구조
str(fscore)
 Factor w/ 3 levels "4","5","6": 1 1 1 1 2 2 2 2 3 3 ...
# levels(): factor의 수준(levels) 반환 함수
levels(fscore)
[1] "4" "5" "6"
# nlevels(): level의 개수 반환
nlevels(fscore)
[1] 3

  • Factor를 벡터 결합 함수 c()로 결합
c(fscore, factor(4)) # 강제로 정수형 벡터로 변환
 [1] 4 4 4 4 5 5 5 5 6 6 6 6 4
Levels: 4 5 6

  • Factor의 범주 수준(level) 및 범주명(label) 지정
x <- rep(c(1:2), each = 4)

# factor의 범주 수준 지정
sex <- factor(x, levels = 1:2)
sex
[1] 1 1 1 1 2 2 2 2
Levels: 1 2
# factor의 범주 수준 및 범주 명칭 지정
sex <- factor(x, levels = 1:2, labels = c("male", "female"))
sex # level의 값이 명칭으로 변경
[1] male   male   male   male   female female female female
Levels: male female
str(sex)
 Factor w/ 2 levels "male","female": 1 1 1 1 2 2 2 2
# 값은 존재하지 않으나 수준을 미리 정해 놓은 경우
severity <- factor(1:2, levels = c(1, 2, 3), labels = c("Mild", "Moderate", "Severe"))
severity[2] <- "Severe"

# 존재하지 않는 수준 할당 
severity[1] <- "Good"
Warning in `[<-.factor`(`*tmp*`, 1, value = "Good"): 요인의 수준(factor
level)이 올바르지 않아 NA가 생성되었습니다.
severity
[1] <NA>   Severe
Levels: Mild Moderate Severe

  • 순서형 factor 생성
severity <- factor(rep(1:3, times = 3), levels = 1:3, 
                   labels = c("Mild", "Moderate", "Severe"), 
                   ordered = T)
severity
[1] Mild     Moderate Severe   Mild     Moderate Severe   Mild     Moderate
[9] Severe  
Levels: Mild < Moderate < Severe
is.ordered(severity) # 순서형 범주 체크
[1] TRUE

요인형 객체에 적용되는 일반적인 함수

tapply() 함수

  • 특정 요인 수준의 고유한 조합으로 각 그룹에 속한 값에 특정 함수를 적용한 결과를 반환
  • 일반적인 함수 사용 형태는 아래와 같음
# tapply() 함수 사용 인수
tapply(
  x, # 벡터, 
  INDEX, # 벡터를 그룹화할 색인(factor)
  FUN, # 각 그룹마다 적용할 함수
)

  • 예시: 2020년 4월 15일 총선의 연령별 지지율
# 문자열을 INDEX의 인수로 받은 경우

x <- c(48, 43, 27, 52, 38, 
       67, 23, 58, 72, 85) # 유권자 연령
f <- rep(c("더불어민주당", "미래통합당"), each = 5)
t <- tapply(x, f, mean) # f의 요인 수준 별 x (연령) 평균 계산
t
더불어민주당   미래통합당 
        41.6         61.0 
# x, f 순서를 랜덤하게 섞은 다음 결과
set.seed(12345) # 난수 생성 결과 고정
idx <- order(runif(10))
x <- x[idx]
f <- f[idx]

tapply(x, f, mean)
더불어민주당   미래통합당 
        41.6         61.0 

  • Factor가 2개 이상인 경우 두 factor 객체의 수준의 조합(AND 조건)에 따른 그룹을 만든 후 그룹별 함수 적용
s <- rep(c("M","F"), each = 6)
income <- c(35, 42, 68, 29, 85, 55, 
            30, 40, 63, 27, 83, 52) * 100 # 단위: 만원
age <- c(32, 36, 44, 25, 55, 41, 
         28, 33, 46, 23, 54, 44)

set.seed(12345) # 난수 생성 결과 고정
idx <- order(runif(12))
s <- s[idx]; income <- income[idx]; age <- age[idx]

# age <= 40 -> 1, 40 < age <= 50 -> 2, 
# age >= 50 -> 3 할당: ifelse() 함수 사용
age <- ifelse(age <= 40, 1, 
       ifelse(age <= 50, 2, 3))

tapply(income, list(sex = s, age = age), mean)
   age
sex        1    2    3
  F 3233.333 5750 8300
  M 3533.333 6150 8500

R에서 가장 많이 활용되는 함수 계열 중 하나로 *apply()를 들 수 있다. 벡터, 행렬 등과 같은 R 객체에 for loop 대신 반복적으로 동일한 함수를 적용할 때 활용된다. *apply() 계열 함수에 대해서는 데이터 프레임 에서 더 상세하게 배울 것임

split() 함수
  • tapply()는 주어진 요인의 수준에 따라 특정 함수를 적용하지만, split()은 데이터를 요인의 수준(그룹) 별로 데이터를 나누어 리스트 형태로 반환
# split() 함수 사용 인수
split(
  x, # 분리할 데이터(벡터)
  f, # 데이터를 분리할 기준이 되는 factor 지정
)

  • split() 함수 사용 예시
# 성별의 수준 남녀 별 소득 수준 분리
split(income, s)
$F
[1] 8300 5200 3000 4000 6300 2700

$M
[1] 5500 8500 3500 6800 4200 2900
# 두 개 요인 조합으로 income 벡터 분리 
split(income, list(s, age))
$F.1
[1] 3000 4000 2700

$M.1
[1] 3500 4200 2900

$F.2
[1] 5200 6300

$M.2
[1] 5500 6800

$F.3
[1] 8300

$M.3
[1] 8500
# 요인의 각 수준에 대한 인덱스를 반환하고자 하는 경우
abalone <- read.csv("http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data", 
    header = FALSE) # 전복 데이터셋
# V1: 전복의 종류
# F=암컷; M=수컷, I=새끼
g <- abalone[, 1] # 전복종류만 추출

set.seed(20200410)
idx <- sample(1:length(g), size = 10)
g <- g[idx]
split(1:length(g), g)
$F
[1] 1 6 8

$I
[1] 2 3 5 7

$M
[1]  4  9 10

2.7.2 테이블(table)

  • 범주형 변수의 빈도 또는 분할표(교차표)를 표현하기 위한 객체(클래스)
  • 범주 별 통계량(평균, 표준편차, 중위수, …) 요약

tapply() 함수를 이용한 테이블 만들기

  • 길이가 12인 임의의 벡터 u를 수준의 개수가 각각 3, 2인 factor의 조합으로 부분벡터로 분리 후 length() 적용 \(\rightarrow\) tapply() 함수 사용
u <- runif(12)
f1 <- factor(c(4, 4, 3, 5, 5, 4, 
               3, 3, 4, 5, 5, 3))
f2 <- factor(c("a", "a", "a", "a", "b", "a", 
               "b", "b", "a", "a", "b", "b"))
tapply(u, list(f1, f2), length)
  a  b
3 1  3
4 4 NA
5 2  2

  • u의 값과 상관 없이 두 factor 형 변수 f1f2의 조합에 따른 개수 반환 \(\rightarrow\) 분할표(contingency table)
  • 위 예시에서 f1이 “4” 이고 f2가 “b” 인 경우는 없기 때문에 0 값이 있어야 하나, tapply() 함수 적용 시 결측값 NA를 반환
  • table(): 하나 이상의 factor의 수준 또는 수준의 조합으로 분할표 생성
  • Factor가 3개 이상인 경우 배열로 다차원 분할표 표현
# table() 적용 예시
t1 <- table(f1, f2)
t1
   f2
f1  a b
  3 1 3
  4 4 0
  5 2 2
typeof(t1); attributes(t1); str(t1)
[1] "integer"
$dim
[1] 3 2

$dimnames
$dimnames$f1
[1] "3" "4" "5"

$dimnames$f2
[1] "a" "b"


$class
[1] "table"
 'table' int [1:3, 1:2] 1 4 2 3 0 2
 - attr(*, "dimnames")=List of 2
  ..$ f1: chr [1:3] "3" "4" "5"
  ..$ f2: chr [1:2] "a" "b"
# factor가 한개인 경우
table(f1)
f1
3 4 5 
4 4 4 
# factor가 3개인 경우
year = c("1","1","2","3","3","4")
gender = c("M","M","F","M","F","F")
grade = c("A","C","B","B","A","C")

table(gender, grade, year)
, , year = 1

      grade
gender A B C
     F 0 0 0
     M 1 0 1

, , year = 2

      grade
gender A B C
     F 0 1 0
     M 0 0 0

, , year = 3

      grade
gender A B C
     F 1 0 0
     M 0 1 0

, , year = 4

      grade
gender A B C
     F 0 0 1
     M 0 0 0