14.5 체르노프 얼굴그림 (Chernoff faces) : aplpack package, faces() 함수

이번 포스팅에서는 (5) 체르노프 얼굴그림 (Chernoff faces)에 대해서 소개하겠습니다.

체르노프 얼굴그림은 다변량 변수의 속성값들을 아래의 표에 나오는 것처럼 15가지의 얼굴의 생김새(얼굴 높이, 얼굴 넓이, 입 높이, 입 넓이…등) 특성에 매핑해서 얼굴 모양이 달라지게 하는 방식입니다.

얼굴 특성 (face characteristics) 다변량 변수 (multivariate mapping)
1. 얼굴의 높이 “height of face” “Price”
2. 얼굴의 넓이 “width of face” “MPG.highway”
3. 얼굴의 구조 “structure of face” “Horsepower”
4. 입의 높이 “height of mouth” “RPM”
5. 입의 넓이 “width of mouth” “Length”
6. 웃음 “smiling” “Weight”
7. 눈의 높이 “height of eyes” “Price”
8. 눈의 넓이 “width of eyes” “MPG.highway”
9. 머리카락 높이 “height of hair” “Horsepower”
10. 머리카락 넓이 “width of hair” “RPM”
11. 헤어스타일 “style of hair” “Length”
12. 코 높이 “height of nose” “Weight”
13. 코 넓이 “width of nose” “Price”
14. 귀 넓이 “width of ear” “MPG.highway”
15. 귀 높이 “height of ear” “Horsepower”

체르노프 얼굴그림은 얼굴 모양을 가지고 데이터 관측치들의 특성을 직관적으로 파악할 수 있다는 장점이 있습니다. 다만, 각 변수가 얼굴 모양의 어느 특성에 매핑이 되었는지를 확인하고자 한다면 앞서 살펴본 레이터 차트나 별그림, 평행좌표그림 등에 비해 불편한 편이고, 왠지 official한 느낌은 덜 듭니다. 그래서 저 같은 경우는 회사에서 보고서에 체르노프 얼굴그림을 사용해본 적은 아직까지는 없습니다. ^^; 그래도 다변량 데이터를 신속하게, 직관적으로 탐색적분석 하는 용도로는 알아듬직 하므로 이번 포스팅을 이어가 보겠습니다.

14.5.1 데이터 세트

예제에 사용할 데이터는 MASS Package에 내장되어있는 Cars93 dataframe을 사용하겠으며, 전체 93개의 관측치가 있는데요, 이를 모두 그리자니 너무 많아서요, 1번째 관측치부터 20번째 관측치까지만 사용하겠습니다. 체르노프 얼굴그림 그릴 때 사용할 변수로는 가격("Price"), 고속도로연비("MPG.highway"), 마력("Horsepower"), RPM("RPM"), 차길이("Length"), 차무게("Weight")의 5개 만 선별해서 사용하겠습니다. 아래처럼 Cars93_1 이라는 새로운 이름의 데이터프레임을 만들었습니다.

# dataset preparation
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 ...
# sampling observations from 1st to 20th, selecting 5 variables
Cars93_1 <- Cars93[c(1:20),c("Price", "MPG.highway", "Horsepower", 
                             "RPM", "Length", "Weight")]
Cars93_1
##    Price MPG.highway Horsepower  RPM Length Weight
## 1     16          31        140 6300    177   2705
## 2     34          25        200 5500    195   3560
## 3     29          26        172 5500    180   3375
## 4     38          26        172 5500    193   3405
## 5     30          30        208 5700    186   3640
## 6     16          31        110 5200    189   2880
## 7     21          28        170 4800    200   3470
## 8     24          25        180 4000    216   4105
## 9     26          27        170 4800    198   3495
## 10    35          25        200 4100    206   3620
## 11    40          25        295 6000    204   3935
## 12    13          36        110 5200    182   2490
## 13    11          34        110 5200    184   2785
## 14    15          28        160 4600    193   3240
## 15    16          29        110 5200    198   3195
## 16    16          23        170 4800    178   3715
## 17    17          20        165 4000    194   4025
## 18    19          26        170 4200    214   3910
## 19    38          25        300 5000    179   3380
## 20    18          28        153 5300    203   3515

14.5.2 체로노프 얼굴그림 그리기

14.5.2.1 패키지 불러오기

체로노프 얼굴그림을 그리기 위해 R의 aplpack Packagefaces() 함수를 사용하겠습니다.

install.package() 함수를 써서 설치하고, library() 함수로 호출해 보겠습니다.

# install.packages("aplpack")
library(aplpack)

14.5.2.2 faces() 함수의 형식

이제 faces() 함수로 체르노프 얼굴 그림을 그려보겠습니다.

faces(dataset, face.type = 0/1/2, main = "title") 의 형식으로 사용합니다.

  • face.type = 0 (line drawing faces)은 색깔 없이 선으로만 얼굴을 그립니다.

  • face.type = 1 (the elements of the faces are painted)는 색깔도 같이 칠해서 얼굴을 그려줍니다.

  • face.type = 2 (Santa Claus faces are drawn)는 산타클로스 얼굴에 색을 칠해서 그려주고요.

아래에 하나씩 예를 들어보겠습니다.

14.5.2.3 체르노프 얼굴 그림 그리기

14.5.2.3.1 face.type = 0 (line drawing faces)
# face.type = 0 : line drawing faces
faces(Cars93_1, face.type = 0, main = "Chernoff faces: face.type = 0")

