[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - table(), prop.table(), xtabs(), margin.table()
수천 명의 정보를 포함한 데이터를 한눈에 요약하고 싶을 때가 많다. 나이, 혈압과 같은 연속형 변수는 평균으로 요약하곤 하는데, 성별이나 음주 여부는 평균을 구할 수 없으니 빈도를 제시하곤 한다. 이를 표로 제시하면 도수분포표 (Frequency table)가 된다. 이를 넘어서 남성 중 음주자가 몇 명인지, 여성중 비음주자가 몇 명인지 알고 싶을 때가 있는데, 이때 사용하는 것이 분할표 (Contingency table)이다. 즉 본 글의 목적은 다음 두 개의 표 내용을 채우는 것이다.
<도수분포표>
빈도 | 백분율 | 누적빈도 | 누적백분율 | |
여성 | ||||
남성 |
<분할표>
비음주자 | 음주자 | 합계 | |
여성 | |||
남성 | |||
합계 |
R이 웬만한 프로그램보다 거의 모든 분야에서 분석하기엔 훨씬 편리하다. 하지만 오늘 다룰 도수분포표 및 분할표는 R이 압도적으로 불편하다. 그 불편한 분석을 오늘 해보고자 한다. (이런 이유로 CrossTable이라는 훌륭한 함수가 개발된 듯 하다. 다음 글로 소개하겠다. -2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - CrossTable())
*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.
2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.29)
코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.
워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.
2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 작업 디렉토리 (Working Directory) 지정 - getwd(), setwd()
setwd("C:/Users/user/Documents/Tistory_blog")
데이터를 불러와 df에 객체로 저장하겠다.
데이터 불러오는 방법은 다음 링크에서 볼 수 있다.
2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()
2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 저장하기 : CSV 파일 - write.csv(), write_csv()
2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()
install.packages("readr")
library("readr")
df<-read_csv("Data.csv")
도수분포표
코드 - table()
* 변수: SEX (성별)
-0: 여성
-1: 남성
table(df$SEX)
table(df$SEX) :df데이터에 있는 SEX변수로 도수분포표를 만들어라.
결과
0 1
482 518
해석
SEX(성별)이 0(여성)인 사람이 482명, 1(남성)인 사람이 518명이다.
하지만 앞으로 table()함수는 사용하지 않을 것이다. 왜냐하면, 보면 알겠지만 어떤 변수를 분석한 것인지 표시되지 않는다. 한 개의 변수를 분석할 때에는 문제가 되지 않겠지만 당장 분석하게 될 분할표에서는 2개 이상의 변수가 들어가는데, 어떤 변수가 행에 들어갔는지, 열에 들어갔는지 표시되지 않으므로 헷갈릴 때가 있기 때문이다.
코드 - xtabs()
xtabs(~SEX, data=df)
xtabs(~SEX, data=df) : df라는 데이터에 있는 SEX로 도수분포표를 만들어라. 단, 도수는 정해져 있지 않다.
도수란 무엇인가?
만약 데이터가 다음과 같다면 도수가 있는 데이터라고 할 수 있다.
SEX(성별) | ALCOHOL(음주) | N(도수=몇 명인데?) |
0 | 1 | 10 |
0 | 0 | 20 |
1 | 1 | 20 |
1 | 0 | 50 |
이 데이터는
여성 & 음주자: 10명
여성 & 비음주자: 20명
남성 & 음주자: 20명
남성 & 비음주자: 50명
임을 의미한다. 즉 각 특성을 갖는 사람이 몇 명인지 알려주는 것인데 이런 변수가 있다면 코드 xtabs(~SEX, data=df) ~왼쪽에 N을 적어야 한다.
#만약 도수를 나타내는 변수가 있는 자료였다면?
xtabs(N~SEX, data=df)
위 코드는 가상의 코드임으로 구동되지 않는다.
결과
SEX
0 1
482 518
함수 xtabs()는 정말 고맙게도 변수의 이름을 표기해준다.
표의 다음 파란 글씨를 이제 채울 수 있게 되었다.
빈도 | 백분율 | 누적빈도 | 누적백분율 | |
여성 | 482 | |||
남성 | 518 |
코드 - 분율
분율을 구하는 법은 다음과 같다.
prop.table(xtabs(~SEX, data=df))
prop.table(xtabs(~SEX, data=df)) :위에서 구한 도수분포표 [코드: xtabs(~SEX, data=df)]의 분율(proportion)을 구하라.
결과
SEX
0 1
0.482 0.518
SEX=0의 분율은 0.482, SEX=1의 분율은 0.518이다.
하지만, %로 나타난 백분율이 아니므로 이대로는 표에 넣을 수 없다. 그리고 이런 식의 코드는 복잡함을 증대시키기 때문에 보통 다음과 같은 코드를 사용한다. 순서대로 설명하면 다음과 같다.
코드 - 백분율
freq_sex<-xtabs(~SEX, data=df)
prop_sex<-prop.table(freq_sex)
prop_sex_100<-100*prop_sex
prop_sex_100
round(prop_sex_100,digits=0)
freq_sex<-xtabs(~SEX, data=df) : 데이터 df안에 있는 변수 SEX의 도수분포표를 작성하여 freq_sex에 저장하라.
prop_sex<-prop.table(freq_sex) : freq_sex의 분율을 구하여 prop_sex에 저장하라.
prop_sex_100<-100*prop_sex : prop_sex에 100을 곱하여 prop_sex_100에 저장하라
prop_sex_100 : prop_sex_100가 뭔지 보여달라.
round(prop_sex_100,digits=0) : prop_sex_100을 소수점 1번째 자리에서 반올림하여 정수로 보여달라
결과
SEX
0 1
48.2 51.8
SEX
0 1
48 52
위의 결과가 일반적인 백분율, 아래 결과는 정수로 반올림한 백분율을 나타낸다. 드디어 표의 두 번째 열을 채울 수 있게 되었다.
빈도 | 백분율 | 누적빈도 | 누적백분율 | |
여성 | 482 | 48.2 | ||
남성 | 518 | 51.8 |
코드 - 누적 빈도, 누적 백분율
#누적 빈도 구하기
cumsum(freq_sex)
#누적 백분율 구하기
cumsum(prop_sex_100)
cumsum(freq_sex) : freq_sex (도수분포표)의 누적 도수를 구하라.
cumsum(prop_sex_100) : prop_sex_100 (백분율)로 누적 백분율을 구하라.
결과
0 1
482 1000
0 1
48.2 100.0
이제 표를 완성할 수 있게 되었다.
빈도 | 백분율 | 누적빈도 | 누적백분율 | |
여성 | 482 | 48.2 | 482 | 48.2 |
남성 | 518 | 51.8 | 1000 | 100.0 |
도수분포표 코드 전체
#작업 디렉토리 지정
setwd("C:/Users/user/Documents/Tistory_blog")
#데이터 불러오기
install.packages("readr")
library("readr")
df<-read_csv("Data.csv")
#도수분포표
freq_sex<-xtabs(~SEX, data=df)
freq_sex #빈도
prop_sex<-prop.table(freq_sex)
prop_sex_100<-100*prop_sex
prop_sex_100 #백분율
round(prop_sex_100,digits=0)
cumsum(freq_sex) #누적 빈도
cumsum(prop_sex_100) #누적 백분율
분할표
분할표를 작성해보자. 코드는 다음과 같다.
코드 - 빈도
#각 셀의 빈도 구하기
freq_sex_alc<-xtabs(~SEX+ALCOHOL, data=df)
freq_sex_alc
#행 별로 합친 빈도 구하기
freq_sex<-margin.table(freq_sex_alc, margin=1)
freq_sex
#열 별로 합친 빈도 구하기
freq_alc<-margin.table(freq_sex_alc, margin=2)
freq_alc
#전체 데이터 수 구하기
total_freq_sex_alc<-sum(freq_sex_alc) #혹은 sum(freq_sex)이나 sum(freq_alc)도 가능
total_freq_sex_alc
freq_sex_alc<-xtabs(~SEX+ALCOHOL, data=df) : ( '+' 표시 앞에 있는) SEX를 세로축에, ('+' 표시 뒤에 있는) ALCOHOL을 가로축에 넣고 분할표를 만들고 freq_sex_alc에 저장하라. 이때 데이터는 df를 사용하라.
freq_sex_alc : 만든 분할표를 보여달라.
freq_sex<-margin.table(freq_sex_alc, margin=1) :행 별로 합친 도수분포표 만들고 freq_sex에 저장하라. 즉, 성별의 도수분포표를 보여달라는 뜻이고 본 데이터에는 결측치가 없으므로 이는 "xtabs(~SEX, data=df)"와 같은 결과를 보여준다. (결측치가 있으면 결과가 다를 수 있다.)
freq_sex : 성별의 도수분포표를 보여달라.
freq_alc<-margin.table(freq_sex_alc, margin=2) :열 별로 합친 도수분포표 만들고 freq_alc에 저장하라. 즉, 음주 여부의 도수분포표를 보여달라는 뜻이고 본 데이터에는 결측치가 없으므로 이는 "xtabs(~ALCOHOL, data=df)"와 같은 결과를 보여준다. (결측치가 있으면 결과가 다를 수 있다.)
freq_alc : 음주 여부의 도수분포표를 보여달라.
total_freq_sex_alc<-sum(freq_sex_alc) : 빈도를 모두 더해 total_freq_sex_alc에 저장하라.
total_freq_sex_alc :총빈도수를 보여달라.
결과
ALCOHOL
SEX 0 1
0 236 246
1 174 344
SEX
0 1
482 518
ALCOHOL
0 1
410 590
[1] 1000
xtabs()함수의 진가는 분할표를 만들 때에 나온다. table()함수에는 나오지 않는 각 변수명을 보여주니 말이다. 위 데이터로 표의 빈도를 채울 수 있게 되었다.
빈도 백분율 행백분율 열백분율 |
비음주자 | 음주자 | 합계 |
여성 | 236 | 246 | 482 |
남성 | 174 | 344 | 518 |
합계 | 410 | 590 | 1000 |
코드 - 백분율
#각 셀의 백분율
prop_sex_alc<-prop.table(freq_sex_alc)
prop_sex_alc_100<-100*prop_sex_alc
prop_sex_alc_100
#행 별로 합친 데이터의 백분율
prop_sex<-prop.table(freq_sex)
prop_sex_100<-100*prop_sex
prop_sex_100
#열 별로 합친 데이터의 백분율
prop_alc<-prop.table(freq_alc)
prop_alc_100<-100*prop_alc
prop_alc_100
#전체 데이터의 백분율
prop_total<-prop.table(total_freq_sex_alc)
prop_total_100<-100*prop_total
prop_total_100
prop_sex_alc<-prop.table(freq_sex_alc) :2*2 분할표에서 각 셀의 분율을 구하고 prop_sex_alc에 저장하라
prop_sex_alc_100<-100*prop_sex_alc : 분율에 100을 곱하여 백분율을 구하고 prop_sex_alc_100에 저장하라
prop_sex_alc_100 : 백분율을 보여달라
prop_sex<-prop.table(freq_sex) :행 별로 합친 데이터의 분율을 구하고 prop_sex에 저장하라
prop_sex_100<-100*prop_sex : 분율에 100을 곱하여 백분율을 구하고 prop_sex_100에 저장하라
prop_sex_100 : 백분율을 보여달라
prop_alc<-prop.table(freq_sex) :열 별로 합친 데이터의 분율을 구하고 prop_alc에 저장하라
prop_alc_100<-100*prop_alc : 분율에 100을 곱하여 백분율을 구하고 prop_alc_100에 저장하라
prop_alc_100 : 백분율을 보여달라
prop_total<-prop.table(total_freq_sex_alc) : 전체 데이터를 합쳤을 때 분율을 구하고 prop_total에 저장하라
prop_total_100<-100*prop_total :분율에 100을 곱하여 백분율을 구하고 prop_total_100에 저장하라
prop_total_100 : 백분율을 보여달라
결과
ALCOHOL
SEX 0 1
0 23.6 24.6
1 17.4 34.4
SEX
0 1
48.2 51.8
ALCOHOL
0 1
41 59
[1] 100
표의 백분율을 채울 수 있게 되었다.
빈도 백분율 행백분율 열백분율 |
비음주자 | 음주자 | 합계 |
여성 | 236 23.6% |
246 24.6% |
482 48.2% |
남성 | 174 17.4% |
344 34.4% |
518 51.8% |
합계 | 410 41.0% |
590 59.0% |
1000 100.0% |
백분율은 가로로 합하면 가로 합계의 백분율과 일치하고, 세로로 더하면 세로 합계의 백분율과 일치한다.
코드 - 행백분율
sum_row<-rowSums(freq_sex_alc)
prop_row<-freq_sex_alc/sum_row
prop_row_100<-100*prop_row
prop_row_100
round(prop_row_100, digits=2)
sum_row<-rowSums(freq_sex_alc) : 행 별로 더한 값을 sum_row에 저장한다. 즉 남성과 여성이 각각 몇 명이 있는지 보여준다. 이 값은 겉으로 보기엔 "freq_sex"와 같다. 하지만 속성이 약간 다르며 freq_sex로 대체할 수 없다.
prop_row<-freq_sex_alc/sum_row : 각 셀의 빈도를 행별로 더한 값으로 나눈다. 즉, 음주자건 비음주자건 남성이면 남성의 수로 나누고, 여성이면 여성의 수로 나눈다. 그리하여 분율을 구한다.
prop_row_100<-100*prop_row : 분율에 100을 곱해 백분율을 구한다.
prop_row_100 : 백분율을 보여달라.
round(prop_row_100, digits=2) : 소수점 셋째 자리에서 반올림하여 둘째 자리까지만 표기하라.
결과
ALCOHOL
SEX 0 1
0 48.96266 51.03734
1 33.59073 66.40927
ALCOHOL
SEX 0 1
0 48.96 51.04
1 33.59 66.41
반올림한 결과가 훨씬 보기 편한 걸 알 수 있다. 그리고 가로로 합하면 100이 나오는 것을 볼 수 있다.
표의 행백분율을 채울 수 있게 되었다.
빈도 백분율 행백분율 열백분율 |
비음주자 | 음주자 | 합계 |
여성 | 236 23.6% 48.96% |
246 24.6% 51.04% |
482 48.2% |
남성 | 174 17.4% 33.59% |
344 34.4% 66.41% |
518 51.8% |
합계 | 410 41.0% |
590 59.0% |
1000 100.0% |
코드 - 열백분율
R 특성상 조금 더 복잡해진다.
sum_col<-colSums(freq_sex_alc)
prop_col<-t(t(freq_sex_alc)/sum_col)
prop_col_100<-100*prop_col
prop_col_100
round(prop_col_100, digits=2)
sum_col<-colSums(freq_sex_alc) : 열 별로 더한 값을 sum_col에 저장한다. 즉 음주자와 비음주자가 각각 몇 명이 있는지 보여준다. 이 값은 겉으로 보기엔 "freq_alc"와 같다. 하지만 속성이 약간 다르며 freq_alc로 대체할 수 없다.
prop_col<-t(t(freq_sex_alc)/sum_col) : R에서 나눌 때에는 행 별로 나눈다. 즉 열 별로 나누려면 행/열을 바꾼 다음에 나누어야 한다. 어려운 말로 전치 행렬을 구해야 한다는 것이고 전치 행렬을 구하는 명령어가 t()다. 나눈 다음에 다시 한번 행/열을 바꾸지 않으면 세로에 음주 여부, 가로에 성별에 들어가 있으므로 보기에 편하려면 다시 한번 전치 행렬을 구해야 한다.
prop_col_100<-100*prop_col : 분율에 100을 곱해 백분율을 구한다.
prop_col_100 : 백분율을 보여달라.
round(prop_col_100, digits=2) : 소수점 셋째 자리에서 반올림하여 둘째 자리까지만 표기하라.
결과
ALCOHOL
SEX 0 1
0 57.56098 41.69492
1 42.43902 58.30508
ALCOHOL
SEX 0 1
0 57.56 41.69
1 42.44 58.31
표를 완성할 수 있다.
빈도 백분율 행백분율 열백분율 |
비음주자 | 음주자 | 합계 |
여성 | 236 23.6% 48.96% 57.56% |
246 24.6% 51.04% 41.69% |
482 48.2% |
남성 | 174 17.4% 33.59% 42.44% |
344 34.4% 66.41% 58.31% |
518 51.8% |
합계 | 410 41.0% |
590 59.0% |
1000 100.0% |
분할표 코드 전체
#작업 디렉토리 지정
setwd("C:/Users/user/Documents/Tistory_blog")
#데이터 불러오기
install.packages("readr")
library("readr")
df<-read_csv("Data.csv")
########빈도########
#각 셀의 빈도 구하기
freq_sex_alc<-xtabs(~SEX+ALCOHOL, data=df)
freq_sex_alc
#행 별로 합친 빈도 구하기
freq_sex<-margin.table(freq_sex_alc, margin=1)
freq_sex
#열 별로 합친 빈도 구하기
freq_alc<-margin.table(freq_sex_alc, margin=2)
freq_alc
#전체 데이터 수 구하기
total_freq_sex_alc<-sum(freq_sex_alc) #혹은 sum(freq_sex)이나 sum(freq_alc)도 가능
total_freq_sex_alc
########백분율########
#각 셀의 백분율
prop_sex_alc<-prop.table(freq_sex_alc)
prop_sex_alc_100<-100*prop_sex_alc
prop_sex_alc_100
#행 별로 합친 데이터의 백분율
prop_sex<-prop.table(freq_sex)
prop_sex_100<-100*prop_sex
prop_sex_100
#열 별로 합친 데이터의 백분율
prop_alc<-prop.table(freq_alc)
prop_alc_100<-100*prop_alc
prop_alc_100
#전체 데이터의 백분율
prop_total<-prop.table(total_freq_sex_alc)
prop_total_100<-100*prop_total
prop_total_100
########행백분율########
sum_row<-rowSums(freq_sex_alc)
prop_row<-freq_sex_alc/sum_row
prop_row_100<-100*prop_row
prop_row_100
round(prop_row_100, digits=2)
########열백분율########
sum_col<-colSums(freq_sex_alc)
prop_col<-t(t(freq_sex_alc)/sum_col)
prop_col_100<-100*prop_col
prop_col_100
round(prop_col_100, digits=2)
세 개 이상의 변수를 사용하는 분할표
코드
freq_sex_alc_htn<-xtabs(~SEX+ALCOHOL+HTN, data=df)
freq_sex_alc_htn
freq_sex_alc_htn<-xtabs(~SEX+ALCOHOL+HTN, data=df) : 데이터는 df를 사용하되 세로축에 SEX, 가로축에 ALCOHOL을 놓는다. HTN 값 별로 분할표를 각각 만들어 freq_sex_alc_htn에 저장한다.
freq_sex_alc_htn : 각각의 분할표를 보여달라.
결과
, , HTN = 0
ALCOHOL
SEX 0 1
0 114 122
1 89 178
, , HTN = 1
ALCOHOL
SEX 0 1
0 122 124
1 85 166
고혈압이 없는 (HTN=0) 사람들과 고혈압이 있는 (HTN=1) 사람들의 분할표를 각각 보여준다. 인구를 고혈압뿐만 아니라 RH혈액형으로도 나누고 싶다면 HTN뒤에 "+RH"를 붙여 다음과 같은 코드를 쓰면 된다.
#코드
freq_sex_alc_htn_rh<-xtabs(~SEX+ALCOHOL+HTN+RH, data=df)
freq_sex_alc_htn_rh
#결과
, , HTN = 0, RH = 0
ALCOHOL
SEX 0 1
0 0 0
1 2 2
, , HTN = 1, RH = 0
ALCOHOL
SEX 0 1
0 1 0
1 1 0
, , HTN = 0, RH = 1
ALCOHOL
SEX 0 1
0 114 122
1 87 176
, , HTN = 1, RH = 1
ALCOHOL
SEX 0 1
0 121 124
1 84 166
SAS에는 인구를 나누는 변수를 맨 앞에 쓰지만, R에서는 맨 뒤에 쓴다는 것을 유의해야 한다.
SAS에서의 분할표 작성법:
2022.08.18 - [기술 통계/SAS] - [SAS] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - PROC FREQ
결론적으로 R로 분할표를 만드는 것은 매우 귀찮은 일이기 때문에 SPSS나 SAS를 쓰거나 CrossTable()함수를 쓰길 권한다.
2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - CrossTable()
[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 정복 완료!
작성일: 2022.08.31.
최종 수정일: 2022.08.31.
이용 프로그램: R 4.1.3
RStudio v1.4.1717
RStudio 2021.09.1+372 "Ghost Orchid" Release
운영체제: Windows 10, Mac OS 10.15.7
'기술 통계 > R' 카테고리의 다른 글
[R] 기술 통계 (평균, 표준편차, 표준오차, 최댓값, 최솟값, 중위수, 분위수 등) (0) | 2022.09.27 |
---|---|
[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - CrossTable() (0) | 2022.08.31 |
[R] 고급 Q-Q Plot - Van der Waerden, Rankit, Tukey, Blom (0) | 2022.08.16 |
[R] 정규성 검정 (4) : 정량적 검정 (Lilliefors test) - lillie.test() (0) | 2022.08.12 |
[R] 정규성 검정 (3) : 정량적 검정 (Shapiro-Wilk, Kolmogorov-Smirnov) - shapiro.test(), ks.test() (0) | 2022.08.11 |