1.4 절에서 살펴보았듯이 범주형 변수는 관측대상이 속하는 범주를 나타내는 데이터이다. Show
범주형 변수에 대한 기술통계 분석은 범주 별로 관측빈도의 분포를
구하는 것이 주를 이룬다. 이 장에서는 한 범주형 변수에 대한 분포를 분석하는 방법과 여러 개의 범주형 변수 간의 상관성을 분석하는 방법으로 나누어 R을 이용한 기술통계 방법을 설명한다. 한 범주형 변수에 대한 분포 분석한 범주형 변수를 분석할 때 관심의 초점은 범주별 분포를 확인하는 것이다. 범주별 분포로부터 다음과 같은 통계적 질문에 대한 답을 탐구한다.
범주형 변수 분포를 수치로 요약하기 - 빈도표 구하기범주별 분포를 수치로 요약할 때는 크게 다음 두 가지 방식 중 하나를 이용한다.
절대 빈도표는 실제 관측 빈도를 확인할 수 있어 더 정확한 방식이지만, 범주 별 빈도를 한눈에 파악하기 어려운 단점이 있다. 다음은
절대 빈도표 만들기R에는 절대 빈도표를 만들기 위해 다음 명령어들을 사용할 수 있다.
이 책에서는 R의 기본 기능으로 제공하는
|
1 | 2 | 3 | 4 | |
---|---|---|---|---|
F | 0 | 14 | 3 | 1 |
M | 1 | 18 | 6 | 2 |
빈도표와 마찬가지로 R에서 교차표를 만드는 방법은 다음 네 가지 방법이 있다.
- 기본
base
패키지의table()
함수 (별도의 패키지 적재 불필요 없음) - 기본
stat
패키지의xtabs()
함수 (별도의 패키지 적재 불필요 없음) reshape2
패키지의acast()
또는dcast()
함수 (reshape2
패키지 적재 필요)dplyr
패키지의count()
함수 (dplyr
패키지 적재 필요)
이 책에서는 R의 기본 기능으로 제공하는 table()
과 xtabs()
함수를 이용하여 교차표를 만드는 방법을 설명한다.
table()
함수로 교차표 만들기
table()
함수를 사용하면 빈도표와 동일한
문법으로 두 개 이상의 범주형 변수에 대한 교차표를 구할 수 있다. 다만 인수가 하나가 아니라 두 개 또는 여러 개의 범주형 변수를 인수로 나열해 주면 된다.
table(벡터1. 벡터2, ...)
table(데이터프레임$열이름1, 데이터프레임$열이름2, ...)
다음은 course
데이터에서 성별과 학년의 교차표를 table()
함수로 구한 예이다. 첫째 인수로 기술된 변수의 범주가 행으로, 둘째 인수로 기술된 변수의 범주가 열로 표현되어 교차표가 구해지는 것을 볼 수 있다.
> table(course$gender, course$year)
1 2 3 4
F 0 14 3 1
M 1 18 6 2
만약 학년을 행으로, 성별을 열로 하여 교차표를 구하고 싶다면 다음처럼 두 인수의 위치를 바꾸어 주면 된다.
> table(course$year, course$gender)
F M
1 0 1
2 14 18
3 3 6
4 1 2
만약 세 범주형 변수의 교차표를 구하려면, 세 변수를 차례로 기술한다. 그러면 첫 번째, 두 번째, 세 번째로 기술된 변수가 각각 교차표의 행, 열, 층(layer)이 되어 3차원의 교차표가 만들어 진다. 다음은 성별을 행으로, 학년을 열로, 분반을 층으로 하여 교차표를 구한 예이다. 2차원인 컴퓨터 화면 상에서 3차원 데이터를 표현할 수 없으므로 층 별로 나누어 교차표가 나타났다. 첫 번째 행렬이 1분반의 성별-학년 교차표이고, 두 번째 행렬이 2분반의 성별-학년 교차표이다.
> table(course$gender, course$year, course$class)
, , = 1
1 2 3 4
F 0 8 2 0
M 0 10 1 1
, , = 2
1 2 3 4
F 0 6 1 1
M 1 8 5 1
xtabs()
함수로 교차표 만들기
빈도표와 마찬가지로 xtabs()
함수를 사용하면 data
인수에 데이터 프레임의 열을 $
연산자로 사용하지 않고도 지정할 수 있기 때문에 데이터에서 여러 개의 열을 지정해야 하는 교차표를 만들 때 xtabs()
는 매우 편리하다. 범주형 변수가 하나일 때와 달라진 점은 수식의 우변에 교차표에 사용될 범주형 변수를 +
로 연결하여 표현한다는 것이다.
xtabs(~ 열이름1 + 열이름2 + ..., data = 데이터프레임)
수식의 우변에 첫 번째 기술되는 변수가 행,
두 번째 기술되는 변수가 열, 세 번째 기술되는 변수가 층이 되어 교차표가 만들어 진다. 두 변수만 기술되면 행렬 형식의 교차표가 만들어 진다. 다음은 course
데이터에서 성별-학년 2차원 교차표, 성별-분반 2차원 교차표, 그리고 성별-학년-분반의 3차원 교차표를 xtabs()
함수로 구한 예이다.
> freqGenderYear <- xtabs(~ gender + year, data=course); freqGenderYear
year
gender 1 2 3 4
F 0 14 3 1
M 1 18 6 2
> freqGenderClass <- xtabs(~ gender + class, data=course); freqGenderClass
class
gender 1 2
F 10 8
M 12 15
> freqGenderYearClass <- xtabs(~ gender + year + class, data=course); freqGenderYearClass
, , class = 1
year
gender 1 2 3 4
F 0 8 2 0
M 0 10 1 1
, , class = 2
year
gender 1 2 3 4
F 0 6 1 1
M 1 8 5 1
한 범주형 변수의 빈도표를 만들 때 설명한 것처럼 xtabs()
함수의 장점은 열 이름을 table()
함수보다 편리하게 지정할 수 있다는 점뿐만 아니라, 특정 조건의 데이터만 선택하여 교차표를 만들 수 있다는 점이다. 만약 총점(score
)가 80점 이상인 학생과 미만인 학생의 성별-학년별 상관성을 나누어 분석한다고 하자. 다음처럼 subset
인수에 해당 조건인
관측만 TRUE
가 되도록 논리값 벡터를 지정해 주면 해당 조건의 관측만으로 교차표를 생성한다.
> xtabs(~ gender + year, data=course, subset = score >= 80)
year
gender 1 2 3 4
F 0 4 1 1
M 0 3 3 1
> xtabs(~ gender + year, data=course, subset = score < 80)
year
gender 1 2 3 4
F 0 10 2 0
M 1 15 3 1
교차표에서 빈도표 구하기
원 데이터에서 빈도표를 직접 구할 수도 있지만, 교차표에서 각 범주형 변수의 빈도표를 구할 수도 있다. 표 7.3처럼 course
데이터에서 성별을 행으로, 학년을 열로 한 교차표가 있으면, 행으로 교차표의 빈도를 합산하면 성별 빈도표가 만들어지고, 열로 교차표의 빈도를 합산하면 학년 빈도표가 만들어지는 것을 알 수 있다.
marginSums()
또는 margin.table()
함수를 이용하면 교차표를 행별 또는 열별로 합산하면 빈도표를 구할 수 있다. margin
은 교차표를 어느 방향으로 합산하여 빈도표를 만들지를 지정한다. 1이면 행으로, 2이면 열로 합산을 한다. margin
인수에 값을 주지 않으면 교차표의 모든 빈도를 합하여 총 빈도를 구한다.
marginSums(교차표) # 총 빈도 합산
marginSums(교차표, margin = 1) # 행으로 빈도 합산
marginSums(교차표, margin = 2) # 열로 빈도 합산
다음은 성별-학년 2차원 교차표에서 전체, 성별, 학년별 관측빈도의 합을 구한 예이다. marginSums()
함수 호출 시 margin
인수를 기술하지 않으면 교차표의 총 빈도가, margin
인수가 1이면 교차표의 행별 합이, margin
인수가 2이면 교차표의 열별 합이 결과로 주어진다.
> marginSums(freqGenderYear)
[1] 45
> marginSums(freqGenderYear, margin=1)
gender
F M
18 27
> marginSums(freqGenderYear, margin=2)
year
1 2 3 4
1 32 9 3
만약 교차표에 행별, 열별 합을 포함하여 출력하고 싶으면
addmargins()
함수를 이용한다.
> addmargins(freqGenderYear)
year
gender 1 2 3 4 Sum
F 0 14 3 1 18
M 1 18 6 2 27
Sum 1 32 9 3 45
3차원 교차표에서도 marginSums()
를 이용하여 빈도표를 만들 수 있다. 3차원 교차표에서는 margin
인수에 3을 부여하면 층별로 합산이 이루어 진다. 다음은 성별-학년-분반 교차표에서 전체 총 빈도, 성별 빈도, 학년 빈도, 분반별 빈도를 구한 예이다.
> marginSums(freqGenderYearClass)
[1] 45
> marginSums(freqGenderYearClass, margin=1)
gender
F M
18 27
> marginSums(freqGenderYearClass, margin=2)
year
1 2 3 4
1 32 9 3
> marginSums(freqGenderYearClass, margin=3)
class
1 2
22 23
3차원 교차표에서는 marginSums()
를 이용하여 2차원 교차표도 만들 수 있다. 예를 들어 성별-학년-분반 교차표에서 행과 열을 기준으로 합산을 하면 층은 사라지고 성별-학년 교차표가 된다. 또는 행과 층을 기준으로 합산하면 성별-분반 교차표가 된다.
> marginSums(freqGenderYearClass, margin=c(1, 2))
year
gender 1 2 3 4
F 0 14 3 1
M 1 18 6 2
> marginSums(freqGenderYearClass, margin=c(1, 3))
class
gender 1 2
F 10 8
M 12 15
상대 빈도로 교차표 구하기
절대 빈도로 표시된 성별-학년 교차표는 각 범주 조합이 몇 번 관측되었는지를 파악할 수 있으나, 전체 관측에서 차지하는 비중이 얼마인지 파악하기 힘들다. 예를 들어 남자와 여자의 학년별 비율이 차이가 있는지를 살펴보려면 상대 빈도로 교차표를 이용하는 것이 좋다.
상대 빈도로 빈도표를 만들 때와 마찬가지로 proportions()
나 prop.table()
함수를 이용하면 절대 빈도 교차표에서 상대 빈도 교차표를 구할 수 있다. 2차원 절대 빈도 교차표에서 상대 빈도 교차표를 만드는 방법은 다음 세 가지 방법이 있다.
- 전체 관측 도수를 1로 하여 각 범주 조합의 상대적 비율을 나타낸다.
- 절대 빈도 교차표의 각 행의 빈도 합을 1로 하여 행별로 상대적 비율을 나타낸다.
- 절대 빈도 교차표의 각 열의 빈도 합을 1로 하여 열별로 상대적 비율을 나타낸다.
propotions()
함수의 문법은 다음과 같다.
propotions(절대빈도교차표) # 총 관측 도수 대비 상대 빈도
propotions(절대빈도교차표, margin = 1) # 행별 상대 빈도
propotions(절대빈도교차표, margin = 2) # 열별 상대 빈도
다음은 성별-학년 절대빈도 교차표에서 전체 관측 도수를 1로 하여 상대 빈도를 구한 예이다. 전체 45명 학생에 대한 관측 중 남자이면서 2학년인 학생이 40%를 차지함을 볼 수 있다. 전체 합이 1이 되는 것을 확인하라.
> proportions(freqGenderYear)
year
gender 1 2 3 4
F 0.00000000 0.31111111 0.06666667 0.02222222
M 0.02222222 0.40000000 0.13333333 0.04444444
전체 관측도수 대비 상대적 빈도뿐 아니라 교차표의 행별, 열별 상대 빈도를 구할 수도 있다. 다음 중 첫 번째 예는 행별 상대 빈도, 즉 성별로 학년 비율을 구한 것이다. 여자 학생 중 2학년 학생은 77.8%를 차지하고 있다. 행의 합은 1이 되는 것을 확인하라. 두 번재 예는 열별 상대 빈도, 즉 학년별로 성별 비율을 구한 것이다. 3학년 학생 중 여학생은 33.3%임을 알 수 있다. 열의 합이 1이 되는 것을 확인하라. 이렇듯 어떤 범주형 변수의 값에 따라(조건) 나머지 범주형 변수의 비율(상대 빈도)을 확인하고 싶으면, 조건이 되는 범주형 변수의 값에 따라 상대 빈도를 구하여 주면 된다.
> proportions(freqGenderYear, 1)
year
gender 1 2 3 4
F 0.00000000 0.77777778 0.16666667 0.05555556
M 0.03703704 0.66666667 0.22222222 0.07407407
> proportions(freqGenderYear, 2)
year
gender 1 2 3 4
F 0.0000000 0.4375000 0.3333333 0.3333333
M 1.0000000 0.5625000 0.6666667 0.6666667
3차원 이상의 절대빈도 교차표에 대해서도 proportions()
함수를 이용하면 상대 빈도표를 구할 수 있다. proportions()
의 margin
인수를 설정하는 방식은 marginSums()
함수를 3차원 교차표에 적용할 때와 동일한 방식으로 하면 된다. margin
은 1, 2, 3으로 주면 행, 열, 층별 합이 1이 되도록 상대 빈도표를 구한다. 두 개 이상의 차원을 margin
에 지정하면 두 차원이 교차되는 셀들의 합이 1이 되도록 상대 빈도표를 구한다. 다음은 성별-학년-분반
교차표에서 행, 열, 층별 상대 빈도와, 행-열 조합을 1로 하였을 때의 상대 빈도표를 구한 예이다.
> proportions(freqGenderYearClass, margin = 1) # 두 층으로 이루어진 한 행의 합은 1
, , class = 1
year
gender 1 2 3 4
F 0.00000000 0.44444444 0.11111111 0.00000000
M 0.00000000 0.37037037 0.03703704 0.03703704
, , class = 2
year
gender 1 2 3 4
F 0.00000000 0.33333333 0.05555556 0.05555556
M 0.03703704 0.29629630 0.18518519 0.03703704
> proportions(freqGenderYearClass, margin = 2) # 두 층으로 이루어진 한 열의 합은 1
, , class = 1
year
gender 1 2 3 4
F 0.0000000 0.2500000 0.2222222 0.0000000
M 0.0000000 0.3125000 0.1111111 0.3333333
, , class = 2
year
gender 1 2 3 4
F 0.0000000 0.1875000 0.1111111 0.3333333
M 1.0000000 0.2500000 0.5555556 0.3333333
> proportions(freqGenderYearClass, margin = 3) # 한 층의 합은 1
, , class = 1
year
gender 1 2 3 4
F 0.00000000 0.36363636 0.09090909 0.00000000
M 0.00000000 0.45454545 0.04545455 0.04545455
, , class = 2
year
gender 1 2 3 4
F 0.00000000 0.26086957 0.04347826 0.04347826
M 0.04347826 0.34782609 0.21739130 0.04347826
> proportions(freqGenderYearClass, margin = c(1, 2)) # 같은 행-열에 위치한 셀의 합은 1
, , class = 1
year
gender 1 2 3 4
F 0.5714286 0.6666667 0.0000000
M 0.0000000 0.5555556 0.1666667 0.5000000
, , class = 2
year
gender 1 2 3 4
F 0.4285714 0.3333333 1.0000000
M 1.0000000 0.4444444 0.8333333 0.5000000
범주형 변수의 상관성을 그래프로 요약하기
교차표를 가지고 두 범주형 변수의 관계를 확인할 수 있지만, 그래프로 표현하는 것이 한 눈에 파악하기 좋다. 두 범주형 변수의 상관성을 나타내는 방법으로는 주로 막대 그래프와 모자이크 그래프가 자주 사용된다.
두 범주형 변수의 막대 그래프 그리기
쌓은 막대 그래프 그리기
두 범주형 변수의 관계를 막대 그래프로 나타내는 방법은, 두 범주형 변수 중 한 변수를 가로축(x
)으로, 다른 범주형 변수를 막대의 채우기 색상(fill
)으로 달리 표시하여 관측 도수를 표현한다. 다음은 ggplot2
패키지에서는 geom_bar()
함수를 이용하여 두 범주형 변수의 막대 그래프를 그리는 문법이다.
ggplot(데이터, aes(x = 범주형변수1, fill = 범주형변수2)) + geom_bar()
다음은 geom_bar()
함수를 이용하여 학년-성별 분포를 막대 그래프로 표현한 것이다. 학년을 가로축에, 성별에 따라 막대의 채우기 색상이 달라지도록 매핑하였다.
> ggplot(course, aes(x = year, fill = gender)) + geom_bar()
위의 그래프처럼 한 범주를 기준으로 막대를 쌓아서 그리는 그래프를 쌓은 막대 그래프라고 한다. 쌓은 막대 그래프는 중심이 되는 변수-여기서는 학년-에 대한 분포가 막대의 크기로 표현되어 있어서 중심이 되는 범주형 변수의 분포를 확인할 수 있는 동시에, 중심이 되는 변수의 값이 정해져 있을 때 나머지 변수의 분포의 차이를 비교하기 좋다. 위의 쌓은 막대 그래프에서 2학년이 가장 빈도가 많으며, 2 학년이 남/녀 성별 비율이 가장 균형을 이루고 있다는 것을 확인할 수 있다.
나란한 막대 그래프 그리기
쌓은 막대 그래프는 중심이 되는 변수-가로축에 매핑되는 변수-의 절대 빈도를
파악하기 쉬운 장점이 있으나, 두 범주형 변수의 범주 값의 조합 중 가장 빈도가 높은 조합이 무엇인지 한 눈에 파악하기 어렵다. 그리고 한 범주형 변수의 값이 정해져 있을 때 다른 범주형 변수의 분포의 차이를 파악하기도 어렵다. 나란한 막대 그래프는 채우기 색상(fill
)에 매핑된 범주형 변수의 값에 따라 나타나는 막대를 쌓아 표현하는 것이 아니라 나란히 표시하여 각 범주 조합의 절대 빈도를 파악할 수 있다.
다음은 geom_bar()
함수를 이용하여 나란한 막대 그래프를 그리는 문법이다. 쌓은 막대 그래프의 문법과 동일한데, 다만 geom_bar()
함수의 position
인수를 "dodge"
로 설정하는 것만 다르다.(따옴표가 있다는 것에 주의.) ggplot2
패키지에서 position
문법의 의미를 자세히 알고자 하는 독자는 R 프로그래밍의
ggplot2의 위치 조정 절을 참조하기 바란다.
ggplot(데이터, aes(x = 변수1, fill = 변수2)) + geom_bar(position = "dodge")
다음은 앞에서 그린 학년과 성별 변수에 대하여 쌓은 막대 그래프를 나란한 막대 그래프를 그린 것이다. 절대 빈도가 가장 큰 조합은 2학년-남(M)학생 조합임을 알 수 있다. 학년 별로 성별 분포를 확인할 수 있는데, 다른 색상으로 표현된 막대의 크기에서 모두 학년에서 남자가 많았음을 확인할 수 있다. 1학년은 남학생밖에 없기 때문에 하나의 막대만 표시되었다.
> ggplot(course, aes(x = year, fill = gender)) + geom_bar(position = "dodge")
x
와 fill
의 매핑을 서로 바꾸면, 성별로 학년 분포(절대 빈도)를 확인할 수 있다. 남, 녀 모두 2학년이 가장 많았고, 그 다음 3학년, 4학년 순으로 수강하고 있음을 볼 수 있다.
> ggplot(course, aes(x = gender, fill = year)) + geom_bar(position = "dodge")
상대 빈도로 막대 그래프 그리기
그런데 학년별로 성별 비율의 상대적 차이를 분석하고자 한다면, 절대 빈도로 그래프를 그려주는 쌓은 막대 그리프나, 나란한 막대 그래프보다는 상대 빈도로 막대 그래프를 그리는 것이 좋다. 상대 빈도로 그리는 막대 그래프는 가로축의 범주별
관측 도수를 1이라고 할 때 색상으로 매핑된 범주의 상대 빈도를 막대의 크기로 표현한다. 다음은 geom_bar()
함수를 이용하여 상대 빈도로 막대 그래프를 그리는 문법이다. 나란한 막대 그래프의 문법과 동일한데, 다만 geom_bar()
함수의 position
인수를 "fill"
로 설정하는 것만 다르다.(따옴표가 있으며, 막대의 채우기 색상을 매핑할 때 사용하는 fill
과는 다른 의미이다. 막대의 크기를 모두 1로 채운다는 의미로 이해하면 된다.)
ggplot(데이터, aes(x = 변수1, fill = 변수2)) + geom_bar(position = "fill")
다음은 각 학년의 데이터를 100%로 하여 성별로 상대 빈도를 막대 그래프로 그려본 것이다. 이 과목의 경우 2학년보다는 3, 4학년에서 남자 학생의 비율이 더 많았음을 볼 수 있다. 이러한 차이가 우연히 발생한 것인지 통계적으로 유의미한 차이인지는 가설검정을 해보아야 알 수 있을 것이다.
> ggplot(course, aes(x = year, fill = gender)) + geom_bar(position = "fill")
범주형 변수의 상관성을 모자이크 그래프로 그리기
앞서 살펴본 상대 빈도로 막대 그래프를 그리는 방법은 한 변수의 값에 따라 다른 범주형 변수의 상대적 비율을 파악하기 쉬운 장점이 있으나, 전체 데이터에서 각 범주 조합의 비중을 파악할 수는 없어서 보는 사람들에게 왜곡된 정보를 줄 수도 있다. 반면 쌓은 막대 그래프나 나란한 막대 그래프는 절대 빈도로 막대를 그리므로 이러한 왜곡을 막을 수 있으나 상대 빈도를 비교하기 어렵다.
예를 들어 앞의 상대 빈도로 그린 막대 그래프에서 1학년 학생은 100%가 남자인 것을 볼 수 있다. 만약 이 그래프만 보고 판단하면 1학년에서 남자 학생의 비율이 매우 큰 것이 의아하게 생각될 수 있다. 그러나 사실 1학년 학생은 전체 학생 중 한 명밖에 없었고, 그 한 명이 남자였기 때문에 1학년의 성별 비율이 100% 남자로 표시된 것이다. 이 경우 1 학년 학생의 데이터가 매우 적다는 것을 표현하면 좋다.
모자이크 그래프는 한 범주형 변수의 값에 따라 다른 범주형 변수의 상대 빈도를 비교하기 좋게 표시하면서도 각 범주 조합의 비중의 크기를 파악할 수 있게 해준다. 모자이크 그래프는 가로축에 매핑되는 범주형 변수의 값의 빈도에 따라 막대의 폭을 다르게 표시한다.
모자이크 그래프는 ggplot2
를 기반으로 하는 ggmosiac
패키지로 모자이크 그래프를 그릴 수 있지만, 여기서는 vcd
패키지의 mosaic()
함수를 사용하면 모자이크 그래프를 그리도록 한다. vcd
패키지가 설치되어 있지 않으면 다음 명령이나
RStudio의 [Packages] 탭을 사용하여 설치를 하도록 한다.
> install.packages("vcd")
mosaic()
함수의 문법은 다음과 같다.
mosaic(범주형변수2 ~ 범주형변수1, data = 데이터, direction = "v)
다음은 학년-성별 모자이크 그래프를 그린 예이다. 각 학년의 성별 비율을 파악할 수 있을뿐 아니라 2학년, 3학년, 4학년 순으로 빈도가 높음을 확인할 수 있으며, 1학년은 매우 데이터가 적다는 것을 파악할 수 있다.
> library(vcd) # vcd 패키지를 먼저 적재한다.
> mosaic(gender ~ year, data = course, direction = "v")
범주형 변수의 분석 사례
관절염 치료 임상시험 데이터 분석
지금까지 범주형 변수의 분석과 관련하여 배운 내용을 이용하여 관절염 치료법에 대한 임상시험 데이터를 분석해 보자. 이 데이터는 Koch and Edwards(1988)가 새로운 관절염 치료법의 효과를 측정한 데이터이다. 이 데이터는 vcd
라는 패키지에 Arthritis
라는 이름으로 포함되어 있고 여기서는 교육의 목적으로 bizstatp
패키지에 같은 이름으로 재수록 하였다.
bizstatp
패키지가 적재되어 있지 않으면 먼저 적재한 후 다음 명령으로 Arthritis
데이터를 살펴보자.
> library(bizstatp) # bizstatp 패키지를 적재한다.
> Arthritis
ID Treatment Sex Age Improved
1 57 Treated Male 27 Some
2 46 Treated Male 29 None
3 77 Treated Male 30 None
4 17 Treated Male 32 Marked
5 36 Treated Male 46 Marked
6 23 Treated Male 58 Marked
7 75 Treated Male 59 None
8 39 Treated Male 59 Marked
9 33 Treated Male 63 None
......
이 데이터를 분석하여 다음과 같은 질문에 답을 해보자.
- 새로운 치료법은 아무 치료도 하지 않는 것보다 효과가 있는가?
- 새로운 치료법의 효과는 성별로 차이가 있는가?
본격적으로 질문에 답하기에 전에 summary()
함수로 전체 데이터에 대한 통계 요약을 해보자. 아래 결과를 보면, 이 임상시험에서 새로운 치료법을 받은(Treated) 환자와 플라시보(Placebo) 치료를 받은 환자의 수가 거의 비슷하였다. 또한 여자 환자의 수가 남자 환자의 수보다 2배 이상 많았고, 환자의 연령대는 23세부터 74세까지 있었다. 치료(플라시보 치료 포함) 후에 차도가 거의 없었던(None) 환자의 수와 약간(Some) 또는 확실히(Marked) 효과가 있었던 환자를 합친 수가 같았다.
ID Treatment Sex Age Improved
Min. : 1.00 Placebo:43 Female:59 Min. :23.00 None :42
1st Qu.:21.75 Treated:41 Male :25 1st Qu.:46.00 Some :14
Median :42.50 Median :57.00 Marked:28
Mean :42.50 Mean :53.36
3rd Qu.:63.25 3rd Qu.:63.00
Max. :84.00 Max. :74.00
그럼 이런 기본 정보를 바탕으로 새로운 치료법이 증상의 개선에 뚜렷이 도움이 되었는지 확인해 보자. 치료법(Treatment
)과 증상 개선 여부(Improved
)에 대한 교차표를 구해보니 뚜렷한 증상 개선(Marked)이 된 환자 중에는 새로운 치료법을 받은 환자(Treated)가 많았다.
> tti <- xtabs(~ Treatment + Improved, data = Arthritis)
> tti
Improved
Treatment None Some Marked
Placebo 29 7 7
Treated 13 7 21
이를 좀더 정확히 살펴보기 위해 치료법에 따른 증상 개선의 상대적 비율(%)을 구해보자. 결과에서 플라시보 치료를 받은 환자의 67%가 증상의 개선이 없었는데, 새로운 치료법을 받은 환자는 31%만 개선이 없었고, 51%의 환자는 확실한 증상 개선이 있었다.
> round(prop.table(tti, margin = 1) * 100, digits=2)
Improved
Treatment None Some Marked
Placebo 67.44 16.28 16.28
Treated 31.71 17.07 51.22
물론 이러한 차이가 통계적으로 유의미한지는 다시 가설검정을 해보아야 한다. 가설검정 방법에 대해서는 뒤에 자세히 살펴보도록 하고, 가설검정 결과만 살펴보면 치료법에 따른 증상 개선 효과의 차이는 없다는 귀무가설에 대한 검정에서 p-값이 매우 작게 나와서 치료법에 따라 증상 개선 효과가 차이가 있었다는 대립가설을 채택하게 해 준다.
Pearson's Chi-squared test
data: tti
X-squared = 13.055, df = 2, p-value = 0.001463
지금까지 분석한 내용을 다른 사람들에게 전달하기 좋도록 그래프로 나타내 보자.
> ggplot(Arthritis, aes(x = Treatment, fill = Improved)) + geom_bar(position = "dodge")
> ggplot(Arthritis, aes(x = Treatment, fill = Improved)) + geom_bar(position = "fill")
그러면 증상 개선 효과(Improved
)의 성별(gender
) 차이가 있었는지를 어떻게 분석할 수 있을까? 먼저 플라시보 치료를 받은 환자에 대하여 증상 개선 효과와 환자 성별로 교차표를 구해보자. 남자에 비해 여성 환자의 확실한(Marked) 증상 개선 사례가 많아 보인다.
> tsi_placebo <- xtabs(~ Sex + Improved, data = Arthritis, subset = Treatment == "Placebo")
> tsi_placebo
Improved
Sex None Some Marked
Female 19 7 6
Male 10 0 1
플라시보 치료를 받은 환자에 대하여 실제 성별로 증상 개선 효과의 상대적 비율이 다른지 확인해 보자. 플라시보 치료의 경우 남자 환자의 90%가 증상 개선이 없었던 반면, 여성 환자의 40% 가량은 증상의 개선이 조금 또는 확연히 있었다.
> proportions(tsi_placebo, margin = 1)
Improved
Sex None Some Marked
Female 0.59375000 0.21875000 0.18750000
Male 0.90909091 0.00000000 0.09090909
물론 이러한 수치가 관측 도수가 작아서 우연히 발생한 것일 수 있다. 그러므로 플라시보 치료자의 증상 개선 효과에 대한 성별 차이가 있었는지에 대하여 가설검정을 해보자. 관측 도수가 매우 낮은 셀이 있어서 Fisher 정확 검증으로 가설검정을 수행하였다. 결과에서 p-값이 크게 나왔으므로 성별 차이는 우연히 발생한 것이라는 귀무가설을 기각하지 못한다.
> fisher.test(tsi_placebo)
Fisher's Exact Test for Count Data
data: tsi_placebo
p-value = 0.1706
alternative hypothesis: two.sided
그러면 새로운 치료법에서는 성별로 증상 개선 효과의 차이가 있었을까? 새로운 치료법을 받은 환자에 대해 성별-증상 개선 효과의 교차표를 구하여, 성별로 증상 개선의 상대적 비율을 구해보았다. 이 경우에도 여성의 증상 개선 효과가 남자보다 크게 나타난 것으로 확인할 수 있다. 그러나 플라시보 치료자와 마찬가지로 이 차이가 통계적으로 유의미한 차이라고 보기는 어렵다.
> tsi_treated <- xtabs(~ Sex + Improved, data = Arthritis, subset = Treatment == "Treated")
> prop.table(tsi_treated, margin = 1)
Improved
Sex None Some Marked
Female 0.2222222 0.1851852 0.5925926
Male 0.5000000 0.1428571 0.3571429
> fisher.test(tsi_treated)
Fisher's Exact Test for Count Data
data: tsi_treated
p-value = 0.2204
alternative hypothesis: two.sided
지금까지 분석한 내용을 다른 사람들에게 전달하기 좋도록 그래프로 나타내 보자. 성별 변수로 측면으로 나누어 막대 그래프를 그리기 위해 facet_wrap()
함수를 이용하여 성별로 측면 그래프를 그렸다.
> ggplot(Arthritis, aes(x = Treatment, fill = Improved)) +
+ geom_bar(position = "dodge") +
+ facet_wrap(~ Sex)
> ggplot(Arthritis, aes(x = Treatment, fill = Improved)) +
+ geom_bar(position = "fill")+
+ facet_wrap(~ Sex)
막대 그래프에서 새로운 치료법을 적용하든 플라시보 치료법이든 여성이 남성에 비해 관절염의 증상 개선 효과가 더 좋은 경향을 보인다는 것을 볼 수 있다. 그러나 이 차이는 통계적으로 유의미한 확실한 차이는 아니었다.
이혼에 대한 사회조사 데이터 분석
bizstatp
패키지의 BrokenMarriage
데이터는 덴마크 사회 조사국에서 수행한 성별 및 사회적 계급에 따른 이혼 또는 영구적 남녀 관계가 깨진 빈도를 측정한 데이터이다. 이 데이터는 vcd
라는 패키지에 BrokenMarriage
라는 이름으로 포함되어 있고 여기서는
교육의 목적으로 같은 이름으로 재수록 하였다. bizstatp
패키지를 메모리에 적재하였다면 다음 명령으로 데이터를 확인할 수 있다.
Freq gender rank broken
1 14 male I yes
2 102 male I no
3 39 male II yes
4 151 male II no
5 42 male III yes
6 292 male III no
7 79 male IV yes
8 293 male IV no
9 66 male V yes
10 261 male V no
11 12 female I yes
12 25 female I no
13 23 female II yes
14 79 female II no
15 37 female III yes
16 151 female III no
17 102 female IV yes
18 557 female IV no
19 58 female V yes
20 321 female V no
이 데이터의 특징은 조사된 원 데이터-조사된 사람 한 명에 대한 관측이 행을 이루는 원래 데이터-가 아니라 이미 그룹별로 빈도가 요약된 데이터라는 것이다. 첫 번째 행은 남성이면서 1-계급에 속하는 사람이 이혼 또는 영구적 남녀 관계가 깨졌는지에 대한 물음에 그렇다고 응답(yes)한 빈도수(Freq
)를 보여준다.
이렇게 이미 그룹으로 요약된 데이터를 다룰 때는 이미 요약된 빈도수가 후속 분석에서 제대로 반영되도록 주의해야 한다. 예를 들어 성별로 이혼 빈도에 대한 교차표를 구할 때, 원 데이터를 가지고 있을 때와 마찬가지로 행 하나를 관측으로 간주하여 빈도를 세면 정확한 결과를 얻을 수 없다.
> xtabs(~ gender + broken, data = BrokenMarriage)
broken
gender yes no
male 5 5
female 5 5
BrokenMarriage
데이터처럼 이미 빈도로
요약된 데이터를 가지고 xtabs()
함수로 빈도표나 교차표를 만드려면 다음처럼 수식의 좌변에 이미 요약된 빈도를 가진 열을 기술해야 한다.
xtabs(빈도변수 ~ 범주형변수1 + ..., data = 데이터)
다음은 성별-이혼 여부 변수에 대한 교차표를 구한 예이다. 수식의 좌변에 빈도수를 가지고 있는 열 Freq
을 지정해 주어야 단순히 행의 개수를 세는 것이 아니라 빈도수 더하여 교차표를 만들어 준다.
> tgb <- xtabs(Freq ~ gender + broken, data = BrokenMarriage)
> tgb
broken
gender yes no
male 240 1099
female 232 1133
성별로 이혼률에 차이가 있는지 확인해 보자. 상대 빈도도 거의 차이가 나지 않고, 그 차이도 통계적으로 유의미하지 않음을 볼 수 있다.
broken
gender yes no
male 0.1792382 0.8207618
female 0.1699634 0.8300366
Pearson's Chi-squared test with Yates' continuity correction
data: tgb
X-squared = 0.34175, df = 1, p-value = 0.5588
그러면 사회 계급별로 이혼률에 차이가 있는지 확인해 보자. 사회 계급별로도 유의미한 차이를 보이지 않았다.
> trb <- xtabs(Freq ~ broken + rank, data = BrokenMarriage)
> proportions(trb, margin = 2)
rank
broken I II III IV V
yes 0.1699346 0.2123288 0.1513410 0.1755577 0.1756374
no 0.8300654 0.7876712 0.8486590 0.8244423 0.8243626
Pearson's Chi-squared test
data: trb
X-squared = 4.8795, df = 4, p-value = 0.2999
성별로 사회계급에 따른 이혼률의 차이가 있는지를 살펴보기 위해서 성별로 측면으로
나누어 막대 그래프를 그려보자. 이미 빈도로 요약된 데이터에 대한 막대 그래프는 geom_bar()
가 아니라 geom_col()
함수로 막대 그래프를 그린다. 두 함수에 대한 자세한 차이는 R 프로그래밍의 ggplot2 범주형 변수의 통계 요약 절을 참조 바란다. geom_col()
으로 이미 빈도로 요약된 데이터에서 막대 그래프를 그리는 문법은 다음과 같다. x
뿐 아니라 y
에 빈도를 가진 영를 매핑하여 막대 그래프를 그린다.
ggplot(데이터, aes(x = 범주형변수, y = 빈도변수)) + geom_col()
ggplot(데이터, aes(x = 범주형변수1, y = 빈도변수, fill = 범주형변수2)) + geom_col()
ggplot(데이터, aes(x = 범주형변수1, y = 빈도변수, fill = 범주형변수2)) +
geom_col(position = "dodge" or "fill")
성별로 사회 계급에 따른 이혼 빈도를 절대 빈도와 상대 빈도로 막대 그래프를 그려보면 다음과 같다.
> ggplot(BrokenMarriage, aes(x = rank, y = Freq, fill = broken)) +
+ geom_col() + facet_wrap(~ gender)
> ggplot(BrokenMarriage, aes(x = rank, y = Freq, fill = broken)) +
+ geom_col(position = "fill") + facet_wrap(~ gender)
절대 빈도를 보여주는 그래프에서 남성에 비해 여성의 계급이 4등급에 집중되어 있다는 것을 볼 수 있다. 그리고 상대 빈도를 보여주는 그래프에서 남성에 비해 여성이 사회적 등급이 높아질수록 이혼률이 약간은 증가하는 경향을 볼 수 있다. 남성과 여성으로 나누어 보았을 때 사회계급의 차이가 이혼률에 영향을 미치는지를 살펴보기 위해 성별로 이혼 여부-사회계급의 교차표를 계산해 보자. 그리고 성별로 사회계급에 따라 이혼률이 달라지는지 확인해 보자.
다음 결과에서 남자의 이혼율은 2, 4, 5 등급에서 20% 정도이고, 1, 3 등급에서 12% 정도였는데, 이러한 차이는 통계적으로 유의미한 차이로 분석되었다.
> tbr_male <- xtabs(Freq ~ broken + rank, data = BrokenMarriage, subset = gender == "male")
> prop.table(tbr_male, margin = 2)
rank
broken I II III IV V
yes 0.1206897 0.2052632 0.1257485 0.2123656 0.2018349
no 0.8793103 0.7947368 0.8742515 0.7876344 0.7981651
Pearson's Chi-squared test
data: tbr_male
X-squared = 13.984, df = 4, p-value = 0.007347
다음 결과에서 여자의 이혼율은 사회 등급이 높아질수록 이혼률이 증가하는 경향을 보였는데, 이러한 차이도 통계적으로 유의미한 차이로 분석되었다.
> tbr_female <- xtabs(Freq ~ broken + rank, data = BrokenMarriage, subset = gender == "female")
> prop.table(tbr_female, margin = 2)
rank
broken I II III IV V
yes 0.3243243 0.2254902 0.1968085 0.1547800 0.1530343
no 0.6756757 0.7745098 0.8031915 0.8452200 0.8469657
Pearson's Chi-squared test
data: tbr_female
X-squared = 11.286, df = 4, p-value = 0.02353
남녀 합쳐서 분석할 때는 사회계급에 따른 이혼률의 차이가 유의미 하지 않았지만, 성별로 나누어 분석해 보면 남성과 여성 모두에서 사회계급과 이혼 여부가 통계적으로 유의미한 상관성을 확인할 수 있다. 이는 남성일수록 상위 계급(1, 3 등급)의 이혼률이 낮아지는데, 여성일수록 상위 계급(1, 2)의 이혼률이 높아져서, 합쳐진 데이터에서는 이러한 경향이 중화되어 나타나지 않았음을 볼 수 있다. 이 에에서 보듯이 한 변수가 다른 변수에 미치는 영향은 두 변수만 한정하여 살펴보는 것뿐만 아니라, 제 삼의 변수의 조건에 따라 두 변수의 상관성이 영향을 받는지 살펴볼 필요가 있다. 이러한 것을 살펴보기 위해서는 여러 측면으로 나누어 기술통계 분석을 실시해 보아야 하고, 분석하는 문제에 대한 충분한 배경 지식을 갖고 있어야 한다.