수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

이번 포스팅에서는 (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한 느낌은 덜 듭니다. 그래서 저 같은 경우는 회사에서 보고서에 체르노프 얼굴그림을 사용해본 적은 아직까지는 없습니다. ^^;  그래도 다변량 데이터를 신속하게, 직관적으로 탐색적분석 하는 용도로는 알아듬직 하므로 이번 포스팅을 이어가 보겠습니다.

 

 

예제에 사용할 데이터는 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   15.9          31        140 6300    177   2705
2   33.9          25        200 5500    195   3560
3   29.1          26        172 5500    180   3375
4   37.7          26        172 5500    193   3405
5   30.0          30        208 5700    186   3640
6   15.7          31        110 5200    189   2880
7   20.8          28        170 4800    200   3470
8   23.7          25        180 4000    216   4105
9   26.3          27        170 4800    198   3495
10  34.7          25        200 4100    206   3620
11  40.1          25        295 6000    204   3935
12  13.4          36        110 5200    182   2490
13  11.4          34        110 5200    184   2785
14  15.1          28        160 4600    193   3240
15  15.9          29        110 5200    198   3195
16  16.3          23        170 4800    178   3715
17  16.6          20        165 4000    194   4025
18  18.8          26        170 4200    214   3910
19  38.0          25        300 5000    179   3380
20  18.4          28        153 5300    203   3515

 

 

 

 

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

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

 

> install.packages("aplpack")
Installing package into ‘C:/Users/Owner/Documents/R/win-library/3.2’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.2/aplpack_1.3.0.zip'
Content type 'application/zip' length 3156450 bytes (3.0 MB)
downloaded 3.0 MB

package ‘aplpack’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\Owner\AppData\Local\Temp\Rtmpk3jrgb\downloaded_packages
> 
> library(aplpack)
필요한 패키지를 로딩중입니다: tcltk

 

 

 

 

이제 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)는 산타클로스 얼굴에 색을 칠해서 그려주고요.

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

 

  • 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"

 

 

 

 

 

 

  • 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"

 

 

 

 

  • 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"

 

 

 

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

 

 

 

  • 체로노프 얼굴그림에 이름 추가하기 : 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"

 

 

 

 

 

  • 산점도에 체르노프 얼굴그림 겹쳐 그르기 (overlapping chernoff faces over scatter plot)

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

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

(3) plot.faces() 함수를 사용해서 산점도 위에 (2)번에서 생성해 놓은 체르노프 얼굴그림을 겹쳐서 그려줍니다. width 와 height 는 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를 참고하시기 바랍니다.

[ Reference ] http://www.inside-r.org/packages/cran/aplpack/docs/faces

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,

수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

이번 포스팅에서는 (4) 3차원 산점도 (3 dimensional scatter plot)에 대해서 소개하겠습니다. 

 

3차원 그래프를 그릴 수 있는 Package가 여러개 있는데요, 그 중에서도 3차원 scatter plot에 특화된 scatterplot3d Package 의 scatterplot3d() 함수를 설명해보겠습니다.

 

예제로 사용할 데이터는 MASS Package에 내장된 Cars93 데이터 프레임의 고속도로연비(MPG.highway), 마력(Horsepower), 무게(Weight) 변수들입니다.

 

> ##----------------------------------------
> ## 3 dimensional scatter plot 
> ##----------------------------------------
> 
> 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 ...

 

 

 

 

library(scatterplot3d)로 패키지를 로딩합니다.

 

scatterplot3d(x, y, z, ...)로 3차원 그래프의 x, y, z 좌표(coordinate)를 지정해줍니다. 아래 예제에서는 x축에 무게(Weight), y축에는 마력(Horsepower), z축에는 연비(MPG.highway)를 할당하였습니다.

 

type = "h" 는 수직선으로 표현하라는 옵션입니다. "p"는 점으로 표현, "l"은 선으로 표현하라는 의미입니다. 아래 예시의 경우는 3차원 공간에 나타내다 보니 "p"나 "l"보다는 "h"가 점과 x, y축 기준 수직선이 함께 보여서 인지하기에 더 수월하기에 type = "h"로 해서 그려보았습니다.

 

scale.y = 0.7 은 x축과 z축을 기준으로 상대적으로 y축은 0.7 배로 해서 나타내라는 뜻입니다. 아래의 프로그램을 복사한 다음에 숫자를 바꿔서 한번 그려보시면 그래프가 어떻게 바뀌는지 금방 이해하실 겁니다.

 

angle = 50 은 x와 y축의 각도를 뜻합니다.  scale.y 와 angle 옵션의 숫자를 바꿔가면서 분석가가 원하는 길이, 각도가 나올 때까지 몇 번 trial and error 로 시도를 해보시면 됩니다.

 

highlight.3d = TRUE  옵션은 y축의 좌표를 기준으로 색깔이 달라지게 하라는 의미입니다. 아래 그래프의 경우 y축 좌표 값이 작을 수록 빨간색, y축 좌표값이 클수록 검정색으로 자동으로 바뀌었습니다.  만약 highlight.ed = FALSE 라고 지정하면 그냥 y축 좌표값이 어떻게 되던간에 모두 검정색으로 나오게 되므로 3차원의 공간감을 나타내는데 부족함이 있습니다. 따라서 highlight.3d = TRUE 옵션 사용을 권장합니다.

 

box = TRUE  옵션은 아래에 파란색(col.axis = "blue")으로 표시된 부분을 그리라는 뜻입니다. default 는 box = TRUE 이므로 별도로 명기하지 않아도 되며, 표기하기 싫을 때는 box = FALSE 라고 표기해야 겠지요.

 

grid = TRUE 는 아래의 예에서 회색(col.grid = "gray")으로 표시된 부분을 나타낼지 정하는 옵션입니다. 이 역시 default 는 grid = TRUE 이므로 별도로 명기하지 않아도 되며, grid 를 제외하고 싶은 때는 grid = FALSE 라고 옵션을 부여하면 됩니다.

 

mar = c(3, 4, 4, 3) 은 아래쪽, 왼쪽, 위쪽, 오른쪽의 순서대로 margin을 부여하는 옵션입니다.  margin도 숫자를 조금씩 바꿔가면서 한번 시험해보시기 바랍니다.  그래프가 margin에 따라서 조금씩 바뀌는걸 알 수 있을 겁니다.  귀찮으면 그냥 default margin c(5.1, 4.1, 4.1, 2.1) 을 사용하면 되겠습니다(mar 옵션 미사용하면 default margin 적용됨).

 

xlab, ylab, zlab 은 x축, y축, z축에 label 부여할 때 사용하는 옵션입니다.

 

main = "xxx"은 제목 붙이는 옵션이구요.

 

 

> library(scatterplot3d) > > x <- Cars93$Weight > y <- Cars93$Horsepower > z <- Cars93$MPG.highway > > > # 3 dimensional scatter plotting > Cars93_3d <- scatterplot3d(x, y, z, + type = "h", # "p" for point, "l" for line, "h" for vertical lines to x-y-plane + pch=16, # symbol, character + scale.y = 0.7, # scale of y axis related to x- and z axis + angle = 50, # angle between x and y axis + highlight.3d=TRUE, # points will be drawn in different colors related to y coordinates + box = TRUE, # a logical value indicating whether a box should be drawn around the plot + col.axis="blue", # the color to be used for axis + grid = TRUE, # a logical value indicating whether a grid should be drawn on the plot + col.grid="gray", # the color to be used for grid + mar = c(3, 4, 4, 3), # margin : c(bottom, left, top, right) + xlab = "x_Weight", # label for the x + ylab = "y_Horsepower", # label for the y + zlab = "z_MPG.highway", # label for the z + main="3 dimensional scatter plot of Cars93") # main title

 

 

 

 

 

 

혹시 색깔을 좀더 다양하게 해보고 싶다면 아래처럼 color 옵션을 사용하면 됩니다. rainbow color를 적용해보았습니다. 저는 위에서 그린 highlight.3d = TRUE 옵션이 아래의 color = rainbowcolor 로 화려하게 그린 그래프보다 시각적으로 더 인지하기에 좋아 보이네요.  아래 그림은 좀 어지럽게 느껴지구요.

 

> # using rainbow color

> dim(Cars93)
[1] 93 27

