자료의 정리와 요약으로
- 일변량 범주형 자료의
도수분포표 (frequency distribution table)
- 이변량 범주형 자료의
분할표 (contingency table)
카이제곱 검정 (chisquare test)
중에서 이번 포스팅에서는 이변량 범주형 자료의 분할표, 카이제곱 검정에 대해서 알아보겠습니다.
참고로, 자료의 형태(질적/범주형변수 vs. 양적변수)에 따라서, 또 양적변수는 연속형이냐 이산형이냐에 따라서 자료를 정리하고 요약하는 방법, 확률모형 설정, 추정과 검정, 모형 개발 등이 달라지는데요, 아래 표를 참고하시기 바랍니다.
[ 자료의 형태 구분 ]
형태 (Type) |
순서 여부 (ordinal yes/no)
연속성 여부 (continuous yes/no) |
예시 (example) |
질적 변수
(Qualitative variable)
or 범주형 변수
(Categorical variable) |
no : 명목형 (nominal) |
이름, 성별, 주소,
학력, 전화번호 등 |
yes : 순서형 (ordinal) |
학년 |
양적 변수
(Quantitative variable) |
yes : 연속형 변수
(continuous variable) |
키, 몸무게, 온도, 습도 등 |
no : 이산형 변수
(descrete variable) |
나이 |
분석 기법은 변수가 몇개냐, 변수의 형태가 무엇이냐(범주형 변수와 연속형 변수의 2개로 구분)해서 간략하게 표로 제시해보면 아래와 같습니다.
일변량 (one variable)
자료 형태 |
분석 기법 |
범주형 변수
(categorical variable) |
<표(table)를 이용한 정리와 요약 >
도수분포표 (frequency distribution table)
|
연속형 변수
(continuous variable) |
< 통계량(statistics)을 이용한 요약 >
- 중심 경향 : 평균 (mean), 중앙값 (median), 최빈값 (mode)
- 퍼짐 정도 : 분산 (variance), 표준편차(standard deviation),
범위 (range), 사분위수(IQR: Inter Quantile Rnage)
- 치우침 정도 : 왜도 (skewness), 첨도 (kurtosis)
|
※ 그래프 분석 병행 매우 중요
이변량 (two variables)
Y 변수
X 변수 |
범주형 변수
(categorical variable) |
연속형 변수
(continuous variable) |
범주형 변수
(categorical variable) |
분할표 (contingency table)
카이제곱 검정 (chi-square test) |
t-Test
ANOVA |
연속형 변수
(continuous variable) |
의사결정나무 (decision tree)
로지스틱회귀분석 (rogistic regression) |
상관분석 (correlation analysis)
회귀분석 (regression analysis) |
※ 그래프 분석 병행 매우 중요
일변량 자료 분석이 변수 자체의 분포, 형태에 대해 관심을 가진다면, 이변량 자료 분석의 경우는 변수와 변수간의 관계에 특히 관심을 가지게 됩니다.
R 예제에 사용한 데이터는 MASS 패키지에 내장된 Cars93 데이터프레임의 차종형태(Type), 실린더(Cylinders), 트렁크공간크기(Luggage.room)의 변수들입니다.
Type, Cylinders 변수는 categorical data 이어서 교차표(crosstabulation table) 분석할 때 그대로 사용하면 되며, Luggage.room 변수는 discrete data (integer) 이므로 categorical data로 변환해서 분할표 분석할 때 사용하겠습니다.
> library(MASS)
> str(Cars93)
'data.frame': 93 obs. of 27 variables:
$ Manufacturer : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...
$ Model : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...
$ Type : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...
$ Min.Price : num 12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...
$ Price : num 15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...
$ Max.Price : num 18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...
$ MPG.city : int 25 18 20 19 22 22 19 16 19 16 ...
$ MPG.highway : int 31 25 26 26 30 31 28 25 27 25 ...
$ AirBags : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...
$ DriveTrain : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...
$ Cylinders : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...
$ EngineSize : num 1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...
$ Horsepower : int 140 200 172 172 208 110 170 180 170 200 ...
$ RPM : int 6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...
$ Rev.per.mile : int 2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...
$ Man.trans.avail : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...
$ Fuel.tank.capacity: num 13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...
$ Passengers : int 5 5 5 6 4 6 6 6 5 6 ...
$ Length : int 177 195 180 193 186 189 200 216 198 206 ...
$ Wheelbase : int 102 115 102 106 109 105 111 116 108 114 ...
$ Width : int 68 71 67 70 69 69 74 78 73 73 ...
$ Turn.circle : int 37 38 37 37 39 41 42 45 41 43 ...
$ Rear.seat.room : num 26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...
$ Luggage.room : int 11 15 14 17 13 16 17 21 14 18 ...
$ Weight : int 2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...
$ Origin : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...
$ Make : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 ..
|
R로 실습을 해보겠습니다.
(1) 이변량 분할표 (contingency table) : table(), xtabs()
> ##----------------------------------------------------------
> ## 이변량 분할표(contingency table) : table(), xtabs()
> ##----------------------------------------------------------
> > # contingency table : table(x, y)
> Car_table_3 <- with(Cars93, table(Type, Cylinders))
> Car_table_3
Cylinders
Type 3 4 5 6 8 rotary
Compact 0 15 0 1 0 0
Large 0 0 0 7 4 0
Midsize 0 7 1 12 2 0
Small 3 18 0 0 0 0
Sporty 0 8 0 4 1 1
Van 0 1 1 7 0 0
>
>
> # contingency table : xtabs(~ x + y, data)
> Car_table_4 <- xtabs(~ Type + Cylinders, data=Cars93)
> Car_table_4
Cylinders
Type 3 4 5 6 8 rotary
Compact 0 15 0 1 0 0
Large 0 0 0 7 4 0
Midsize 0 7 1 12 2 0
Small 3 18 0 0 0 0
Sporty 0 8 0 4 1 1
Van 0 1 1 7 0 0
|
참고로, table 형태의 데이터를 가지고 xtabs() 함수를 사용해서 cross tabulation 계산할 때의 예를 아래에 들어보겠습니다. 데이터 형태가 위의 Cars93과는 다르다보니 xtabs() 함수 쓸 때 '~' 앞에 도수가 들어있는 변수를 지정해주는 것이 다릅니다. 아래에 UC버클리 대학교 입학 관련 데이터에의 예의 제일 아래에 보면 xtabs(Freq ~ Gender + Admit, data=UCBAdmissions.df) 라고 했지요? 위의 Cars93의 예의 경우는 xtabs( ~ Type + Cylinders, data=Cars93)이라고 했구요. 데이터가 어떻게 생겼느냐에 따라서 알맞는 arguments를 사용하면 되겠습니다.
> # getting data of table format
> data(UCBAdmissions)
> str(UCBAdmissions)
table [1:2, 1:2, 1:6] 512 313 89 19 353 207 17 8 120 205 ...
- attr(*, "dimnames")=List of 3
..$ Admit : chr [1:2] "Admitted" "Rejected"
..$ Gender: chr [1:2] "Male" "Female"
..$ Dept : chr [1:6] "A" "B" "C" "D" ...
> UCBAdmissions
, , Dept = A
Gender
Admit Male Female
Admitted 512 89
Rejected 313 19
, , Dept = B
Gender
Admit Male Female
Admitted 353 17
Rejected 207 8
, , Dept = C
Gender
Admit Male Female
Admitted 120 202
Rejected 205 391
, , Dept = D
Gender
Admit Male Female
Admitted 138 131
Rejected 279 244
, , Dept = E
Gender
Admit Male Female
Admitted 53 94
Rejected 138 299
, , Dept = F
Gender
Admit Male Female
Admitted 22 24
Rejected 351 317
>
> # transforming to dataframe
> UCBAdmissions.df <- as.data.frame(UCBAdmissions)
> UCBAdmissions.df
Admit Gender Dept Freq
1 Admitted Male A 512
2 Rejected Male A 313
3 Admitted Female A 89
4 Rejected Female A 19
5 Admitted Male B 353
6 Rejected Male B 207
7 Admitted Female B 17
8 Rejected Female B 8
9 Admitted Male C 120
10 Rejected Male C 205
11 Admitted Female C 202
12 Rejected Female C 391
13 Admitted Male D 138
14 Rejected Male D 279
15 Admitted Female D 131
16 Rejected Female D 244
17 Admitted Male E 53
18 Rejected Male E 138
19 Admitted Female E 94
20 Rejected Female E 299
21 Admitted Male F 22
22 Rejected Male F 351
23 Admitted Female F 24
24 Rejected Female F 317
>
> # cross tabulation of transformed dataset
> xtabs(Freq ~ Gender + Admit, data=UCBAdmissions.df)
Admit
Gender Admitted Rejected
Male 1198 1493
Female 557 1278
|
(2) 상대 분할표 (relative frequency contingency table) : prop.table()
> # relative frequency distribution table : prop.table()
> options("digit" = 3) # decimal point setting
> Prop_Car_table_3 <- prop.table(Car_table_3)
> Prop_Car_table_3
Cylinders
Type 3 4 5 6 8 rotary
Compact 0.00000000 0.16129032 0.00000000 0.01075269 0.00000000 0.00000000
Large 0.00000000 0.00000000 0.00000000 0.07526882 0.04301075 0.00000000
Midsize 0.00000000 0.07526882 0.01075269 0.12903226 0.02150538 0.00000000
Small 0.03225806 0.19354839 0.00000000 0.00000000 0.00000000 0.00000000
Sporty 0.00000000 0.08602151 0.00000000 0.04301075 0.01075269 0.01075269
Van 0.00000000 0.01075269 0.01075269 0.07526882 0.00000000 0.00000000
|
(3) 한계분포 (marginal distribution) : margin.table(table, margin=1 or 2)
> margin.table(Car_table_3, margin=1) # margin=1 for row sum
Type
Compact Large Midsize Small Sporty Van
16 11 22 21 14 9
> margin.table(Prop_Car_table_3, margin=1) # margin=1 for row sum
Type
Compact Large Midsize Small Sporty Van
0.17204301 0.11827957 0.23655914 0.22580645 0.15053763 0.09677419
>
> margin.table(Car_table_3, margin=2) # margin=2 for column sum
Cylinders
3 4 5 6 8 rotary
3 49 2 31 7 1
> margin.table(Prop_Car_table_3, margin=2) # margin=2 for column sum
Cylinders
3 4 5 6 8 rotary
0.03225806 0.52688172 0.02150538 0.33333333 0.07526882 0.01075269
|
(4) 분할표에 한계분포 추가 (add marginal distribution at the table) addmargins()
> # marginal distribution at the table : addmargins(table, margin=1 or 2)
> addmargins(Car_table_3) # row sum and column sum at the table
Cylinders
Type 3 4 5 6 8 rotary Sum
Compact 0 15 0 1 0 0 16
Large 0 0 0 7 4 0 11
Midsize 0 7 1 12 2 0 22
Small 3 18 0 0 0 0 21
Sporty 0 8 0 4 1 1 14
Van 0 1 1 7 0 0 9
Sum 3 49 2 31 7 1 93
> addmargins(Prop_Car_table_3) # row sum and column sum at the table
Cylinders
Type 3 4 5 6 8 rotary Sum
Compact 0.00000000 0.16129032 0.00000000 0.01075269 0.00000000 0.00000000 0.17204301
Large 0.00000000 0.00000000 0.00000000 0.07526882 0.04301075 0.00000000 0.11827957
Midsize 0.00000000 0.07526882 0.01075269 0.12903226 0.02150538 0.00000000 0.23655914
Small 0.03225806 0.19354839 0.00000000 0.00000000 0.00000000 0.00000000 0.22580645
Sporty 0.00000000 0.08602151 0.00000000 0.04301075 0.01075269 0.01075269 0.15053763
Van 0.00000000 0.01075269 0.01075269 0.07526882 0.00000000 0.00000000 0.09677419
Sum 0.03225806 0.52688172 0.02150538 0.33333333 0.07526882 0.01075269 1.00000000
>
> > addmargins(Car_table_3, margin=1) # margin=1 for row sum at the table
Cylinders
Type 3 4 5 6 8 rotary
Compact 0 15 0 1 0 0
Large 0 0 0 7 4 0
Midsize 0 7 1 12 2 0
Small 3 18 0 0 0 0
Sporty 0 8 0 4 1 1
Van 0 1 1 7 0 0
Sum 3 49 2 31 7 1
> addmargins(Prop_Car_table_3, margin=1) # margin=1 for row sum at the table
Cylinders
Type 3 4 5 6 8 rotary
Compact 0.00000000 0.16129032 0.00000000 0.01075269 0.00000000 0.00000000
Large 0.00000000 0.00000000 0.00000000 0.07526882 0.04301075 0.00000000
Midsize 0.00000000 0.07526882 0.01075269 0.12903226 0.02150538 0.00000000
Small 0.03225806 0.19354839 0.00000000 0.00000000 0.00000000 0.00000000
Sporty 0.00000000 0.08602151 0.00000000 0.04301075 0.01075269 0.01075269
Van 0.00000000 0.01075269 0.01075269 0.07526882 0.00000000 0.00000000
Sum 0.03225806 0.52688172 0.02150538 0.33333333 0.07526882 0.01075269
>
> > addmargins(Car_table_3, margin=2) # margin=2 for column sum at the table
Cylinders
Type 3 4 5 6 8 rotary Sum
Compact 0 15 0 1 0 0 16
Large 0 0 0 7 4 0 11
Midsize 0 7 1 12 2 0 22
Small 3 18 0 0 0 0 21
Sporty 0 8 0 4 1 1 14
Van 0 1 1 7 0 0 9
> addmargins(Prop_Car_table_3, margin=2) # margin=2 for column sum at the table
Cylinders
Type 3 4 5 6 8 rotary Sum
Compact 0.00000000 0.16129032 0.00000000 0.01075269 0.00000000 0.00000000 0.17204301
Large 0.00000000 0.00000000 0.00000000 0.07526882 0.04301075 0.00000000 0.11827957
Midsize 0.00000000 0.07526882 0.01075269 0.12903226 0.02150538 0.00000000 0.23655914
Small 0.03225806 0.19354839 0.00000000 0.00000000 0.00000000 0.00000000 0.22580645
Sporty 0.00000000 0.08602151 0.00000000 0.04301075 0.01075269 0.01075269 0.15053763
Van 0.00000000 0.01075269 0.01075269 0.07526882 0.00000000 0.00000000 0.09677419
|
margin.table()은 row 혹은 column 별로 sum을 따로 구한데 반해, addmargins() 는 contingency table은 고정시켜놓고 거기에 row 혹은 column sum을 추가한 것이 다릅니다.
(5) NA를 분할표에 포함시키고자 할 경우 (including NA to contingency table) : useNA = "ifany"
> ##------
> # useNA = "ifany" option
> # count of missing value
> dim(Cars93)
[1] 93 27
> sum(is.na(Cars93$Type))
[1] 0
> sum(is.na(Cars93$Cylinders))
[1] 0
> sum(is.na(Cars93$Luggage.room)) # number of NA = 11
[1] 11
> summary(Cars93$Luggage.room)
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
6.00 12.00 14.00 13.89 15.00 22.00 11
>
> # useNA = "ifany" option
> addmargins(with(Cars93, table((Luggage.room_big = Luggage.room >= 14), Type)))
Type
Compact Large Midsize Small Sporty Van Sum
FALSE 4 0 2 18 10 0 34
TRUE 12 11 20 3 2 0 48
Sum 16 11 22 21 12 0 82
> addmargins(with(Cars93, table((Luggage.room_big = Luggage.room >= 14), Type, useNA="ifany")))
Type
Compact Large Midsize Small Sporty Van Sum
FALSE 4 0 2 18 10 0 34
TRUE 12 11 20 3 2 0 48
<NA> 0 0 0 0 2 9 11
Sum 16 11 22 21 14 9 93
|
(6) 카이제곱 검정 (chi-square test) : gmodels package, CrossTable(x,y, expected=T, chisq=T)
> install.packages("gmodels")
Installing package into ‘C:/Users/user/Documents/R/win-library/3.2’
(as ‘lib’ is unspecified)
trying URL 'http://cran.rstudio.com/bin/windows/contrib/3.2/gmodels_2.16.2.zip'
Content type 'application/zip' length 73944 bytes (72 KB)
downloaded 72 KB
package ‘gmodels’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\user\AppData\Local\Temp\RtmpSUTL1V\downloaded_packages
> library(gmodels) > with(Cars93, CrossTable(Type, Cylinders, expected=TRUE, chisq=TRUE))
Cell Contents
|-------------------------|
| N |
| Expected N |
| Chi-square contribution |
| N / Row Total |
| N / Col Total |
| N / Table Total |
|-------------------------|
Total Observations in Table: 93
| Cylinders
Type | 3 | 4 | 5 | 6 | 8 | rotary | Row Total |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Compact | 0 | 15 | 0 | 1 | 0 | 0 | 16 |
| 0.516 | 8.430 | 0.344 | 5.333 | 1.204 | 0.172 | |
| 0.516 | 5.120 | 0.344 | 3.521 | 1.204 | 0.172 | |
| 0.000 | 0.938 | 0.000 | 0.062 | 0.000 | 0.000 | 0.172 |
| 0.000 | 0.306 | 0.000 | 0.032 | 0.000 | 0.000 | |
| 0.000 | 0.161 | 0.000 | 0.011 | 0.000 | 0.000 | |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Large | 0 | 0 | 0 | 7 | 4 | 0 | 11 |
| 0.355 | 5.796 | 0.237 | 3.667 | 0.828 | 0.118 | |
| 0.355 | 5.796 | 0.237 | 3.030 | 12.153 | 0.118 | |
| 0.000 | 0.000 | 0.000 | 0.636 | 0.364 | 0.000 | 0.118 |
| 0.000 | 0.000 | 0.000 | 0.226 | 0.571 | 0.000 | |
| 0.000 | 0.000 | 0.000 | 0.075 | 0.043 | 0.000 | |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Midsize | 0 | 7 | 1 | 12 | 2 | 0 | 22 |
| 0.710 | 11.591 | 0.473 | 7.333 | 1.656 | 0.237 | |
| 0.710 | 1.819 | 0.587 | 2.970 | 0.071 | 0.237 | |
| 0.000 | 0.318 | 0.045 | 0.545 | 0.091 | 0.000 | 0.237 |
| 0.000 | 0.143 | 0.500 | 0.387 | 0.286 | 0.000 | |
| 0.000 | 0.075 | 0.011 | 0.129 | 0.022 | 0.000 | |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Small | 3 | 18 | 0 | 0 | 0 | 0 | 21 |
| 0.677 | 11.065 | 0.452 | 7.000 | 1.581 | 0.226 | |
| 7.963 | 4.347 | 0.452 | 7.000 | 1.581 | 0.226 | |
| 0.143 | 0.857 | 0.000 | 0.000 | 0.000 | 0.000 | 0.226 |
| 1.000 | 0.367 | 0.000 | 0.000 | 0.000 | 0.000 | |
| 0.032 | 0.194 | 0.000 | 0.000 | 0.000 | 0.000 | |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Sporty | 0 | 8 | 0 | 4 | 1 | 1 | 14 |
| 0.452 | 7.376 | 0.301 | 4.667 | 1.054 | 0.151 | |
| 0.452 | 0.053 | 0.301 | 0.095 | 0.003 | 4.793 | |
| 0.000 | 0.571 | 0.000 | 0.286 | 0.071 | 0.071 | 0.151 |
| 0.000 | 0.163 | 0.000 | 0.129 | 0.143 | 1.000 | |
| 0.000 | 0.086 | 0.000 | 0.043 | 0.011 | 0.011 | |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Van | 0 | 1 | 1 | 7 | 0 | 0 | 9 |
| 0.290 | 4.742 | 0.194 | 3.000 | 0.677 | 0.097 | |
| 0.290 | 2.953 | 3.360 | 5.333 | 0.677 | 0.097 | |
| 0.000 | 0.111 | 0.111 | 0.778 | 0.000 | 0.000 | 0.097 |
| 0.000 | 0.020 | 0.500 | 0.226 | 0.000 | 0.000 | |
| 0.000 | 0.011 | 0.011 | 0.075 | 0.000 | 0.000 | |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Column Total | 3 | 49 | 2 | 31 | 7 | 1 | 93 |
| 0.032 | 0.527 | 0.022 | 0.333 | 0.075 | 0.011 | |
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Statistics for All Table Factors
Pearson's Chi-squared test
------------------------------------------------------------
Chi^2 = 78.93491 d.f. = 25 p = 1.674244e-07
|
P-value 가 매우 작으므로 차종(Type)과 Cylinder개수(Cylinders)는 5% 유의수준(significnace level)에서 서로 독립이 아니라(귀무가설 기각, 대립가설 채택)고 판단할 수 있겠습니다.
(7) Mosaic plot for categorical data : vcd package, mosaic()
> # mosaic plot : vcd package, mosaic()
> library(vcd)
필요한 패키지를 로딩중입니다: grid
> Car_table_3 <- with(Cars93, table(Type, Cylinders))
> Car_table_3
Cylinders
Type 3 4 5 6 8 rotary
Compact 0 15 0 1 0 0
Large 0 0 0 7 4 0
Midsize 0 7 1 12 2 0
Small 3 18 0 0 0 0
Sporty 0 8 0 4 1 1
Van 0 1 1 7 0 0
> mosaic(Car_table_3,
+ gp=gpar(fill=c("red", "blue")),
+ direction="v",
+ main="Mosaic plot of Car Type & Cylinders")
|
많은 도움 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡'를 꾸욱 눌러주세요. ^^