## effect of variables:
##  modified item       Var          
##  "height of face   " "Price"      
##  "width of face    " "MPG.highway"
##  "structure of face" "Horsepower" 
##  "height of mouth  " "RPM"        
##  "width of mouth   " "Length"     
##  "smiling          " "Weight"     
##  "height of eyes   " "Price"      
##  "width of eyes    " "MPG.highway"
##  "height of hair   " "Horsepower" 
##  "width of hair   "  "RPM"        
##  "style of hair   "  "Length"     
##  "height of nose  "  "Weight"     
##  "width of nose   "  "Price"      
##  "width of ear    "  "MPG.highway"
##  "height of ear   "  "Horsepower"
14.5.2.3.2 face.type = 1 (the elements of the faces are painted)
# face.type = 1 : the elements of the faces are painted
faces(Cars93_1, face.type = 1, main = "Chernoff faces: face.type = 1")

## effect of variables:
##  modified item       Var          
##  "height of face   " "Price"      
##  "width of face    " "MPG.highway"
##  "structure of face" "Horsepower" 
##  "height of mouth  " "RPM"        
##  "width of mouth   " "Length"     
##  "smiling          " "Weight"     
##  "height of eyes   " "Price"      
##  "width of eyes    " "MPG.highway"
##  "height of hair   " "Horsepower" 
##  "width of hair   "  "RPM"        
##  "style of hair   "  "Length"     
##  "height of nose  "  "Weight"     
##  "width of nose   "  "Price"      
##  "width of ear    "  "MPG.highway"
##  "height of ear   "  "Horsepower"
14.5.2.3.3 face.type = 2 (Santa Claus faces are drawn)
# face.type = 2 : Santa Claus faces are drawn
faces(Cars93_1, face.type = 2, main = "Chernoff faces: face.type = 2")

## effect of variables:
##  modified item       Var          
##  "height of face   " "Price"      
##  "width of face    " "MPG.highway"
##  "structure of face" "Horsepower" 
##  "height of mouth  " "RPM"        
##  "width of mouth   " "Length"     
##  "smiling          " "Weight"     
##  "height of eyes   " "Price"      
##  "width of eyes    " "MPG.highway"
##  "height of hair   " "Horsepower" 
##  "width of hair   "  "RPM"        
##  "style of hair   "  "Length"     
##  "height of nose  "  "Weight"     
##  "width of nose   "  "Price"      
##  "width of ear    "  "MPG.highway"
##  "height of ear   "  "Horsepower"

산타클로스 얼굴은 정신이 하도 산만해서 관측치들간의 유사성이나 차이가 눈에 잘 안들어오네요. @@~

14.5.2.3.4 체로노프 얼굴그림에 이름 추가하기 : labels =
# putting labels as face names : labels
faces(Cars93_1, face.type = 1, 
      labels = Cars93[1:20,]$Model, 
      main = "putting labels as face names : labels = ")

## effect of variables:
##  modified item       Var          
##  "height of face   " "Price"      
##  "width of face    " "MPG.highway"
##  "structure of face" "Horsepower" 
##  "height of mouth  " "RPM"        
##  "width of mouth   " "Length"     
##  "smiling          " "Weight"     
##  "height of eyes   " "Price"      
##  "width of eyes    " "MPG.highway"
##  "height of hair   " "Horsepower" 
##  "width of hair   "  "RPM"        
##  "style of hair   "  "Length"     
##  "height of nose  "  "Weight"     
##  "width of nose   "  "Price"      
##  "width of ear    "  "MPG.highway"
##  "height of ear   "  "Horsepower"

14.5.3 산포도에 체르노프 얼굴그림 겹쳐 그르기

  1. 먼저 산포도plot() 함수를 사용해서 그립니다.

  2. 그 다음에 faces() 함수로 체르노프 얼굴그림을 실행시킵니다. 이때 scale = TRUE, plot = FALSE 옵션을 사용해줍니다. 그래프는 화면에 안나타나구요, (3)번 스텝에서 그래프가 그려질 수 있도록 데이터가 준비된 상태입니다.

  3. plot.faces() 함수를 사용해서 산포도 위에 (2)번에서 생성해 놓은 체르노프 얼굴그림을 겹쳐서 그려줍니다. widthheight 는 x축과 y축의 단위를 보고서 trial & error 를 해보면서 숫자를 조금씩 바꿔가면서 그려본 후에 가장 마음에 드는 걸로 선택하면 되겠습니다.

체르노프 얼굴그림을 산포도에 겹쳐서 그리니 제법 유용한 다차원 그래프이지 않은가요? ^^

# Overlapping Chernoff faces over scatter plot (MPG.highway*Weight)
plot(Cars93_1[,c("MPG.highway", "Weight")], 
     bty="n", # To make a plot with no box around the plot area
     main = "Chernoff faces of Cars93")

Cars93_1_faces <- faces(Cars93_1, scale = TRUE, plot=FALSE)
## effect of variables:
##  modified item       Var          
##  "height of face   " "Price"      
##  "width of face    " "MPG.highway"
##  "structure of face" "Horsepower" 
##  "height of mouth  " "RPM"        
##  "width of mouth   " "Length"     
##  "smiling          " "Weight"     
##  "height of eyes   " "Price"      
##  "width of eyes    " "MPG.highway"
##  "height of hair   " "Horsepower" 
##  "width of hair   "  "RPM"        
##  "style of hair   "  "Length"     
##  "height of nose  "  "Weight"     
##  "width of nose   "  "Price"      
##  "width of ear    "  "MPG.highway"
##  "height of ear   "  "Horsepower"
plot.faces(Cars93_1_faces, 
           Cars93_1[,c("MPG.highway")], 
           Cars93_1[,c("Weight")], 
           width = 2, 
           height = 250)

체르노프 얼굴그림에 대해서 좀더 알고 싶은 분은 아래의 Reference를 참고하시기 바랍니다.

14.5.4 pairs() 함수를 사용한 산포도 행렬 그리기

14.5.5 R 모자이크 그림: vcd패키지 mosaic() 함수