> rainbowcolor <- rainbow(93) # number 93 indicate 93 observations of Cars93 dataframe > > Cars93_3d <- scatterplot3d(x, y, z, + type = "h", # "p" for point, "l" for line, "h" for vertical lines to x-y-plane + pch=16, # symbol, character + scale.y = 0.7, # scale of y axis related to x- and z axis + angle = 50, # angle between x and y axis + color = rainbowcolor, # colors of points in the plot + box = TRUE, # a logical value indicating whether a box should be drawn around the plot + col.axis="blue", # the color to be used for axis + grid = TRUE, # a logical value indicating whether a grid should be drawn on the plot + col.grid="gray", # the color to be used for grid + mar = c(3, 4, 4, 3), # margin : c(bottom, left, top, right) + xlab = "x_Weight", # label for the x + ylab = "y_Horsepower", # label for the y + zlab = "z_MPG.highway", # label for the z + main="3 dimensional scatter plot of Cars93 - using rainbow color") # main title

 

 

 

 

 

 

다음으로 Cars93_lm <- lm(MPG.highway ~ Weight + Horsepower) 를 사용해서 x축 무게(Weight)와 y축 마력(Horsepower)와 z축 고속도로연비(MPG.highway) 간의 회귀모형을 적합시킨 후에, 3D scatter plot에 회귀평면(regression plane)을 그려보도록 하겠습니다.  보통 2차원 산포도를 그리고 선형회귀모형을 적합시킨 후에 선형회귀선을 2차원 산포도에 추가로 그려놓고는 했었을 것입니다. 아래 예시는 z ~ x + y 로 회귀모형을 적합시켜서 3차원 그래프로 그린 것인데요, 아무래도 2차원 그래프보다는 좀 이해하기가 어렵습니다. 

 

> # Adding a regression plane to the "scatterplot3d"
> attach(Cars93)

> Cars93_lm <- lm(MPG.highway ~ Weight + Horsepower) > Cars93_3d$plane3d(Cars93_lm, lty.box = "solid")

> detach(Cars93)

 

 

 

 

 

 

 

만약 위의 그래프를 톰크루즈가 주연으로 나왔던 영화 minority report 처럼 3차원 그래프를 상, 하, 좌, 우로 자유자재로 돌려볼 수 있다면 아마도 좀더 데이터의 분포 형태를 좀더 인지하기가 쉬울 것입니다.  아쉽게도 scatterplot3d Package는 이 기능을 지원하지 않는데요, 혹시 이 기능을 원하신다면 3D 그래프를 회전시키면서 볼 수 있는 다른 오픈소스를 찾아보셔야 할 거예요.

 

 

 

[ 영화 Minority Report 의 한 장면 ]

 

* 출처 : http://www.bustle.com/articles/111715-will-tom-cruise-be-in-the-minority-report-tv-show-its-telling-a-different-story

 

 

 

scatterplot3d Package에 대해서 좀더 알고 싶은신 분, 다른 예제를 참고하고 싶으신 분은 아래의 Reference를 참고하시기 바랍니다.

 

[Reference] https://cran.r-project.org/web/packages/scatterplot3d/scatterplot3d.pdf

 

 

많은 도움이 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,

수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

