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\) 정수형 벡터임
<- rep(c(4:6), each = 4)
score <- factor(score)
fscore
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) 지정
<- rep(c(1:2), each = 4)
x
# factor의 범주 수준 지정
<- factor(x, levels = 1:2)
sex sex
[1] 1 1 1 1 2 2 2 2
Levels: 1 2
# factor의 범주 수준 및 범주 명칭 지정
<- factor(x, levels = 1:2, labels = c("male", "female"))
sex # level의 값이 명칭으로 변경 sex
[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
# 값은 존재하지 않으나 수준을 미리 정해 놓은 경우
<- factor(1:2, levels = c(1, 2, 3), labels = c("Mild", "Moderate", "Severe"))
severity 2] <- "Severe"
severity[
# 존재하지 않는 수준 할당
1] <- "Good" severity[
Warning in `[<-.factor`(`*tmp*`, 1, value = "Good"): 요인의 수준(factor
level)이 올바르지 않아 NA가 생성되었습니다.
severity
[1] <NA> Severe
Levels: Mild Moderate Severe
- 순서형 factor 생성
<- factor(rep(1:3, times = 3), levels = 1:3,
severity 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, # 벡터를 그룹화할 색인(factor)
INDEX, # 각 그룹마다 적용할 함수
FUN, )
- 예시: 2020년 4월 15일 총선의 연령별 지지율
# 문자열을 INDEX의 인수로 받은 경우
<- c(48, 43, 27, 52, 38,
x 67, 23, 58, 72, 85) # 유권자 연령
<- rep(c("더불어민주당", "미래통합당"), each = 5)
f <- tapply(x, f, mean) # f의 요인 수준 별 x (연령) 평균 계산
t t
더불어민주당 미래통합당
41.6 61.0
# x, f 순서를 랜덤하게 섞은 다음 결과
set.seed(12345) # 난수 생성 결과 고정
<- order(runif(10))
idx <- x[idx]
x <- f[idx]
f
tapply(x, f, mean)
더불어민주당 미래통합당
41.6 61.0
- Factor가 2개 이상인 경우 두 factor 객체의 수준의 조합(AND 조건)에 따른 그룹을 만든 후 그룹별 함수 적용
<- rep(c("M","F"), each = 6)
s <- c(35, 42, 68, 29, 85, 55,
income 30, 40, 63, 27, 83, 52) * 100 # 단위: 만원
<- c(32, 36, 44, 25, 55, 41,
age 28, 33, 46, 23, 54, 44)
set.seed(12345) # 난수 생성 결과 고정
<- order(runif(12))
idx <- s[idx]; income <- income[idx]; age <- age[idx]
s
# age <= 40 -> 1, 40 < age <= 50 -> 2,
# age >= 50 -> 3 할당: ifelse() 함수 사용
<- ifelse(age <= 40, 1,
age 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, # 데이터를 분리할 기준이 되는 factor 지정
f, )
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
# 요인의 각 수준에 대한 인덱스를 반환하고자 하는 경우
<- read.csv("http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data",
abalone header = FALSE) # 전복 데이터셋
# V1: 전복의 종류
# F=암컷; M=수컷, I=새끼
<- abalone[, 1] # 전복종류만 추출
g
set.seed(20200410)
<- sample(1:length(g), size = 10)
idx <- g[idx]
g 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()
함수 사용
<- runif(12)
u <- factor(c(4, 4, 3, 5, 5, 4,
f1 3, 3, 4, 5, 5, 3))
<- factor(c("a", "a", "a", "a", "b", "a",
f2 "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 형 변수f1
과f2
의 조합에 따른 개수 반환 \(\rightarrow\) 분할표(contingency table)- 위 예시에서
f1
이 “4” 이고f2
가 “b” 인 경우는 없기 때문에 0 값이 있어야 하나,tapply()
함수 적용 시 결측값NA
를 반환 table()
: 하나 이상의 factor의 수준 또는 수준의 조합으로 분할표 생성- Factor가 3개 이상인 경우 배열로 다차원 분할표 표현
# table() 적용 예시
<- table(f1, f2)
t1 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개인 경우
= c("1","1","2","3","3","4")
year = c("M","M","F","M","F","F")
gender = c("A","C","B","B","A","C")
grade
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