데이터 변환 방법으로서
(1) 표준화
(2) 정규분포화
(3) 범주화
- (3-1) 이산형화(discretization)
- (3-2) 이항변수화(binarization)
(4) 개수 축소
(5) 차원 축소
- 주성분분석
- 요인분석
(6) 시그널 데이터 압축
중에서 우선 (3-1) 이산형화(discretization)에 대해서 알아보겠습니다.
분할표(contingency table)를 구하거나 카이제곱 검정을 할 때 범주형 변수를 대상으로 집단 간 독립성 검정을 하게 됩니다. 이처럼 분석기법에 따라서 연속형 변수를 범주형 변수로 변환을 한 이후에야 분석이 가능한 경우가 있습니다.
혹은, 회귀분석을 한다고 했을 때 명목형, 범주형 자료에 대해서 가변수(dummy variable) 화 해서 분석을 진행해야 할 때도 있습니다. 가령 요일효과를 모형에 적합시키고자 한다면 요일 변수를 월요일 여부(mon_yn), 화요일 여부(tue_yn), ... , 토요일 여부(sat_yn) 등과 같이 1, 0 으로 코드화된 가변수로 변환해야 하는 경우도 있습니다.
이번 포스팅에서는 첫번째 경우의 (1) 이산형화, 두번째 경우의 (2) 이항변수화에 대해서 R에서는 어떻게 처리하는지 알아보도록 하겠습니다.
R 데이터 변환 (3) 범주화 : 이산형화(discretization) |
[ 데이터 변환 구성 ]
(3-1) 이산형화 (Discretization)
연속형 변수를 범주형 변수로 변환하는 작업을 이산형화라고 합니다. 이산형화 변화 시에는 '몇 개의 범주로 나눌지?'와 '구분선(cutting line)을 무슨 기준으로, 어디로 할지?'가 중요한 질문이 되겠습니다.
두 질문에 대한 학술적인 단 하나의 답안은 없습니다. 두 질문에 대해 공통적으로 분석/활용의 목적이 무엇이냐와 Biz. Domain Konwledge가 충분히 반영이 되어서 의사결정을 해야만 하고, 운영 과정상의 시행착오와 경험을 통한 긍정/부정적 피드백을 반영하여 지속적으로 개선해나가야 할 것입니다.
이번 포스팅에서는 (a) 간격을 동일하게 한 범주화와 (b) quantile을 활용한 범주화 (c) frequency를 동일하게 한 범주화를 R로 어떻게 하는지Cars93 데이터셋의 고속도로 연비(MPG.highway)을 가지고 예를 들어보겠습니다.
(참고로, Cars93 은 MASS 패키지에 내장된 데이터 셋으로서, 자동차의 속성에 대해서 27개의 변수, 93개 자동차 관측치를 가진 데이터 프레임)
(a) 간격을 동일하게 한 범주화는 R의 hist() 함수로 히스토그램을 그려보는 것이 좋은 출발점이 될 수 있습니다. R의 hist() 함수의 디폴트 구간 개수가 꽤 좋은 결과를 내주거든요. bin size를 조정해가면서 분포를 탐색해보고서 특정 구간에서 변곡점이 있다면, 혹은 특정 segment 나 factor 별로 분포상의 큰 차이를 보인다면 그 구분선을 가지고 범주를 나눌 수도 있을 것입니다.
R의 within() 함수를 활용하여 아래의 Cars93의 고속도로연비는 20~50까지 5단위씩 등간격으로 6개 범주로 나누어 보겠습니다.
> 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 .. > ## 고속도로연비(MPG.highway) 히스토그램
> hist(Cars93$MPG.highway)
> ## Model, MPG.highway 두 개 변수만 선택해서 disc_1 데이터 프레임 생성
> disc_1 <- Cars93[,c("Model", "MPG.highway")] > ## 상위 6개 미리보기 > head(disc_1)
Model MPG.highway
1 Integra 31
2 Legend 25 3 90 26
4 100 26 5 535i 30
6 Century 31
> > > ## 6개 범주로 등간격 범주화
> disc_1 <- within( disc_1, {
+ MPG.highway_cd = character(0)
+ MPG.highway_cd[ MPG.highway >=20 & MPG.highway <25 ] = "20~25"
+ MPG.highway_cd[ MPG.highway >=25 & MPG.highway <30 ] = "25~30"
+ MPG.highway_cd[ MPG.highway >=30 & MPG.highway <35 ] = "30~35"
+ MPG.highway_cd[ MPG.highway >=35 & MPG.highway <40 ] = "35~40"
+ MPG.highway_cd[ MPG.highway >=40 & MPG.highway <45 ] = "40~45"
+ MPG.highway_cd[ MPG.highway >=45 & MPG.highway <=50 ] = "45~50"
+ MPG.highway_cd = factor(MPG.highway_cd,
+ level = c("20~25", "25~30", "30~35",
+ "35~40", "40~45", "45~50"))
+ }) > > ## 상위 6개 보기
> head(disc_1)
Model MPG.highway MPG.highway_cd
1 Integra 31 30~35
2 Legend 25 25~30
3 90 26 25~30
4 100 26 25~30
5 535i 30 30~35
6 Century 31 30~35
> attributes(disc_1$MPG.highway_cd)
$levels
[1] "20~25" "25~30" "30~35" "35~40" "40~45" "45~50"
$class
[1] "factor" > table(disc_1$MPG.highway_cd) # 분할표 생성
20~25 25~30 30~35 35~40 40~45 45~50
14 41 27 7 2 2
|
"MPG.highway" 변수 옆에 "MPG.highway_cd" 라는 범주형 변수가 생겼음을 알 수 있습니다. 나중에 통계분석과 연계하기 위해 "MPG.highway_cd" 변수를 within()함수의 제일 마지막 줄에서 요인(factor)으로 지정을 해줬고, level = c("20~25", "25~30", "30~35", "35~40", "40~45", "45~50")) 으로 순서형 요인(ordered factor)의 수준을 지정해주었습니다.
다음으로 (b) quantile을 활용한 범주화 방법에 대해서 알아보겠습니다. MPG.highway를 0~25%, 25~50%, 50~75%, 75~100%의 구성비로 해서 4개 범주로 나누어보겠습니다.
> summary(disc_1$MPG.highway)
Min. 1st Qu. Median Mean 3rd Qu. Max.
20.00 26.00 28.00 29.09 31.00 50.00 > > # 4분위수의 1Q, 2Q, 3Q, 4Q를 기준으로 4개의 범주 생성
> disc_1 <- within( disc_1, {
+ MPG.highway_cd2 = character(0)
+ MPG.highway_cd2[ MPG.highway < quantile(MPG.highway, 0.25) ] = "1Q"
+ MPG.highway_cd2[ MPG.highway >= quantile(MPG.highway, 0.25)
+ & MPG.highway < quantile(MPG.highway, 0.50) ] = "2Q"
+ MPG.highway_cd2[ MPG.highway >=quantile(MPG.highway, 0.50)
+ & MPG.highway < quantile(MPG.highway, 0.75) ] = "3Q"
+ MPG.highway_cd2[ MPG.highway >= quantile(MPG.highway, 0.75) ] = "4Q"
+ MPG.highway_cd2 = factor(MPG.highway_cd2,
+ level = c("1Q", "2Q", "3Q", "4Q"))
+ }) > > # 상위 6개 보기
> head(disc_1)
Model MPG.highway MPG.highway_cd MPG.highway_cd2
1 Integra 31 30~35 4Q
2 Legend 25 25~30 1Q
3 90 26 25~30 2Q
4 100 26 25~30 2Q
5 535i 30 30~35 3Q
6 Century 31 30~35 4Q
> table(disc_1$MPG.highway_cd2) # 분할표 생성
1Q 2Q 3Q 4Q
22 17 25 29
|
다음으로, (c) frequency를 동일하게 해서 4개 범주를 구성해보도록 하겠습니다. 먼저 고속도로연비(MPG.highway) 기준으로 정렬을 해줘야합니다.
> ## 고속도로연비(MPG.highway) 기준으로 오름차순 정렬
> disc_1 <- disc_1[order(disc_1$MPG.highway), ]
> dim(disc_1) # 93개 관측치, 4개 변수
[1] 93 4
## 관측치 개수 > dim(disc_1)[1]
[1] 93 > > disc_1$N <- seq(1:length(disc_1$MPG.highway)) # 1~93까지 순서대로 1씩 증가하는 N이라는 변수 생성
> > # 동일 frequency (23개)로 4개 범주 생성 > disc_1 <- within( disc_1, {
+ MPG.highway_cd3 = character(0)
+ MPG.highway_cd3[ N <= 23 ] = "1st_Freq"
+ MPG.highway_cd3[ N >= 24 & N <= 46 ] = "2nd_Freq"
+ MPG.highway_cd3[ N >= 47 & N <= 69 ] = "3rd_Freq"
+ MPG.highway_cd3[ N >= 70 ] = "4th_Freq"
+ MPG.highway_cd3 = factor(MPG.highway_cd3,
+ level = c("1st_Freq", "2nd_Freq", "3rd_Freq", "4th_Freq"))
+ })
>
> head(disc_1)
Model MPG.highway MPG.highway_cd MPG.highway_cd2 N MPG.highway_cd3
17 Astro 20 20~25 1Q 1 1st_Freq
36 Aerostar 20 20~25 1Q 2 1st_Freq
26 Caravan 21 20~25 1Q 3 1st_Freq
89 Eurovan 21 20~25 1Q 4 1st_Freq
48 Q45 22 20~25 1Q 5 1st_Freq
87 Previa 22 20~25 1Q 6 1st_Freq
>
> table(disc_1$MPG.highway_cd3)
1st_Freq 2nd_Freq 3rd_Freq 4th_Freq
23 23 23 24
|
위의 분할표를 보면 4개 범주별로 23개, 23개, 23개, 24개(총 93개여서 마지막에 1개 더 넣음) 로 동일 frequency로 범주화가 되었음을 알 수 있습니다. 그런데 (c) 같은 frequency 로 범주화 시에 동일한 고속도로연비임에도 범주가 다르게 구분이 되는 수가 생깁니다. 아래 예에서 보면 고속도로연비가 28인 경우 "2nd_Freq"와 "3rd_Freq" 범주에 양다리 걸쳐있는것을 확인할 수 있습니다. ("1st_Freq"와 "2nd_Freq"에도 고속도로연비 26이 양다리를 걸치고 있습니다. 또한 31이 "3rd_Freq"와 "4th_Freq"에 양다리를 걸치고 있습니다.) 이처럼 동일 frequency로 범주화시에는 중첩됨이 없이 범주화하기가 어려운 문제점이 있습니다. 따라서 해석의 용이성과 중첩 방지를 위해서 (a) 등간격 범주화 또는 (b) quantile 활용 범주화가 (c) 동일 freqency보다는 좀더 유용하다고 볼 수 있겠습니다.
이항변수화 (binarization)은 다음번 포스팅에서 소개해드리겠습니다.
이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^