산점도 행렬(http://rfriend.tistory.com/83, http://rfriend.tistory.com/82)과 모자이크 그림(http://rfriend.tistory.com/71)은 이전 포스팅을 참고하시기 바랍니다.

 

이번 포스팅에서는 (3) 평행 좌표 그림 (parallel coordinate plot)에 대해서 소개하겠습니다. 

 

MASS Package의 parcoord() 함수를 사용하겠으며, 예제 데이터 역시 MASS Package에 내장된 Cars93 데이터 프레임의 차종(Type)별로 선모양(line type)과 색깔(color)을 달리하여 가격(Price), 고속도로연비(MPG.highway), 마력(Horsepower), 분당회전수(RPM), 길이(Length), 무게(Weight) 변수를 가지고 그래프를 그려보겠습니다.

 

 

 

> ##--------------------------------------
> ## parallel coordinate plot
> ##--------------------------------------
> 
> 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 ...

 

 

 

차종(Type)별로 선 모양(lty)과 선 색깔(col)을 다르게 하기 위해서 데이터 전처리를 해보겠습니다. 차종이 현재는 "Compact", "Large" 등과 같이 character 로 되어있는데요, 1, 2, ..., 6 의 numeric 으로 변환하겠습니다.

 

> # making Type_number variable to put line type and color by Car Type
> Cars93_1 <- transform(Cars93, 
+                       Type_no = ifelse(Type == "Compact", 1, 
+                                        ifelse(Type == "Large", 2, 
+                                               ifelse(Type == "Midsize", 3, 
+                                                      ifelse(Type == "Small", 4, 
+                                                             ifelse(Type == "Sporty", 5, 6)))))
+                       )
> # checking top 10 observations
> head(Cars93_1[,c("Type", "Type_no")], n=10)
      Type Type_no
1    Small       4
2  Midsize       3
3  Compact       1
4  Midsize       3
5  Midsize       3
6  Midsize       3
7    Large       2
8    Large       2
9  Midsize       3
10   Large       2
>  

 

 

 

 

이제 준비가 되었네요. MASS Package의 parcoord() 함수를 사용해서 평행 좌표 그림(parallel coordinate plot)을 그려보겠습니다. 

 

Cars93_1[, c("MPG.highway", "RPM", "Horsepower", "Weight", "Length", "Price")] 은 평행좌표그림을 그릴 대상 변수만 선별해오는 명령문입니다.

 

위에서 Cars93_1 이라는 새로운 데이터 프레임에 Type_no 라는 numeric 변수를 만들었는데요, 선 유형(lty, line type)과 색깔(col, color)를 Cars93_1$Type_no 로 지정을 해줘서 차종(Type)에 따라서 선 유형과 색깔이 달라지게 했습니다.

 

var.label = TRUE 옵션을 설정하면 각 변수별로 minimum value, maximum value 가 하단과 상단에 표기됩니다.

 

main = "parallel coordinate plot of Cars93 by Type" 옵션은 그래프에 제목 넣을 때 사용합니다.

 

아래 그래프 상단 우측에 범례가 들어가 있는데요, legend() 함수를 사용해서 추가한 것입니다.

 

> # parallel coordinate plot > library(MASS)

> parcoord(Cars93_1[, c("MPG.highway", "RPM", "Horsepower", "Weight", "Length", "Price")], 
+          lty = Cars93_1$Type_no,
+          col = Cars93_1$Type_no, 

+ var.label = TRUE, + main = "parallel coordinate plot of Cars93 by Type") > > # putting legend > legend("topright", + legend = c("Compact", "Large", "Midsize", "Small", "Sporty", "Van"), + lty = c(1:6), + col = c(1:6), + lwd = 2, # line width + cex = 0.7) # character size

 

 

 

 

다음번 포스팅에서는 3차원 산점도 (3 dimensional scatter plot)에 대해서 소개하도록 하겠습니다.

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

 

728x90
반응형
Posted by Rfriend
,

수 3개 이상의 다변량 데이터(multivariate data set)를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그래프 (star graph) (레이더 차트와 유사, 중심점 차이 존재)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

 

산점도 행렬(http://rfriend.tistory.com/83, http://rfriend.tistory.com/82)과 모자이크 그림(http://rfriend.tistory.com/71)은 이전 포스팅을 참고하시기 바랍니다.

 

이번 포스팅에서는 (2) 별 그래프 (star graph)에 대해서 소개하겠습니다. 

 

graphics Package의 stars() 함수를 사용하겠습니다.  graphics Package는 base Package로서 R 설치할 때 기본으로 설치되므로 stars() 함수를 사용하기 위해 추가로 별도 패키지 설치는 필요하지 않습니다.

 

stars() 함수는 dataframe 이나 matrix 형태의 데이터셋을 사용합니다. scale = TRUE 옵션을 사용하면 (minimum value) 0 ~ (maximum value) 1 사이의 값으로 다변량 변수들의 값을 표준화해줍니다.  별 그래프(star graph)의 기본 원리는 중심점(center point)으로 부터 각 관측치별/ 각 변수별로 거리(distance) 혹은 반지름(radius)이 얼마나 떨어져있는가를 시각화한 것입니다.

 

실습을 위해서 MASS Package에 내장된 Cars93 dataframe을 사용하겠습니다. 이전 포스팅 레이더 차트(radar chart) 와 비교하기 쉽도록 이번에도 차종(Type), 가격(Price), 고속도로연비(MPG.highway), 마력(Horsepower), 분당회전수(RPM), 길이(Length), 무게(Weight) 의 7개 변수를 똑같이 사용하겠습니다.

 

> 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 ...

 

 

 

 

93개의 차량 관측치가 있는데요, 이것을 6개의 차종(Type)을 기준으로 평균 통계량으로 요약한 후에, 차종별로 6개의 평균치 다변량 변수를 가지고 별 그래프를 그려보겠습니다.

 

> # cross tabulation by Car Type
> table(Cars93$Type)

Compact   Large Midsize   Small  Sporty     Van 
     16      11      22      21      14       9
> 
> # mean of multivariates by Car Type
> install.packages("doBy")
> library(doBy)
> 
> mean_by_Type <- summaryBy(MPG.highway + RPM + Horsepower + Weight + Length + Price ~ Type, 
+                           data=Cars93, 
+                           FUN = c(mean))
> 
> mean_by_Type
     Type MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean
1 Compact         29.87500 5362.500        131.0000    2918.125    182.1250   18.21250
2   Large         26.72727 4672.727        179.4545    3695.455    204.8182   24.30000
3 Midsize         26.72727 5336.364        173.0909    3400.000    192.5455   27.21818
4   Small         35.47619 5633.333         91.0000    2312.857    167.1905   10.16667
5  Sporty         28.78571 5392.857        160.1429    2899.643    175.2143   19.39286
6     Van         21.88889 4744.444        149.4444    3830.556    185.6667   19.10000

 

 

 

 

stars() 함수에서는 rownames 를 가져다가 labeling 을 합니다.  현재 rownames 는 1, 2,..., 6 의 숫자로 되어있으므로, 이를 차종(Type) 이름으로 변경하도록 하겠습니다. (굷게 파란색으로 밑줄친 부분)

 

> # creating row names with Type
> rownames(mean_by_Type) <- mean_by_Type$Type
> 
> mean_by_Type
           Type MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean
Compact Compact         29.87500 5362.500        131.0000    2918.125    182.1250   18.21250
Large     Large         26.72727 4672.727        179.4545    3695.455    204.8182   24.30000
Midsize Midsize         26.72727 5336.364        173.0909    3400.000    192.5455   27.21818
Small     Small         35.47619 5633.333         91.0000    2312.857    167.1905   10.16667
Sporty   Sporty         28.78571 5392.857        160.1429    2899.643    175.2143   19.39286
Van         Van         21.88889 4744.444        149.4444    3830.556    185.6667   19.10000

 

 

 

 

위에서 rownames() 로 뭐가 바뀌었나 잘 모를수도 있는데요, 아래에 화면 캡쳐한 그래프를 참고하시기 바랍니다. 제일 왼쪽에 rowname 이 숫자에서 차종(Type)으로 바뀐게 보이지요?

 

 

 

 

doBy Package로 요약통계량을 생성하면 변수명 뒤에 자동으로 통계량 이름이 따라 붙습니다. 이번 예제의 경우에는 평균을 구했으므로 MPG.highway.mean, RPM.mean, ... 이런 식으로요.  변수명이 너무 길다보니 나중에 labeling 할 때 옆으로 삐죽 튀어나가서 보기 싫어서요, 변수명을 좀더 짧게 변경해보겠습니다. 변수명 뒤에 .mean 을 생략하고 사용하겠습니다.  위에 rownames() 함수는 stars() 함수를 사용하려면 꼭 해줘야 하는 것이구요, 아래의 renames()는 필수사항은 아닙니다.

 

 

> # renaming of variables
> library(reshape)
> mean_by_Type <- rename(mean_by_Type, 
+                        c(MPG.highway.mean = "MPG.highway",  
+                          RPM.mean = "RPM",  
+                          Horsepower.mean = "Horsepower",  
+                          Weight.mean = "Weight", 
+                          Length.mean = "Length", 
+                          Price.mean = "Price"
+                          )
+                        )
> mean_by_Type
           Type MPG.highway      RPM Horsepower   Weight   Length    Price
Compact Compact    29.87500 5362.500   131.0000 2918.125 182.1250 18.21250
Large     Large    26.72727 4672.727   179.4545 3695.455 204.8182 24.30000
Midsize Midsize    26.72727 5336.364   173.0909 3400.000 192.5455 27.21818
Small     Small    35.47619 5633.333    91.0000 2312.857 167.1905 10.16667
Sporty   Sporty    28.78571 5392.857   160.1429 2899.643 175.2143 19.39286
Van         Van    21.88889 4744.444   149.4444 3830.556 185.6667 19.10000

 

 

 

이제 드디어 데이터셋이 준비가 되었습니다.  stars() 함수를 사용해서 별 그래프를 그려보겠습니다.

 

stars(x, ...) 의 x 자리에는 dataframe 이나 matrix 형태의 다변량 데이터셋 이름을 입력하면 됩니다.

locations = NULL, nrow = 2, ncol = 4 옵션은 행이 2줄, 열이 4줄인 square layout 으로 배열하라는 뜻입니다.

scale = TRUE 는 변수별로 단위(scale)가 달라서 들쭉날쭉한 값들을 변수별로 모두 최소값 0 ~ 최대값 1 사이로 변수별 값들을 표준화(standardization) 합니다.

full = TRUE 로 지정하면 360도의 전체 원으로 그래프를 그립니다. full = FALSE 로 지정하면 1180도짜리 반원(semi-circle)으로 그래프가 그려집니다.

radius = TRUE 로 지정하면 반지름 선이 그려집니다. 만약 radius = FALSE 로 하면 반지름 선이 안그려지는데요, 보기에 좀 휑~합니다. ^^'

frame.plot = TRUE 로 하면 그래프의 외곽에 네모 박스 선으로 테두리가 쳐집니다.

main 은 제목을 입력하는 옵션입니다. sub 는 부제목 입력하는 옵션이구요.

cex 는 글자 크기 지정하는 옵션인데요, default 가 1이고 숫자가 커질 수록 글자 크기가 커집니다.

lwd 는 선 두께 (line width) 지정하는 옵션입니다. default 가 1이며, 숫자가 커질 수록 선이 두꺼워집니다.

key.loc = c(7.5, 1.5) 는 x, y 좌표 위치에 각 변수들의 이름(unit key)을 범례로 집어넣습니다.

 

말로 설명해놓긴 했는데요, 잘 이해가 안갈수도 있겠습니다.  아래에 stars() 함수를 복사해놓고서 옵션마다 하나씩 '#'을 붙여가면서 실행을 해보시기 바랍니다.  그러면 '#'을 붙이기 전과 비교가 될테고, 옵션별 기능을 바로 확인할 수 있습니다.

 

> # star plot > stars(mean_by_Type[, 2:7], # dataframe or matrix + locations = NULL, # locations = NULL, the segment plots will be placed in a rectangular grid + nrow = 2, # number of rows at a square layout (w/locations = NULL) + ncol = 4, # number of columns at a square layout (w/locations = NULL) + scale = TRUE, # the columns are scaled independently (max in each column: 1, min: 0) + full = TRUE, # TRUE: occupy a full circle, FALSE : semi-circle + radius = TRUE, # the radii corresponding to each variable in the data will be drawn + frame.plot = TRUE, # if TRUE, the plot region is framed + main = "Star plot - means of multivariate by Car Type", # a main title for the plot + cex = 1, # size of label character (by default, cex = 1) + # labels = NULL # if NULL, no attempt is made to construct labels + lwd = 1, # line width (by default, lwd = 1) + key.loc = c(7.5, 1.5) # vector with x and y coordinates of the unit key + )

 

 

 

 

 

 

[ stars() 함수로 radar chart 그리기 ]

 

이전 포스팅에서 소개했던 레이더 차트 or 거미줄 그림(radar chart, or spider plot)도 stars() 함수로 그릴 수 있습니다. 별 그래프(star plot)이 개별 관측치마다 location을 부여하여 하나씩 다변량 그래프를 그린 것이라면, 레이더 차트(radar chart) or 거미줄 그림(spider plot)은 하나의 공통된 location을 중심점으로 하여 관측치들을 중첩하여 그린 다변량 그래프입니다.  locations = c(0, 0)으로 중심점을 한개로 통일하였고,  key.loc = c(0, 0) 으로 똑같이 지정해주어서 이 중심점 좌표를 기준으로 변수명을 labeling 할 수 있게 하였습니다.

 

radius = FALSE 로 바꾸어서 반지름 선은 표시하지 않게끔 하였습니다. 6개 차종(Type)의 그래프가 중첩이 되다보니 radius = TRUE 로 했더니 선이 겹쳐서 아예 안보이는게 있어서요.

 

관치치들의 다변량 변수 간에 존재하는 패턴에 대해서 관심이 있는 분석가라면 아무래도 그룹별로 선 색깔을 달리하여 그린 레이더 차트 (or 거미줄 그림)가 별 그래프(star chart)보다는 좀더 유용한 편입니다. col.lines = c(1:6) 옵션으로 6개 차종(Type)별 색깔을 구분하였습니다.

 

범례(legend)는 legend(x= , y= , ...) 함수로 추가를 하였습니다. x, y 좌표는 몇 번 숫자를 넣어보고 시행착오를 거치면서 적당한 좌표를 찾아나가야 합니다. "topright", "topleft" 이런 식으로 범례 좌표를 지정했더니 레이더 차트랑 자꾸 겹쳐서요. ^^;

 

> # radar chart (or spider chart) 
> stars(mean_by_Type[, 2:7], 
+       locations = c(0, 0), 
+       key.loc = c(0, 0), 
+       scale = TRUE, 
+       radius = FALSE, 
+       cex = 1, 
+       lty = 2, 
+       col.lines = c(1:6), 
+       lwd = 2, 
+       main = "radar chart - means of multivariate by Car Type" 
+       )
> 
> legend(x=1, y=1, legend = mean_by_Type$Type, lty = 2, col = c(1:6), lwd = 2)

 

 

 

 

 

위에 stars() 함수로 레이더 차트를 그리기는 했는데요, 이전 포스팅에서 fmsb Package의 radarchart() 함수로 그린 radar chart 보다는 가독성이 좀 떨어져보입니다.

 

여러개의 그룹을 레이더 차트 (radar chart)로 보려면 fmsb Package의 radarchart() 함수를 사용하고, 개별 그룹 단위로 분리해서 보려면 graphics Package의 stars() 함수로 별 그림 (star plot)을 그려서 보면 좋을 것 같습니다.

 

다음 번에는 평행 좌표 그림 (parallel coordinate plot)에 대해서 알아보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,

실전 업무에서는 다변량 데이터(multivariate data set)를 사용하는 경우가 다반사입니다. 그리고 분석업무 초반에 탐색적 분석을 수행할 때 시각화를 통해 변수들 간의 관계, 패턴을 탐색하는 분석 기법이 굉장히 유용합니다.

 

하지만 다변량 데이터 중에서도 특히 3개 이상의 변수를 가지는 다변량 데이터의 경우 그동안 소개해드렸던 히스토그램, 막대그림, 박스 그림, 산점도, 선그림/시계열 그림 등을 활용해서 2차원 평면에 나타낼 수 없는 한계가 있습니다. (물론, 색깔이라든지 모양을 데이터 그룹 별로 달리하면 3차원, 4차원의 정보를 시각화할 수 있기는 합니다만...)

 

변수 3개 이상의 다변량 데이터를 2차원 평면에 효과적으로 시각화할 수 있는 방법으로

 

(1) 레이더 차트 (radar chart) or 거미줄 그림(spider plot)

(2) 별 그림 (star graph) (레이더 차트와 유사, 중심점 다름)

(3) 평행 좌표 그림 (parallel coordinate plot)

(4) 3차원 산점도 (3 dimensional scatter plot)

(5) 체르노프 얼굴그림 (Chernoff faces)

(6) 산점도 행렬(scatter plot matrix)

(7) 모자이크 그림(mosaic plot)

 

등이 있습니다. 

산점도 행렬(http://rfriend.tistory.com/83, http://rfriend.tistory.com/82)과 모자이크 그림(http://rfriend.tistory.com/71)은 이전 포스팅을 참고하시기 바랍니다.

 

이번 포스팅에서는 (1) 레이더 차트 (radar chart)에 대해서 소개하겠습니다. 방사형의 레이더 차트가 마치 거미줄을 닮아서 거미줄 그림 (spider plot)이라고도 부릅니다.

 

별 그림 (star plot) 도 레이더 차트와 형태는 거의 유사한데요, 약간 현태가 다른 점이 있고 stars 라는 R 패키지가 별도로 있고 해서 다음번에 따로 설명을 드리겠습니다.

 

R 실습에 사용할 데이터는 MASS 패키지에 내장되어 있는 Cars93 데이터프레임입니다. 분석 대상 변수로는 차 유형(Type), 가격(Price), 고속도로연비(MPG.highway), 마력(Horsepower), 분당회전수RPM(RPM), 길이(Length), 무게(Weight) 등의 7개 변수입니다.

 

> 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 ...
> 

 

 

먼저 table() 함수를 사용하여 차 유형별 분할표를 만들어보았습니다.  6종류의 차 유형별로 10~20여대씩 분포하고 있음을 알 수 있습니다.

 

 

> # cross tabulation by car type

> table(Cars93$Type)

Compact   Large Midsize   Small  Sporty     Van 
     16      11      22      21      14       9
 

 

 

 

다음으로, 차 유형(Type)별로 가격(Price), 고속도로연비(MPG.highway), 마력(Housepower), 분당회전수RPM(RPM), 길이(Length), 무게(Weight) 등 6개 변수별 평균(mean)을 구해보겠습니다.

 

doBy package 의 summaryBy() 함수를 사용하면 연속형변수의 다변량 데이터에 일괄적으로 요약통계량을 편리하게 계산할 수 있습니다. Base package가 아니므로 install.packages("doBy")로 설치하시고, library(doBy)로 호출한 후에 summaryBy() 함수의 FUN = c(mean, min, max, sd, ...) 처럼 원하는 통계량 함수를 입력하면 됩니다. 이번에는 평균만 사용할 것이므로 아래 예에서는 FUN = c(mean) 만 입력하였습니다.

 

> # mean of multivariates by Car Type
> install.packages("doBy")
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/doBy_4.5-14.zip'
Content type 'application/zip' length 3419973 bytes (3.3 MB)
downloaded 3.3 MB

package ‘doBy’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\user\AppData\Local\Temp\RtmpGGgn4j\downloaded_packages
> library(doBy)
필요한 패키지를 로딩중입니다: survival
Warning message:
패키지 ‘doBy’는 R 버전 3.2.3에서 작성되었습니다 
> 
> mean_by_Type <- summaryBy(MPG.highway + RPM + Horsepower + Weight + Length + Price ~ Type, 
+           data=Cars93, 
+           FUN = c(mean))
> 
> 
> mean_by_Type

     Type MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean
1 Compact         29.87500 5362.500        131.0000    2918.125    182.1250   18.21250
2   Large         26.72727 4672.727        179.4545    3695.455    204.8182   24.30000
3 Midsize         26.72727 5336.364        173.0909    3400.000    192.5455   27.21818
4   Small         35.47619 5633.333         91.0000    2312.857    167.1905   10.16667
5  Sporty         28.78571 5392.857        160.1429    2899.643    175.2143   19.39286
6     Van         21.88889 4744.444        149.4444    3830.556    185.6667   19.10000

 

 

 

 

다음으로, 레이더 차트(radar chart)를 그리려면 fmsb Package 를 사용합니다. install.packages("fmsb")로 설치하고, library(fmsb)로 호출해보겠습니다.

 

> install.packages("fmsb")
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/fmsb_0.5.2.zip'
Content type 'application/zip' length 214358 bytes (209 KB)
downloaded 209 KB

package ‘fmsb’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\user\AppData\Local\Temp\RtmpGGgn4j\downloaded_packages
> library(fmsb)
Warning message:
패키지 ‘fmsb’는 R 버전 3.2.3에서 작성되었습니다

 

 

 

 

fmsb Package의 radarchart() 함수를 사용하기 위한 데이터 형태는

(1) 데이터 구조는 Dataframe

(2) 첫번째 행(1st row)에 최대값(max value)

(3) 두번째 행(2nd row)에 최소값(min value)

(4) 세번째 행부터는 원래의 관측값

이 오도록 데이터를 전처리해주어야 합니다.

 

 

[ fmsb Package의 radrchart() 함수 사용하기 위한 데이터 준비 ]

 

 

 

 

R 사용자정의함수로 첫번째 행에 최대값, 두번째 행에 최소값이 오도록 하여 Dataframe으로 묶는 명령어는 아래와 같습니다. 

 

사용자정의함수에 더하여 scale() 함수를 사용해서 6개의 변수를 표준화 하였습니다.

 

> # manipulating dataset for radar chart

> # data frame includes possible maximum values as row 1 
> # and possible minimum values as row 2

> df_radarchart <- function(df) { + df <- data.frame(df) + dfmax <- apply(df, 2, max) + dfmin <- apply(df, 2, min) + as.data.frame(rbind(dfmax, dfmin, df)) + } >

> # maximum value as row 1, minimum value as row 2 : user-defined function df_radarchart

> # standardization : scale()

> mean_by_Type_trans <- df_radarchart(scale(mean_by_Type[,c(2:7)]))

> 

> mean_by_Type_scale MPG.highway.mean RPM.mean Horsepower.mean Weight.mean Length.mean Price.mean 1 2.6145692 2.1399576 1.98554516 2.1439959 2.53293142 2.2793069 2 -2.4199059 -2.3321490 -2.73029381 -2.5089822 -2.31904165 -2.6344948 11 0.3636458 0.4429717 -0.50216519 -0.4509575 -0.18708691 -0.2596045 21 -0.3393415 -1.3321490 0.98554516 0.9078356 1.53293142 0.7806413 3 -0.3393415 0.3757101 0.79016106 0.3913731 0.60272622 1.2793069 4 1.6145692 1.1399576 -1.73029381 -1.5089822 -1.31904165 -1.6344948 5 0.1203738 0.5210954 0.39261423 -0.4832648 -0.71088103 -0.0579024 6 -1.4199059 -1.1475858 0.06413856 1.1439959 0.08135194 -0.1079465

 

 

 

 

드디어 radarchart() 함수를 사용해서 레이더 차트를 그려보겠습니다. 각 옵션에 대한 기능은 아래 R 명령어에 부가설명을 달아놓았습니다.

 

범례는 legend() 함수를 사용해서 왼쪽 상단에 추가하였습니다.

 

> # radar chart (or spider plot)
> radarchart(df = mean_by_Type_scale, # The data frame to be used to draw radarchart
+            seg = 6, # The number of segments for each axis 
+            pty = 16, # A vector to specify point symbol: Default 16 (closed circle)
+            pcol = 1:6, # A vector of color codes for plot data
+            plty = 1:6, # A vector of line types for plot data
+            plwd = 2, # A vector of line widths for plot data
+            title = c("radar chart by Car Types") # putting title at the top-middle
+            )
> 

> # adding legend

> legend("topleft", legend = mean_by_Type$Type, col = c(1:6), lty = c(1:6), lwd = 2)

 

 

 

 

 

 

선의 형태(plty)나 선의 색깔(pcol)을 프로그래밍 편하라고 1:6 이라고 했는데요, 원하는 선 모양이나 색깔을 순서대로 지정할 수 있습니다. 

 

다음번 포스팅에서는 별 그림(star graph)에 대해서 알아보겠습니다.

 

많은 도움 되어기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

 

728x90
반응형
Posted by Rfriend
,

수집한 데이터셋의 관측치들 간에 중복(duplication)이 있는 경우가 있습니다.  혹은 여러개의 흩어져 있는 데이터셋을 특정 기준 변수(key)를 사용해서 병합(merge)하는 전처리 작업을 하다 보면 가끔씩 의도하지 않게 중복데이터가 생기는 수가 있습니다.  서로 다른 행인데 각 변수별 관측값들이 동일한 경우 말이지요.  이럴 경우 저장 공간을 중복되는 만큼 더 잡아먹는고 데이터 처리 속도가 더 걸린다는 문제가 있으며, 더 심각하게는 이러한 데이터셋을 그대로 두고 통계 분석을 진행할 경우 분석 결과에 왜곡이 생길 수도 있으므로 중복 관측값 전처리가 필요합니다. (가령, 평균만 하더라도 중복이 있는 관측치가 여럿 있을 경우 분자의 관측치 합과 분모의 관측치 개수가 중복 제거후와는 서로 달라지겠지요?)

 

중복 데이터가 있을 경우에는 먼저 한개의 유일한 관측치(unique elements)만을 남겨놓고 나머지 중복 데이터들은 제거하는 전처리를 거쳐야 합니다. 이를 위해 R의

 

- {base} 패키지 : unique()

- {base} 패키지 : dataframe[!duplicated(var), ]

- {dplyr} 패키지 : distinct()

 

함수를 사용할 수 있습니다.

 

SAS 사용자라면 datastep에서 특정 변수를 기준으로 sorting을 한 후에 first.variable_name 또는 last.variable_name 명령문을 사용했던 것을 생각하시면 이해하기 쉬울 것입니다.  SAS와는 다르게 R은 sorting을 할 필요가 없습니다. (SAS는 merge 할 때도 먼저 sorting을 해줘야 하는 반면, R은 merge 할 때 sorting 해줄 필요 없습니다)

 

단, unique도 그렇고, merge도 그렇고 크기가 작은 데이터셋에는 별 무리가 없지만 대용량 데이터셋에 사용하기에는 처리 성능에 부담이 아주 많이 되는 함수입니다.  수십 기가가 넘는 대용량 사이즈의 데이터셋이라면 하둡 클러스터 내에서 Hive 등으로 중복 데이터 전처리하여 사용하시길 권합니다.

 

 

 

[ 중복없이 유일한 관측치만 남기기 (extracting unique elements) ]

 

 

 

 

R의 unique() 함수는 base package 함수에 내장되어 있으므로 별도의 패키지를 설치할 필요는 없습니다.  데이터 프레임(data frame), 배열(array), 행렬(matrix), 벡터(vector)에 모두 사용할 수 있는데요, 일반적으로 데이터 프레임을 분석에 많이 사용하므로 아래에는 데이터 프레임을 대상으로 unique() 함수 사용하는 방법을 소개하겠습니다.  

 

 

먼저 R 실습을 위해 관측치들 간에 중복이 포함되어 있는 변수 3개짜리 데이터 프레임을 만들어 보겠습니다.

 

> ##------------------------------------------
> ## extracting unique elements : unique()
> ##------------------------------------------
> 
> a1 <- rep(1:10, each = 2)
> a1
 [1]  1  1  2  2  3  3  4  4  5  5  6  6  7  7  8  8  9  9 10 10
> 
> a2 <- rep(c(1, 3, 5, 7, 9), each = 4)
> a2
 [1] 1 1 1 1 3 3 3 3 5 5 5 5 7 7 7 7 9 9 9 9
> 
> a3 <- c(1, 1, 1, 1, 3, 3, 3, 3, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12)
> a3
 [1]  1  1  1  1  3  3  3  3  5  5  6  6  7  7  8  8  9 10 11 12
> 
> a1a2a3 <- data.frame(cbind(a1, a2, a3))
> a1a2a3
   a1 a2 a3
1   1  1  1
2   1  1  1
3   2  1  1
4   2  1  1
5   3  3  3
6   3  3  3
7   4  3  3
8   4  3  3
9   5  5  5
10  5  5  5
11  6  5  6
12  6  5  6
13  7  7  7
14  7  7  7
15  8  7  8
16  8  7  8
17  9  9  9
18  9  9 10
19 10  9 11
20 10  9 12
> 
> str(a1a2a3)
'data.frame':	20 obs. of  3 variables:
 $ a1: num  1 1 2 2 3 3 4 4 5 5 ...
 $ a2: num  1 1 1 1 3 3 3 3 5 5 ...
 $ a3: num  1 1 1 1 3 3 3 3 5 5 ...

 

 

 

 

[예제 1]

변수가 3개 있는 데이터 프레임인데요, a1과 a2의 두 개 변수를 기준으로 중복여부를 체크한 후에, 중복이 있을 경우에는 1개만 선택하고 나머지 중복된 관측치는 제거하는 방법에 대한 예시는 아래와 같습니다.

 

>

> # extracting unique elements by 2 variables > aqa2a3_uniq_var2 <- unique(a1a2a3[, c("a1", "a2")]) > aqa2a3_uniq_var2 a1 a2 1 1 1 3 2 1 5 3 3 7 4 3 9 5 5 11 6 5 13 7 7 15 8 7 17 9 9 19 10 9

 

 

 

 

위의 예제에서 "a1"변수와 "a2" 변수를 기준으로 중복 관측치를 제거하고 유일한 관측치만 남기는 처리 개념을 풀어서 설명하면 아래와 같습니다.  참고로, a1a2a3[, c("a1", "a2")] 은 a1a2a3 데이터 프레임에서 변수 "a1"과 "a2"만 select 하라는 뜻입니다.

 

 

 

 


 

 

[예제 2]

다음으로, "a1", "a2", "a3" 세 개의 변수를 기준으로 중복된 관측치가 있다면 유일한 관측치만 남기고 나머지 중복 관측치는 제거하는 예를 들어보겠습니다.

 

> 

> # extracting unique elements by 3 variables > aqa2a3_uniq_var3 <- unique(a1a2a3[, c("a1", "a2", "a3")]) > aqa2a3_uniq_var3 a1 a2 a3 1 1 1 1 3 2 1 1 5 3 3 3 7 4 3 3 9 5 5 5 11 6 5 6 13 7 7 7 15 8 7 8 17 9 9 9 18 9 9 10 19 10 9 11 20 10 9 12

 

 

 

 

위 R 함수의 처리 과정을 풀어보면 아래와 같습니다.

 

 

 

 

"a1", "a2"의 두 개 변수만을 기준으로 했을 때 대비, "a1", "a2", "a3"의 세 개변수를 기준으로 unique() 함수를 적용했을 때 18번째와 20번째 행이 중복없는 유일한 행으로서 추가로 살아남았음을 알 수 있습니다.

 

 

 


 

[예제 3]

unique(x, fromLast = TRUE) 옵션을 적용하면 중복된 관측치들 중에서 남길 관측치(행, row)를 선택할 때 가장 밑에 있는 관측치(from Last observation)를 기준으로 선택합니다. default 는 fromLast = FALSE 입니다.

 

> 
> # identical element will be kept from the last : fromLast = TRUE 
> # defaulu : fromLast = FALSE
> aqa2a3_uniq_var3_fromLast <- unique(a1a2a3[, c("a1", "a2", "a3")], fromLast = TRUE) 
> aqa2a3_uniq_var3_fromLast  # differnt order
   a1 a2 a3
2   1  1  1
4   2  1  1
6   3  3  3
8   4  3  3
10  5  5  5
12  6  5  6
14  7  7  7
16  8  7  8
17  9  9  9
18  9  9 10
19 10  9 11
20 10  9 12

 

 

 

 

 

[예제2]의 fromLast = FALSE (default 이므로 특별히 명기할 필요는 없음) 일 때와 [예제3]의 fromLast = TRUE 일 때의 차이가 무엇인지 잘 이해가 안 갈 수도 있는데요, 아래 [예제2]와 [예제3]의 데이터프레임들의 row names 의 번호가 서로 다름을 알 수 있습니다. 

 

1번째 행과 2번째 행이 중복된 것의 처리에 대해서만 설명드리자면, [예제2]의 fromLast = FALSE의 경우1번 행(first row)을 가져왔고, [예제3]의 fromLast = TRUE 의 경우 2버 행(second row)를 유일한 행으로 가져왔습니다.

 

 

 

 

[예제2]와 [예제3]의 결과는 동일합니다. 그런데 왜 굳이 이런것이 필요하지 싶을 것입니다. ^^?

위의 예제는 설명의 편의를 위해서 변수 3개 짜리 중복 데이터셋을 초간단으로 만들어본 것인데요, 실전에서 사용하는 데이터셋은 변수가 수십, 수백개, 관측치(행의 개수)도 수천, 수만, 수백만개인 경우가 다반사입니다.  이때 특정 변수를 기준으로 중복인 경우 유일한 관측치를 선별하고, 나머지 변수들은 그대로 사용해야 하는 경우 중복된 관측치의 first observation을 살려둘지 아니면 last obsetvation을 살려둘지에 따라서 중복 제거 기준 변수 이외의 타 변수들의 관측치 값들이 다른 경우에는 고민 좀 해야겠지요?  이럴 경우에 fromLast = FALSE/TRUE 옵션이 필요합니다.  (이럴 경우 SAS처럼 미리 특정 변수를 기준으로 정렬해놔야 겠군요)

 

 


 

 

{base} package에 내장되어 있는 duplicated() 함수를 사용해서 중복값을 제거하고 유일한 값만 선별할 수도 있습니다.  duplicated() 함수를 사용하면 아래 예시처럼 중복되는 행에 대해서 TRUE, FALSE boolean 값을 반환합니다.  이 논리형 값을 가지고 dataframe에서 indexing을 해오는 방식으로 중복값을 처리하고 유일한 값만 남겨놓을 수 있습니다.

 

 

> ##-----------------------
> ## duplicated() function
> ##-----------------------
> 
> # original dataset
> a1a2a3
   a1 a2 a3
1   1  1  1
2   1  1  1
3   2  1  1
4   2  1  1
5   3  3  3
6   3  3  3
7   4  3  3
8   4  3  3
9   5  5  5
10  5  5  5
11  6  5  6
12  6  5  6
13  7  7  7
14  7  7  7
15  8  7  8
16  8  7  8
17  9  9  9
18  9  9 10
19 10  9 11
20 10  9 12
> 
> 
> # returning TRUE for duplicated value
> duplicated(a1a2a3$a1) 
 [1] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE
[12]  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
> 
> 
> # indexing unduplicated rows using dataframe[!duplicated(dataframe$var1), ]
> a1a2a3_not_duplicated_var1 <- a1a2a3[!duplicated(a1a2a3$a1),]
> a1a2a3_not_duplicated_var1
   a1 a2 a3
1   1  1  1
3   2  1  1
5   3  3  3
7   4  3  3
9   5  5  5
11  6  5  6
13  7  7  7
15  8  7  8
17  9  9  9
19 10  9 11
> 
> # another exmaple
> a1a2a3[!duplicated(a1a2a3$a2),]
   a1 a2 a3
1   1  1  1
5   3  3  3
9   5  5  5
13  7  7  7
17  9  9  9

 

 

 


 

dplyr 패키지의 distinct() 함수도 중복이 없는 유일한 값을 반환합니다.  dplyr 패키지의 distinct() 가 깔끔하기도 하고, dplyr 패키지 내의 여러 데이터 전처리 함수를 함께 이용할 수 있어서 알아두시면 좋겠습니다.

 

 

 



10억 개의 정수 값에 대해 base 패키지의 unique(), duplicated() 함수와 dplyr패키지의 distinct() 함수를 적용해서 수행 시간 (elapsed time)을 비교해보니 dplyr의 distinct() 함수가 근소하게 빠르기는 합니다만, 차이가 그리 크지는 않네요. 


> a1 <- sample(1:99, 1000000000, replace=TRUE)

> system.time(unique(a1))

   user  system elapsed 

 13.676   7.327  22.999 

> system.time(!duplicated(a1))

   user  system elapsed 

 13.558   5.049  20.198 

> library(dplyr)

> system.time(dplyr::distinct(data.frame(a1)))

   user  system elapsed 

 17.602   1.645  19.267

 



많은 도움이 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서 선형독립 또는 1차 독립 (linearly independent), 선형종속 또는 1차 종속 (linearly dependent) 에 대해서 알아보았습니다.

 

이번 포스팅에서는 기저 (basis)와 차원 (dimension)에 대해서 알아보겠습니다.  선형독립의 정의를 알지못하면 기저를 이해할 수 없으며, 선형독립과 기저의 개념이 헷갈릴 수도 있습니다. 따라서 혹시 선형독립(linearly independent)에 대해서 잘 모르고 있거나 가물가물하다면 이전 선형독립 포스팅을 다시 한번 살펴보시길 바랍니다.

(☞ 선형독립(linearly independent), 선형종속(linearly dependent) 바로가기)

 

 

기저(basis, 基底)란 어떤 벡터공간 V의 벡터들이 선형독립이면서 벡터공간 V 전체를 생성할 수 있다면 이 벡터들의 집합을 말합니다.  다른 말로 표현하자면, 기저는 "R^m의 임의의 원소를 표현하기 위해 필요한 최소한의 벡터로 이루어진 집합"입니다.

 

 

[ 기저의 정의 (definition of basis) ]

 

 

 

 

 

위의 정의에 따라, 기저인 예와 기저가 아닌 예를 아래에 들어보겠습니다.  실제 예를 보시면 이해가 좀더 쉬울 것입니다.

 

  • 기저인 예 (example of a basis)

     : 2 차원 (2 dimension)

 

 

 

 

  : 3차원 (3 dimension)

 

 

 

 

  • 기저가 아닌 예 (not a basis)

   : 2차원 (2 dimension)

     --> 2차원의 임의의 원소를 표현하는데 필요한 최소한의 벡터는 2개인데 반해, 아래의 예는 4개의 벡터로 구성되어 있으므로 군더더기 벡터가 2개나 더 있는 셈입니다.  그러므로 "m차원의 임의의 원소를 표현하기 위해 필요한 최소의 벡터로 이루어진 집합"인 기저(basis)가 아닌 것입니다.

 

 

 

 

 

 

   : 3차원 (3 dimension)

  --> 3차원의 임의의 원소를 표현하기 위해서 필요한 최소한의 벡터는 3개인데요, 아래의 예는 3개의 벡터로 되어 있으므로 위의 2차원 예와는 조금 다른 경우입니다. 아래의 예는 3개 벡터의 세번째 원소가 모두 '0'으로 되어 있어서 3차원의 세번째 차원을 표현할 방법이 없으므로 기저가 아닌 경우입니다. 즉, 위의 2차원 예에서는 해가 2개 이상이어서 기저가 아닌 경우이며, 아래의 3차원 예의 경우는 해가 아예 하나도 존재하지 않기 때문에 기저가 아닌 경우입니다.  물론, 위의 2차원 예에서처럼 3차원(R^3)인데 원소가 '0'이 아닌 벡터가 3개를 초과한다면 군더더기 벡터가 존재하게 되어 기저가 아니게 되겠지요.

 

 

 

 

 

 

아래의 R^3의 두 벡터 (1, 0, 0), (0, 1, 0) 역시 기저가 아닙니다.  3차원의 임의의 원소를 표현하기 위한 최소한의 벡터 개수는 3개인데 반해 2개 밖에 없어서 1개가 모자라기 때문입니다. 세번째 차원의 원소 (0, 0, 1)을 표현할 방법이 없으므로 기저의 정의를 만족시키지 못합니다.

  

 

 

 

바로 위의 예가 기저가 아니라고 했는데요, 그러면 R^3의 두 벡터 (1, 0, 0), (0, 1, 0)은 선형독립일까요?  선형독립이지요.  기저는 아닌데 선형독립인 예입니다.

 

 

 

 

 

아래에 선형독립과 기저의 정의를 복습하는 의미에서 다시 한번 정리하여 보았습니다.  선형독립(linearly independent)은 제로벡터(zero vector) (0, 0, ..., 0)에 한정된 개념인데 반해, 기저(basis)s는 R^m (m dimension)의 모든 벡터를 대상으로 하는 개념입니다.

 

 

[ 선형독립 vs. 기저  정의 (definition of linearly independent and basis) ]

 

 

 

 

벡터공간, 부분공간, 차원(dimension)에 대해서는 나중에 추가로 덧붙여서 설명하겠습니다.

 

이번 포스팅이 도움이 되었다면 아래의 공감 ♡ 꾸욱~ 눌러주세요. ^^

 

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 선형독립 혹은 1차 독립(linearly independent)과 선형종속 혹은 1차 종속(linearly dependent)에 대해서 알아보겠습니다. 

 

선형독립 혹은 1차 독립 (linearly independent) 개념은 나중에 이어서 소개할 기저(base)와 차원(dimension), 행렬의 계수(rank)와 선형연립방정식의 존재성(existence), 유일성(uniqueness), 가우스 소거법(Gauss Jordan Elimination)과의 관계 등에 줄줄이 연관이 되어있으므로 정확히 이해하는 것이 필요합니다.  선형독립에 대한 이해가 집의 주춧돌인 셈입니다.  집을 지을 때 주춧돌이 부실하면 나중에 집이 무너지는 수가 있습니다.  차원을 정의하고 선형연립방정식 푸는데 가장 밑에 받쳐주는 개념이 선형독립(linearly independent) 개념이므로 배워야 합니다.  

 

 

[ 선형독립과 선형대수의 관계 ]

(relation between linearly independent/dependent and linear algebra)

 

 

 

 

 

 

다변량통계분석 책을 보면 선형독립(linearly independent) 개념이 텍스트로만 해서 3~5줄로 설명이 되어있습니다. 그래서 선형대수를 따로 배우지 않은 분이라면 처음에는 이게 뭔소리인가 하고 이해하기 매우 힘들것 같습니다. 어디에 쓰는지, 왜 배우는지도 잘 모를것 같기도 하구요. 하지만 처음에는 이해가 잘 안되더라도 중요한 개념이므로 2번, 3번 계속 읽어보시고 다른 자료도 찾아서 공부해두시면 좋겠습니다.  (공과 대학원 준비하는 분이라면 행렬의 계수(rank)를 비롯한 선형대수 문제는 구술시험 반드시 나온다에 500원 걸겠습니다. 그만큼 중요하다는 얘기입니다.)  선형독립(linearly independent) 정의가 다음번에 포스팅할 기저(base)와 좀 헷갈릴 수 가 있으므로 정확히 이해하시기 바랍니다.

 

텍스트로 선형독립(linearly independent)을 정의하면 아래와 같습니다. 좀 어렵지요? ^^;

 

 

 

 

위의 텍스트 정의와 똑같은데요, 이걸 좀더 쉽게 풀어서 벡터를 직접 입력해서 다시 한번 설명하자면 아래와 같습니다. 

 

 

 

 

선형독립의 개념을 좀더 쉽게 이해할 수 있도록 아래에 기하하적인 해석을 덧붙여서 선형독립인 예와 선형종속인 예를 몇 개 들어보겠습니다. 

 

 

(1) R^2 의 두 벡터 (1, 0), (0, 1)은 선형독립임.

 

 

 

 

(2) R^3 의 두 벡터 (1, 0, 0), (0, 1, 0) 은 선형독립임.

 

 

 

 

 

(3) R^3의 세 벡터 (1, 0, 0), (0, 1, 0), (0, 0, 1)은 선형독립임.

 

 

 

 

아래는 선형종속(linearly dependent) 예입니다.

 

(4) R^3 의 세 벡터 (1, 0, 0), (0, 1, 0), (2, 1, 0)은 선형종속임.

 

 

 

 

제로벡터 (0, 0, 0) 에 대한 R^3 의 세 벡터 (1, 0, 0), (0, 1, 0), (2, 1, 0)의 해가 (c1=0, c2=0, c3=0) 말고도 (c1=2, c2=1, c3=-1), (c1=-2, c2=-1, c3=1) 등도 추가로 더 있으므로 선형종속 혹은 1차 종속 (linearly dependent)가 됩니다. 

 

해 (c1=2, c2=1, c3=-1) 을 좌표로 그려보면 아래와 같습니다. 돌고, 돌고, 돌아서 제로벡터 (0, 0, 0)으로 돌아왔음을 알 수 있습니다.

 

 

 

 

또 다른 해 (c1=2, c2=-1, c3=1) 을 좌표로 그려보면 아래와 같습니다.  이 해 역시 돌고, 돌고, 돌아서 제로벡터 (0, 0, 0)으로 돌아왔음을 알 수 있습니다.

 

 

 

 

 

 

(5) R^3 의 네 벡터 (1, 0, 0), (0, 1, 0), (0, 0, 1), (2, 2, 2)는 선형종속임.

 

 

 

위의 R^3의 네 벡터에 대한 해 (c1=2, c2=2, c3=2, ㅊ4=-1) 을 좌표로 그려보면 아래와 같습니다.  이 해 역시 돌고, 돌고, 돌아서 제로벡터 (0, 0, 0)으로 돌아왔음을 알 수 있습니다.  좌표의 이동 경로가 좀 헷갈릴 수도 있는데요, 색깔을 참조해서 유심히 살펴보시기 바랍니다.

 

 

 

수식 입력이랑 그래프 그리다보니 시간 엄청 걸리네요. 헉, 헉... ^^;

 

다음 포스팅에서는 기저(base)에 대해서 소개하고, 선형독립과 비교를 해보겠습니다.

 

이번 포스팅이 도움이 되었다면 아래의 공감 ♡ 꾸욱~ 눌러주세요. ^^

 

 

728x90
반응형
Posted by Rfriend
,

이전 포스팅에서 벡터는 "힘(magnitude)"과 "방향(direction)"을 가진 양이라고 정의를 했습니다. 이번 포스팅에서는 벡터를 가지고 점(dot), 축(axis), 직선(line), 평면(space), 3차원 공간(3 dimensional space), n차원 공간(n dimensional space)를 나타내는 방법을 알아보겠습니다.

 

앞으로 선형독립, 기저, 랭크(RANK), 고유값(Eigen value), 고유벡터(Eigen vector) 등에 대해서 소개할 텐데요, 이번 시간은 잠깐 쉬어가면서 기본 개념을 잡아보는 시간을 생각하면 좋겠습니다. 

 

3차원까지는 이해가 가는데 n차원이라고 하면 이게 무슨 소리인지, 벡터로는 어떻게 표현하는지, 다차원분석을 한다고 하는데 n차원으로 생각한다는 것이 무엇인지 조금이나마 감을 잡는데 이번 포스팅이 도움이 되면 좋겠습니다. 

 

단위벡터(unit vector)를 사용해서, 상수 c와 단위벡터의 곱의 집합으로 표현합니다.  벡터를 사용해서 파동 곡선 함수라든지 타원형 함수 등도 표현할 수 있습니다는 정도만 알아두시구요, 상세 내용은 sine, cosine 등의 삼각함수도 나오고 해서 좀 어려울듯 하니 생략하겠습니다.

 

  • 벡터로 점 표현하기 (representing a dot by a vector)

 점(3, 0)과 점(0, 3)을 벡터로 나타내면 아래와 같습니다.

 

 

 

 

 

  • 벡터로 축 표현하기 (representing an axis by a vector)

 x1축과 x2축을 각 각 벡터로 나타내면 아래와 같습니다.

 

 

 

 

 

  • 벡터로 직선 표현하기 (representing a line by vector)

x1 = 4인 직선을 벡터로 나타내보겠습니다.

 

 

 

 

x2 = 5인 직선을 벡터로 나타내면 아래와 같습니다.

 

 

  • 벡터로 2차원 평면 표현하기 (representing 2 dimensional space by vector)

x1 축과 x2 축에 수평인 벡터로 이루어진 2차원 평면입니다.  

 

 

 

 

단위벡터가 아닌 벡터를 사용해도 2차원 평면을 표현할 수 있습니다.  중/고등학교 때 좌표 개념을 배울 때는 단위벡터를 가정합니다.  그렇다보니 아래처럼 단위벡터가 아닌 벡터를 사용한 2차원 평면 좌표에 대해서는 굉장히 낯설게 느껴질 것 같습니다.  그런데 나중에 벡터, 선형사상을 가지고 확대나 회전,  평형이동 등에 활용할 때 아래의 예시 개념을 활용합니다.  게임 개발하거나 CAD 설계 하는 분이라면 일상적으로 사용하는 개념입니다.

 

 

  • 벡터로 3차원 공간 표현하기 (representing 3 dimensional space by vector)

 

 

 

 

 

 

  • 벡터로 n차원 공간 표현하기 (representing n dimensional space by vector)

4차원 이상의  n차원 공간을 상상하기가 쉽지 않을텐데요, 이를 벡터의 집합으로 표현하면 아래와 같습니다. 2차원, 3차원 공간을 벡터로 표현했던 위의 집합을 보면 n차원의 벡터 표현도 이해가 될 것입니다.

 

 

다음번 포스팅에서는 차원(dimension)을 정의하는데 꼭 필요한 개념인 선형독립(linear independence), 선형종속(linear dependence)에 대해서 알아보겠습니다.

 

이번 포스팅이 도움이 되었다면 아래의 공감 ♡ 꾸욱~ 눌러주세요. ^^

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 그래프에 추가적인 정보를 입력하는 낮은 수준의 그래프 함수(low level graphic functions) 중에서

(1) 제목, XY축 Label 추가하는 title()

(2) XY축의 형태를 변환하는 axis(side, ...)

(3) 직선 연결, 추가 : lines(x, y), abline(a, b), abline(h=y), abline(v=x)

(4) 점 추가 : points(x, y)

(5) 문자 추가 : text(x, y, labels, ...), mtext()

(6) 범례 추가 : legend(x, y, legend, ...)

에 대해서 알아보았습니다.

 


이번 포스팅에서는 낮은 수준의 그래프 함수 네번째로 (7) 다각형 추가 : polygon(x, y, ...) 에 대해서 소개하겠습니다.



[ 낮은 수준의 그래프 함수 (Low level graphic function) ]

 

 

 

다각형을 그리는 polygon() 함수의 일반적인 사용법은 다음과 같습니다.

 

polygon(x, y = NULL, density = NULL, angle = 45,
        border = NULL, col = NA, lty = par("lty"),
        ..., fillOddEven = FALSE) 

 

 

 구분

기능 설명 

 x, y

  다각형의 좌표의 벡터

 density

  다각형 안을 채우는 음영 선의 밀도 (default 는 NULL)

 angle

  음영있는 선의 각도 (수평선을 기준으로 해서 반시계방향)

 border

  다각형 테두리의 색깔

 col

  다각형을 채우는 색깔 (default 는 NA)

 lty

  par() 에서 사용하는 선 유형

  : 0=blank, 1=solid (default), 2=dashed, 3=dotted, 4=dotdash,

    5=longdash, 6=twodash

 ...

  추가로 그래프 모수 사용 가능

 fillOddEven

  다각형의 음영을 논리적으로 조절하는 모드 (default 는 FALSE)

 

 

 

두 개의 삼각형을 테두리의 색깔(border)과 선 유형(lty), 다각형을 채우는 색깔(col), 다각형을 채우는 선의 밀도(density)와 각도(angle), 색깔(col)을 달리해서 그려보겠습니다.

 

x와 y의 좌표값의 중간에 "NA" value가 들어갔음에 주의해서 보시기 바랍니다.

> ##-------------------------------------
> ## polygon : polygon(x, y, ...)
> ##-------------------------------------
> 
> # Multiple polygons from NA values
> 
> plot(c(1, 6), c(-3.5, 3.5), type = "n")
> x <- c(1, 2, 3, NA, 4, 4, 6)
> y <- c(1, -3, 2, NA, -3, 3, -3)
> polygon(x, y,
+         col = c("yellow", "blue"),
+         border = c("black", "red"),
+         lwd = 2, 
+         lty = c("dotted", "solid"))
> title("Multiple polygons from NA values")

 

 

 

 

 

 

아래의 다각형은 위와 R script가 거의 동일한데요, 단 한가지 차이점이라면 x, y의 좌표값에 "NA" value가 없다는 점입니다.  "NA" value가 없다보니 R은 중간에 다각형을 분리하지를 못하고, 그냥 하나의 색깔, 선 유형, 다각형 채우는 색을 계속 사용하고 있습니다.

 

> ## what if no NA value
> plot(c(1, 6), c(-3.5, 3.5), type = "n")
> x <- c(1, 2, 3, 4, 4, 6)
> y <- c(1, -3, 2, -3, 3, -3)
> polygon(x, y,
+         col = c("yellow", "blue"),
+         border = c("black", "red"),
+         lwd = 2, 
+         lty = c("dotted", "solid"))
> title("Multiple polygons without NA value")

 

 

 

 

 

 

이번에는 다각형 안의 음영을 선으로 채우는 방법을 소개하겠습니다. density 로 선의 밀도(숫자가 클 수록 촘촘해짐)를 지정하고, angle 로 선의 각도(수평선을 기준으로 반시계방향)를 지정하면 됩니다.

 

> # Line-shaded polygons
> plot(c(1, 6), c(-3.5, 3.5), type = "n")
> x <- c(1, 2, 3, NA, 4, 4, 6)
> y <- c(1, -3, 2, NA, -3, 3, -3)
> polygon(x, y,
+         col = c("yellow", "blue"),
+         border = c("black", "red"),
+         lwd = 2, 
+         lty = c("dotted", "solid"), 
+         density = c(10, 20), 
+         angle = c(45, -45))
> title("Multiple polygons with Line-shaded density")

 

 

 

 

 

 

아래 다각형은 x, y 좌표값이 위에서 든 예시와는 좀 다르지요?  두개의 좌표값들 간의 거리에 색깔을 채워넣은 형태의 그래프인데요, polygon() 함수로 이런 그래프도 그릴 수 있다는 예시로 보면 좋겠다 싶어서 www.math.cula.edu 사이트에서 참조하였습니다.

 

> ## Color-shaded polygon
> # exmaple source : http://www.math.ucla.edu/~anderson/rw1001/library/base/html/polygon.html
> n <- 100
> xx <- c(0:n, n:0)
> yy <- c(c(0,cumsum(rnorm(n))), rev(c(0,cumsum(rnorm(n)))))
> plot   (xx, yy, type="n", xlab="Time", ylab="Distance")
> polygon(xx, yy, col="gray", border = "red")
> title("Distance Between Brownian Motions")

 

 

 

 * R script source : http://www.math.ucla.edu/~anderson/rw1001/library/base/html/polygon.html

 

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.^^

 

728x90
반응형
Posted by Rfriend
,