이번 포스팅에서는 방향성 있는 가중 네트워크 시각화 (directed and weighted network visualization)에 대해서 소개하겠습니다.

 

 - R igraph package 를 사용해서

 - 심리학 저널의 상호인용 빈도 데이터

  (* source : Lattin, Carroll and Green, 2003)

 

를 대상으로 논문 상호인용 빈도 네트워크를 그려보겠습니다.

 

먼저, 방향성 있는 가중 네트워크에 대해서 한번 더 소개하자면, 아래와 같이 화살표로 방향이 있고, 연결선에 가중치(weight)가 있는 네트워크를 말합니다.

 

 

[ 방향성 있는 가중 네트워크 (Directed and Weighted Network) ]

 

 

 

심리학 저널의 상호인용 빈도를 행렬 형태로 나타내보면 아래와 같습니다.

행렬의 요소 (i, j) 빈도는 저널 i의 논문이 저널 j에 인용된 회수입니다.

 - 예) (1, 2) = 32 : AJP 논문 32편이 JASP 논문에 인용됨

        (2, 1) = 8 : JASP 논문 8편이 AJP 논문에 인용됨

 

[ 심리학 저널 간 상호 인용 빈도 ]

 

[1] AJP

 [2] JASP

[3] JAP 

[4] JCPP 

[5] JCP 

[6] JEDP 

[7] JEXP 

[8] PKA 

[1] AJP

119

32 

35 

125 

[2] JASP

510 

116 

19 

[3] JAP

16 

84 

11 

[4] JCPP

21 

11 

533 

70 

[5] JCP

73 

225 

13 

[6] JEDP

52 

[7] JEXP

85 

119 

16 

126 

12 

27 

586 

13 

[8] PKA

10 

15 

58 

 

 

library()함수로 R의 igraph package를 로딩해서 시각화를 해보겠습니다.

igraph package는 데이터 포맷이 ID1, ID2, Weight or Frequency 의 행렬(matrix) 입니다.

아래에 위의 표를 행렬로 입력해서 불러들였는데요, 빈도(3번째 열)에 +1 을 해주었습니다.

(0이면 에러가 나는지 안되네요)

 

R script는 'R을 활용한 사회네트워크분석 입문'의 예시를 거의 대부분 사용하였으며,

그래프의 설정 parameter를 이리 저리 숫자를 조절해보면서 살짝 바꿔보았습니다.

 

> ############################################# > ## Network Analysis - igraph package > ############################################# > library(igraph) > > psych_edgelist <- matrix( + c(0, 1, 32, 0, 2, 2, 0, 3, 35, 0, 4, 6, 0, 5, 4, + 0, 6, 125, 0, 7, 2, 1, 0, 8, 1, 2, 8, 1, 3, 8, + 1, 4, 116, 1, 5, 9, 1, 6, 19, 1, 7, 5, 2, 0, 4, + 2, 1, 16, 2, 3, 0, 2, 4, 11, 2, 5, 7, 2, 6, 6, + 2, 7, 5, 3, 0, 21, 3, 1, 11, 3, 2, 1, 3, 4, 1, + 3, 5, 0, 3, 6, 70, 3, 7, 0, 4, 0, 0, 4, 1, 73, + 4, 2, 7, 4, 3, 0, 4, 5, 3, 4, 6, 0, 4, 7, 13, + 5, 0, 1, 5, 1, 9, 5, 2, 8, 5, 3, 1, 5, 4, 7, + 5, 6, 0, 5, 7, 2, 6, 0, 85, 6, 1, 119, 6, 2, 16, + 6, 3, 126, 6, 4, 12, 6, 5, 27, 6, 7, 13, 7, 0, 2, + 7, 1, 4, 7, 2, 10, 7, 3, 1, 7, 4, 7, 7, 5, 5, 7,6, 15), + byrow = T, ncol = 3) + 1 > > psych_edgelist [,1] [,2] [,3] [1,] 1 2 33 [2,] 1 3 3 [3,] 1 4 36 [4,] 1 5 7 [5,] 1 6 5 [6,] 1 7 126 [7,] 1 8 3 [8,] 2 1 9 [9,] 2 3 9 [10,] 2 4 9 [11,] 2 5 117 [12,] 2 6 10 [13,] 2 7 20 [14,] 2 8 6 [15,] 3 1 5 [16,] 3 2 17 [17,] 3 4 1 [18,] 3 5 12 [19,] 3 6 8 [20,] 3 7 7 [21,] 3 8 6 [22,] 4 1 22 [23,] 4 2 12 [24,] 4 3 2 [25,] 4 5 2 [26,] 4 6 1 [27,] 4 7 71 [28,] 4 8 1 [29,] 5 1 1 [30,] 5 2 74 [31,] 5 3 8 [32,] 5 4 1 [33,] 5 6 4 [34,] 5 7 1 [35,] 5 8 14 [36,] 6 1 2 [37,] 6 2 10 [38,] 6 3 9 [39,] 6 4 2 [40,] 6 5 8 [41,] 6 7 1 [42,] 6 8 3 [43,] 7 1 86 [44,] 7 2 120 [45,] 7 3 17 [46,] 7 4 127 [47,] 7 5 13 [48,] 7 6 28 [49,] 7 8 14 [50,] 8 1 3 [51,] 8 2 5 [52,] 8 3 11 [53,] 8 4 2 [54,] 8 5 8 [55,] 8 6 6 [56,] 8 7 16 > > psych.w <- graph.edgelist(psych_edgelist[, 1:2]) > psych.w IGRAPH D--- 8 56 -- + edges: [1] 1->2 1->3 1->4 1->5 1->6 1->7 1->8 2->1 2->3 2->4 2->5 2->6 [13] 2->7 2->8 3->1 3->2 3->4 3->5 3->6 3->7 3->8 4->1 4->2 4->3 [25] 4->5 4->6 4->7 4->8 5->1 5->2 5->3 5->4 5->6 5->7 5->8 6->1 [37] 6->2 6->3 6->4 6->5 6->7 6->8 7->1 7->2 7->3 7->4 7->5 7->6 [49] 7->8 8->1 8->2 8->3 8->4 8->5 8->6 8->7 > > E(psych.w)$weight <- psych_edgelist[,3] > psych.w IGRAPH D-W- 8 56 -- + attr: weight (e/n) + edges: [1] 1->2 1->3 1->4 1->5 1->6 1->7 1->8 2->1 2->3 2->4 2->5 2->6 [13] 2->7 2->8 3->1 3->2 3->4 3->5 3->6 3->7 3->8 4->1 4->2 4->3 [25] 4->5 4->6 4->7 4->8 5->1 5->2 5->3 5->4 5->6 5->7 5->8 6->1 [37] 6->2 6->3 6->4 6->5 6->7 6->8 7->1 7->2 7->3 7->4 7->5 7->6 [49] 7->8 8->1 8->2 8->3 8->4 8->5 8->6 8->7 > > psych.diag <- c(119, 510, 84, 533, 225, 52, 586, 58) > > psych.name <- c("AJP", "JASP", "JAP", "JCPP", "JCP", "JEDP", "JEXP", "PKA") > > plot(psych.w, + layout = layout.circle, + vertex.size = 2, + vertex.shape = "none", + vertex.size = psych.diag, + vertex.label = psych.name, + vertex.label.font = 2, + vertex.label.cex = sqrt(psych.diag)/10, + edge.width=2 + E(psych.w)$weight/10, + edge.arrow.width = E(psych.w)$weight/100 + )

 

 

 

 

 

igraph plot 의 parameter 기능은 아래와 같습니다. 

parameter를 바꿔가면서 최적의 이쁜 그래프를 찾아가 보시기 바랍니다.

 

 

1) Layout : 점의 좌표를 정하는 알고리즘

 

 - layout.circle : 원 배치 (위의 예시)

 

 - layout.random : 무작위 배치

 

 

- layout.fruchterman.reingold : Fruchterman Reingold 배치 알고리즘

 

 

 - layout.kamada.kawai : kamada Kawai 배치 알고리즘

 

 

 

 - layout.lgl : 대규모 네트워크를 위한 배치 알고리즘

 

 

 

2) Edge : 선 관련 파라미터

 

- edge.color : 선 색 지정 (default = "darkgrey")

- edge.width : 선 폭

 

- edge.arrow.size : 화살 크기

- edge.arrow.width : 화살 폭

- edge.arrow.mode : 화살 머리 유형 (0 : 없음,  1 : 역방향,  2 : 순방향,   3 : 양방향)

                            (무방향 네트워크의 경우 default = 0)

 

- edge.lty : 선 유형 ("solid", "dashed", "dotted", "dotdash", "longdash", "twodash")

- edge.label : 선 레이블

- edge.label.family : 선 레이블 종류 ("serif", "sans", "mono" 등)

- edge.label.font : 선 레이블 글자형 (1 : plain text, 2 : bold, 3 : italic, 4 : bold italic)

- edge.label.cex : 선 레이블 크기 (default = 1)

- edge.label.color : 선 레이블 색 (default = "navy")

 

 

3) Vertex : 점 관련

 

- vertex.size : 점 크기, vector도 가능 (default = 15)

- vertex.color : 점 색 (default = "SkyBlue2")

- vertex.frame.color : 점 윤곡의 색 (default = "black")

- vertex.shape : 점 형태 ("circle", "square", "rectangle", "none", default = "circle")

 

- vertex.label : 점 레이블 (vector)

- vertex.label.family : 점 레이블 종류 ("serif", "sans", "mono" 등)

- vertex.label.font : 점 레이블 글자형 (1 : plain text, 2 : bold, 3 : italic, 4 : bold italic)

- vertex.label.cex : 점 레이블 크기 (default = 1)

- vertex.label.dist : 점 중심과 레이블 간 거리 (default = 0)

- vertex.label.degree : 점 레이블 방향(radian) (좌 : 0, 우 : pi, 상 : -pi/2, 하 : pi/2)

- vertex.label.color : 점 레이블 색 (default = "navy")

 

 

네트워크 그래프 하나 그리는데 무슨 놈의 파라미터가 종류가 이렇게 많은 건지 놀랍기도하고, 이걸 언제 다 설정하나 부담되기도 하지요?

 

default 설정 값을 이용해서 한번 얼른 그려보시고요, 원하는 모양이 아니다 싶으면 parameter 종류 중에서 살짝 살짝 손을 좀 봐가면서 몇 번 더 그래프를 그려보시기 바랍니다. 

 

R이 제공하는 이런 다양한 그래프 옵션이면 못할 것이 없겠지요?!

 

[Reference]

- R을 활용한 사회네트워크분석 입문, 허명회 저, 자유아카데미, 2012

 

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

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 방향을 가진 네트워크 상에서 유량, 에너지, 물자 등의 '네트워크(network) 기반'의 흐름(flow)을 시각화하는데 유용한 Sankey Diagram 에 대해서 알아보겠습니다. 

 

Sankey Diagram 은 얼핏보면 평행좌표그림(parallel coordinate plot)과 비슷한 면이 있습니다.  하지만 Sankey Diagram은 Node -> Edge 로의 관계, 경로가 있다는 점, 경로의 두께를 weight 에 따라서 다르게 한다든지, 색깔을 부여할 때도 반투명(alpha)하게 한다든지 해서 평행좌표그림 대비 다릅니다. (평행좌표그림은 그냥 다변량 변수들을 y축 높이를 같게 해서 옆으로 x를 죽 늘어놓은 형태. 경로 개념 없음. 선 두께 동일) 

 

아래 이미지는 구글에서 Sankey Diagram 이라고 키워드 검색했을 때 나오는 이미지들을 화면캡쳐한 것입니다.  아래 이미지를 보면 '아, 이거~ ' 싶으시죠?

 

 

* 이미지 출처 : Google 검색

 

 

자, 그럼

 

 - R의 riverplot package(* author : January Weiner) 를 가지고

 - minard 데이터셋(* source : Charles Joseph Minard)을 사용해서
   (R riverplot package에 내장되어 있음)

 

나폴레옹 군대가 러시아로 진군했다가 퇴각했던 경로를 시각화해보겠습니다.

 

 

분석의 재미를 더하기 위해 "minard" 데이터셋에 대한 역사적인 배경을 간략히 알아보고 넘어가겠습니다.

 

때는 바야흐로 1812년, 유럽이 되겠습니다.  프랑스의 나폴레옹은 유럽의 상당 국가를 점령했으며, 영국을 침탈하기 위해 백방으로 쌈질을 걸었지만 번번히 실패하고 있던 상황이었습니다.  이에 화가 난 나폴레옹은 '바다를 건너가서 싸우는 게 승산이 낮으니 차라리 유럽 본토와 영국과의 무역을 봉쇄해서 영국의 피를 말리자. 그래, 바로 이거야. 내 사전에 불가능은 없어!' 라는 계획을 세우게 됩니다.

 

그러나 but,

 

나폴레옹의 프랑스가 이미 과도하게 힘이 세졌기 때문에 견제가 필요하다가 생각한 러시아의 알렉산더 짜르는 '나폴레옹, 내가 니 봉이냐?  영국 다음에 러시아 공격할거지?  내가 누구 좋으라고 니 말을 따라?' 라면서 나폴레옹의 영국과의 무역 폐쇄령을 쌩까고 게기게 됩니다. 

 

이에 발끈한 나폴레옹은 프랑스 대군을 모집해서 러시아 짜르의 못되고 괴씸한(?) 버릇을 고쳐주고자, 본떼를 보여주고자 1812년 10월, 겨울이 코앞인 시점에 러시아 모스코바로 진격을 하게 됩니다. 이때만 해도 정말 나폴레옹 군대는 "진격의 거인" 이었습니다.

 

그러나 but,

 

러시아 알렉산더 짜르가 대책없이 나폴레옹에게 대든게 아니었습니다.  러시아 짜르는 러시아 군과 국민에게 아주 간단한(?) 전략의 명령을 내립니다.  "프랑스군이 진격하는 곳의 모든 것을 태워서 프랑스군이 아무것도 탈취하지 못하도록 하고, 싸우지는 말고 퇴각하라.  전투 전략 끝!"

 

아마, 나폴레옹의 프랑스군은 처음 며칠은 러시아로 무혈입성하는 것에 신이 났을지도 모릅니다.

 

그러나 but,

 

10월이 11월이 되고, 그 담에 12월이 되면서 추위와 배고픔과 질병에 프랑스 군인들의 대부분이 죽어나갔습니다.  진격의 거인 나폴레옹은 러시아 짜르의 "불태우고 후퇴" 전략에 속수무책으로 당하면서 거의 전멸을 당하게 됩니다.

 

 

 

아래의 그림이 나폴레옹 프랑스 군대가 러시아로 진격했다가 퇴각한 진로를 지도 상에 표기한 것입니다.

 

* 출처 : https://robots.thoughtbot.com/analyzing-minards-visualization-of-napoleons-1812-march

 

 

 

여기까지의 이야기를 토대로 숫자와 그래프를 가지고 한눈에 실감할 수 있는 시각화를 Charles Joseph Minard 이라는 분이 아래와 같이 했습니다.

 

[ Napoleon army march : minard ]

* 출처 : https://robots.thoughtbot.com/analyzing-minards-visualization-of-napoleons-1812-march

 

 

 

위의 2차원의 minard visualization에는 다양한 차원의 정보가 알차게(!) 들어있는데요,


 - (1) 프랑스군의 진격과 퇴각 경로 (advance and retreat path and direction)

        : 연한 색깔이 진격(advance), 검정 색깔이 퇴각(retreat)

        : 도시 이름은 좌표에 따라 text로 표기

        : 프랑스 군이 세갈래(하나의 큰 줄기, 두 개의 얇은 줄기)로 나누어 진격한 것도 선이 갈라지게 표현

 - (2) 프랑스군의 인명 손실 규모 (loss of life at a time and location)
        : 선의 두께(line width), 처음에는 몽둥이처럼 두꺼웠던 선이 퇴각 마무리 시점에는 실처럼 가늘게 됨

 

 - (3) 온도 (temperature)

        : 그림 하단에 퇴각 시점의 온도를 그리 넣음.  최저 -30도씨까지 떨어졌음.  얼어죽기 딱 좋은 날씨. -_-;

 

 - (4) 강 (river)

        : 하단에 얇은 수직 선으로 나폴레옹군이 퇴각 시점에 맞닥트려 시련을 더해 준 강(river)을 그려 넣음. 

 

 

이렇게 많은 알찬 정보를 저 위의 시각화 하나에 오롯히 담아 냈습니다!!!  이해하기 쉽죠?!

 

 

이걸 데이터로 나타내 보면 아래와 같습니다.  @@;  

이게 무슨 소린가, 데이터가 뭘 말해주려고 하나.... 눈 돌아가지요? 

위의 그래프로 보면 단박에 이해되는 것을 아래의 숫자로 보면 한숨 나오고 갑갑하지요? ㅋㅋ

 

> install.packages("riverplot")
> library(riverplot)

 

> data( minard )
> minard
$edges
    ID1  ID2  Value direction
1    A1   A2 422000         A
2    A2   A3 400000         A
3    A3   A4 320000         A
4    A4   A5 320000         A
5    A5   A6 300000         A
6    A6   A7 280000         A
7    A7   A8 240000         A
8    A8   A9 210000         A
9    A9  A10 180000         A
10  A10  A11 175000         A
11  A11  A12 145000         A
12  A12  A13 140000         A
13  A13  A14 127100         A
14  A14  A15 100000         A
15  A15  A16 100000         A
16  A16   R1 100000         A
17   R1   R2 100000         R
18   R2   R3  98000         R
19   R3   R4  97000         R
20   R4   R5  96000         R
21   R5   R6  87000         R
22   R6   R7  55000         R
23   R7   R8  37000         R
24   R8   R9  24000         R
25   R9  R10  20000         R
26  R10  R11  50000         R
27  R11  R12  50000         R
28  R12  R13  48000         R
29  R13  R14  20000         R
30  R14  R15  12000         R
31  R15  R16  14000         R
32  R16  R17   8000         R
33  R17  R18   4000         R
34  R18  R19  10000         R
35  R19  R19  10000         R
36   A3 A4.2  60000         A
37 A4.2 A5.2  40000         A
38 A5.2 A6.2  33000         A
39 A6.2  R10  30000         R
40   A2 A3.1  22000         A
41 A3.1  R18   6000         A

$nodes
       ID Longitude Latitude
A1     A1      24.0     54.9
A2     A2      24.5     55.0
A3     A3      25.5     54.5
A4     A4      26.0     54.7
A5     A5      27.0     54.8
A6     A6      28.0     54.9
A7     A7      28.5     55.0
A8     A8      29.0     55.1
A9     A9      30.0     55.2
A10   A10      30.3     55.3
A11   A11      32.0     54.8
A12   A12      33.2     54.9
A13   A13      34.4     55.5
A14   A14      35.5     55.4
A15   A15      36.0     55.5
A16   A16      37.6     55.8
R1     R1      37.7     55.7
R2     R2      37.5     55.7
R3     R3      37.0     55.0
R4     R4      36.8     55.0
R5     R5      35.4     55.3
R6     R6      34.3     55.2
R7     R7      33.3     54.8
R8     R8      32.0     54.6
R9     R9      30.4     54.4
R10   R10      29.2     54.3
R11   R11      28.5     54.2
R12   R12      28.3     54.3
R13   R13      27.5     54.5
R14   R14      26.8     54.3
R15   R15      26.4     54.4
R16   R16      25.0     54.4
R17   R17      24.4     54.4
R18   R18      24.2     54.4
R19   R19      24.1     54.4
A4.2 A4.2      26.6     55.7
A5.2 A5.2      27.4     55.6
A6.2 A6.2      28.7     55.5
A3.1 A3.1      24.6     55.8

$cities
   Longitude Latitude           Name
1       24.0     55.0          Kowno
2       25.3     54.7          Wilna
3       26.4     54.4       Smorgoni
4       26.8     54.3      Moiodexno
5       27.7     55.2      Gloubokoe
7       28.5     54.3     Studienska
8       28.7     55.5        Polotzk
9       29.2     54.4           Bobr
10      30.2     55.3        Witebsk
11      30.4     54.5         Orscha
13      32.0     54.8       Smolensk
14      33.2     54.9    Dorogobouge
15      34.3     55.2          Wixma
16      34.4     55.5          Chjat
17      36.0     55.5        Mojaisk
18      37.6     55.8         Moscou
19      36.6     55.3      Tarantino
20      36.5     55.0 Malo-Jarosewii

 

 

* source : R riverplot package, author : January Weiner, data source : Charles Joseph Minard

 

 

 Sankey Diagram에서 사용하는 node, edge라는 용어를 이해하기 위해서, 두 개체 간 쌍을 이룬 관계 (mathematical structures used to model pairwise relations between objects)를 다루는 Graph Theory에 대해서 간략히 짚고 넘어가겠습니다.

 

아래 그래프처럼 점(Node or Point or Vertice)과 선(Edge or Link or Line or Arc)으로 개체 간의 관계를 나타내는 그래프로 나타내어 연구하는 수학, 컴퓨터 과학 분야가 Graph theory입니다.  최적화(optimization) 할 때도 네트워크 그래프 많이 쓰곤 합니다.

 

 

 

 

Sankey Diagram 그리려면

 

  - Nodes : 개체들의 ID, Longitude, Latitude, Labels

  - Edges : 개체 간 관계를 나타내는 ID 1, ID 2, Value (or weight) 

 

정보가 필요합니다.

 

> str(minard)
List of 3
 $ edges :'data.frame':	41 obs. of  4 variables:
  ..$ ID1      : chr [1:41] "A1" "A2" "A3" "A4" ...
  ..$ ID2      : chr [1:41] "A2" "A3" "A4" "A5" ...
  ..$ Value    : num [1:41] 422000 400000 320000 320000 300000 280000 240000 210000 180000 175000 ...
  ..$ direction: Factor w/ 2 levels "A","R": 1 1 1 1 1 1 1 1 1 1 ...
 $ nodes :'data.frame':	39 obs. of  3 variables:
  ..$ ID       : chr [1:39] "A1" "A2" "A3" "A4" ...
  ..$ Longitude: num [1:39] 24 24.5 25.5 26 27 28 28.5 29 30 30.3 ...
  ..$ Latitude : num [1:39] 54.9 55 54.5 54.7 54.8 54.9 55 55.1 55.2 55.3 ...
 $ cities:'data.frame':	18 obs. of  3 variables:
  ..$ Longitude: num [1:18] 24 25.3 26.4 26.8 27.7 28.5 28.7 29.2 30.2 30.4 ...
  ..$ Latitude : num [1:18] 55 54.7 54.4 54.3 55.2 54.3 55.5 54.4 55.3 54.5 ...
  ..$ Name     : Factor w/ 20 levels "Bobr","Chjat",..: 5 18 15 9 4 16 13 1 19 12 

 

 

 

 

R riverplot package를 사용해서 드디어 Sankey diagram을 그려보겠습니다.  R script는 riverplot package(* author : January Weiner)에 있는 예제 script를 그대로 인용하였습니다. (날로 먹는 듯한 이 기분..^^;) 

 

 

> ############################
> # Sankey diagram 
> # using R riverplot package 
> # minard data (list format)
> ############################
> 
> # install.packages("riverplot")
> library(riverplot)
> data( minard )
> 
> nodes <- minard$nodes
> edges <- minard$edges
> colnames( nodes ) <- c( "ID", "x", "y" )
> colnames( edges ) <- c( "N1", "N2", "Value", "direction" )
> 
> 
> # color the edges by troop movement direction
> edges$col <- c( "#e5cbaa", "black" )[ factor( edges$direction ) ]
> 
> # color edges by their color rather than by gradient between the nodes
> edges$edgecol <- "col"
> 
> # generate the riverplot object and a style
> river <- makeRiver( nodes, edges )
> style <- list( edgestyle= "straight", nodestyle= "invisible" )
> 
> # plot the generated object
> plot( river, lty= 1, default_style= style )
> 
> # Add cities
> with( minard$cities, points( Longitude, Latitude, pch= 19 ) )
> with( minard$cities, text( Longitude, Latitude, Name, adj= c( 0, 0 ) ) )
> # Add title
> title("Sankey Diagram - Napoleon army march, minard")

 

* R script author : January Weiner

 

 

다음번 포스팅에서는 igraph package를 사용해서 방향성 있는 가중 네트워크를 시각화해보겠습니다.

 

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

 

[Reference]

 - R riverplot package manual : https://cran.r-project.org/web/packages/riverplot/riverplot.pdf

 - On minards visualization : https://robots.thoughtbot.com/analyzing-minards-visualization-of-napoleons-1812-march

 

 

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)

 

등이 있습니다. 

 

이번 포스팅에서는 (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
,

지난번 포스팅에서는 그래프에 추가적인 정보를 입력하는 낮은 수준의 그래프 함수(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
,

지난번 포스팅에서는 그래프에 추가적인 정보를 입력하는 낮은 수준의 그래프 함수(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, ...) 에 대해서 소개하겠습니다.



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

 

 

 

범례를 추가하는 legend()함수의 일반적인 사용법은 아래와 같습니다.

 

legend(x, y = NULL, legend, fill = NULL, col = par("col"),
       border = "black", lty, lwd, pch,
       angle = 45, density = NULL, bty = "o", bg = par("bg"),
       box.lwd = par("lwd"), box.lty = par("lty"), box.col = par("fg"),
       pt.bg = NA, cex = 1, pt.cex = cex, pt.lwd = lwd,
       xjust = 0, yjust = 1, x.intersp = 1, y.intersp = 1,
       adj = c(0, 0.5), text.width = NULL, text.col = par("col"),
       text.font = NULL, merge = do.lines && has.pch, trace = FALSE,
       plot = TRUE, ncol = 1, horiz = FALSE, title = NULL,
       inset = 0, xpd, title.col = text.col, title.adj = 0.5,
       seg.len = 2) 

 

 

옵션이 굉장히 많지요?  ^^;  그래프에 관한한 R 가지고 못하는게 거의 없다는게 바로 이런 겁니다.  그런데 이걸 다 설명하자니 시간이 너무 오래걸릴것 같기도 하고 대부분은 아마 거의 사용할 일이 없을 것 같기도 합니다.  그래서 많이 사용하는 옵션 위주로 몇 개만 선별해서 어려움없이 사용할 수 있는 정도로만 설명하겠습니다.

 

 

 구분

옵션 기능 

 x, y

  범례를 추가할 위치를 설정하는 3가지 방법

  (1) x, y 좌표를 입력하면 범례 사각형의 왼쪽 상단이 그 지점에 위치함

  (2) locator(1)을 입력하면 커서를 가리키는 지점에 범례 생성

  (3) 위치를 나타내는 아래의 9개 단어 중 하나를 선택해서 입력

    : "bottomright", "bottom", "bottomleft", "left", "topleft",

      "top", "topright", "right" and "center"

 legend

  길이가 1보다 큰 문자(character) 혹은 범례를 담은 벡터(expression vector)

 col

  색깔 지정 벡터

 lty

  선 유형 지정 벡터

 lwd

  선 두께 지정 벡터

 pch

  기호 지정 벡터

...

  그래픽 모수 추가 설정 가능

 

 

 

MASS 패키지에 내장된 Cars93 데이터프레임의 차종(Type) 별로 차 무게(Weight)와 고속도로 연비 (MPG.highway) 변수를 사용해서 산포도를 그려보겠습니다. 그리고 차종(Type) 그룹에 대한 범례(legend)를 추가해보겠습니다.

 

 

(1) x, y 좌표를 직접 입력하여 범례 위치 설정

 

> # to use Cars93 dataframe
> library(MASS)
> 
> # scatter plot
> attach(Cars93)
> 
> # adding points with different characters by condition
> plot(Weight, MPG.highway, type = 'n') # blank plot
> 
> # Type = Compact
> points(Weight[Type == "Compact"], MPG.highway[Type == "Compact"], pch = 0)
> 
> # Type = Large
> points(Weight[Type == "Large"], MPG.highway[Type == "Large"], pch = 1)
> 
> # Type = Midsize
> points(Weight[Type == "Midsize"], MPG.highway[Type == "Midsize"], pch = 17, col = "yellow")
> 
> # Type = Small
> points(Weight[Type == "Small"], MPG.highway[Type == "Small"], pch = 3)
> 
> # Type = Sporty
> points(Weight[Type == "Sporty"], MPG.highway[Type == "Sporty"], pch = 9)
> 
> # Type = Van
> points(Weight[Type == "Van"], MPG.highway[Type == "Van"], pch = 15, col = "blue")
> 
> title("adding legend to the plot")
> 
> 
> # adding legend to topright side
> legend(x = 3500, y = 50, 
+        c("Compact", "Large", "Midsize", "Small", "Sporty", "Van"), 
+        col = c("black", "black", "yellow", "black", "black", "blue"), 
+        pch = c(0, 1, 17, 3, 9, 15)
+ )
>

 

 

> detach(Cars93)

 

 

 

 

(2) 위치를 나타내는 말을 직접 입력하여 범례 위치 설정

 

> library(MASS)
> # scatter plot
> attach(Cars93)
> # adding points with different characters by condition
> plot(Weight, MPG.highway, type = 'n') # blank plot
> # Type = Compact
> points(Weight[Type == "Compact"], MPG.highway[Type == "Compact"], pch = 0)
> 
> # Type = Large
> points(Weight[Type == "Large"], MPG.highway[Type == "Large"], pch = 1)
> 
> # Type = Midsize
> points(Weight[Type == "Midsize"], MPG.highway[Type == "Midsize"], pch = 17, col = "yellow")
> 
> # Type = Small
> points(Weight[Type == "Small"], MPG.highway[Type == "Small"], pch = 3)
> 
> # Type = Sporty
> points(Weight[Type == "Sporty"], MPG.highway[Type == "Sporty"], pch = 9)
> 
> # Type = Van
> points(Weight[Type == "Van"], MPG.highway[Type == "Van"], pch = 15, col = "blue")
> 
> title("adding points with different characters by Car Types")
> 
> 
> # adding legend to topright side
> legend("topright", 
+        c("Compact", "Large", "Midsize", "Small", "Sporty", "Van"), 
+        col = c("black", "black", "yellow", "black", "black", "blue"), 
+        pch = c(0, 1, 17, 3, 9, 15)
+        )
> 

 


> detach(Cars93)

 

 

 

다음번 포스팅에서는 다각형(polygon)을 추가하는 방법에 대해서 소개하겠습니다.

 

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

 

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

 

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() 에 대해서 소개하겠습니다.



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

 

 

 

그래프에 문자를 추가할 때 text() 함수와 mtext() 함수를 사용합니다. 차이점은 text()가 그래프 내에 문자를 추가할 때 사용하는 반면, mtext()는 외부 마진 영역(1 하단, 2 좌측, 3 상단, 4 우측)에 문자를 추가할 때 사용한다는 것입니다.

 

 

text() 함수와 mtext() 함수의 일반적인 사용법은 아래와 같습니다.

 

함수 (function)

사용법 (usage)

 text()

  text(x, y, labels = , pos = , ... )

 mtext()

  mtext("text to place", side = , line = , adj, outer = , ... )

 

 

 함수

옵션 

기능 설명 

 text()

x, y

  문자를 추가할 위치의 x, y좌표.

  단, x, y 좌표 대신에 locator(1) 을 입력하면 커서로 지적하는

  곳에 문자를 추가함

 labels = " "

  추가할 문자

 pos =

  좌표를 기준으로 문자를 입력할 상대적인 위치

   : 1=below, 2=left, 3=above(default), 4=right

 ...

  폰트, 색깔, 크기 등의 그래프 모수 지정

 mtext()

 "text to place"

  추가할 문자

 side =

  문자를 추가할 위치

   : 1=bottom, 2=left, 3=top(default), 4=right

 line =

  문자와 그래프와의 마진 거리

  (to indicate the line in the margin starting with 0 and moving out)

 adj =

  adj=0 : 왼쪽/아래쪽 정렬,

  adj=1 : 위쪽/오른쪽 정렬,

  생략 : 중앙 정렬

  (adj=0 for left/bottom alignment or adj=1 for top/right alignment)

 outer =

  outer=TRUE : 외부마진에 문자 추가

  outer=FALSE : 내부마진에 문자 추가

 ...

  폰트, 색깔, 크기 등의 그래프 모수 지정

 

 

 

MASS 패키지에 내장되어있는 Cars93 데이터프레임의 차 무게 (Weight), 고속도로 연비 (MPG.highway) 변수를 활용해서 산점도를 그리고, 모델명(Model) 변수를 가지고 text를 추가해보겠습니다.

 

> ##-------------------------------------------
> ## adding text to the plot : text(), mtext()
> ##-------------------------------------------
> 
> ## adding text within a plot : text()
> library(MASS)
> attach(Cars93)
> 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 ...
> 
> plot(Weight, MPG.highway, main = "scatter plot of MPG.highway ~ Weight")
>

 

 
 
> text(x = Weight, y = MPG.highway, labels = Model, pos = 3, cex = 0.5)

 

 

 

 

 

text(x, y, ) 좌표 대신에 text(locator(1), ) 옵션을 사용하면 커서로 문자가 들어갈 위치를 콕 찍어서 지정할 수 있습니다.  reproducible research 관점에서 보면 추천할 만한 방법은 아닌데요, x, y 좌표를 정확히 모르거나, 한번만 간편하게 그래프 그려서 볼 목적이라면 큰 문제는 없겠습니다.

 

 

> # placing text at the point of cursor : locator(1)
> text(locator(1), labels = "Low Mileage Per Gallon")
 

 

> detach(Cars93)

 

 

 

 

다음으로 mtext() 를 사용해서 그래프 외부 마진 영역에 문자를 추가해보는 예제입니다. 

title() 함수로 제목을 추가하는 것과 유사한 측면이 있는데요, mtext()의 경우 여러 개의 그래프를 결합했을 때 외부마진에 그래프 전체를 아우리는 제목을 자유롭게 추가할 수 있다는 유용한 장점이 있습니다.

 

 

> ## places text in one of the four margins : mtext()
> 
> # Save default par values
> op <- par(no.readonly = TRUE)
> 
> # combining 2 graphs in 1 row
> par(mfrow = c(1,2), # 1 row, 2 windows
+     oma = c(2, 2, 4, 1)) # outer margin
> 
> 
> attach(Cars93)
> 
> plot(Weight, MPG.highway, main = "MPG.highway ~ Weight") # plot 1
> plot(Horsepower, MPG.highway, main = "MPG.highway ~ Horsepower") # plot 2
> 

 


> 
> mtext("MPG.highway by Weight, Horsepower", 
+       side = 3, # which margin to place text. 1=bottom, 2=left, 3=top, 4=right
+       line = 1, # to indicate the line in the margin starting with 0 and moving out
+       adj = 2, # adj=0 for left/bottom alignment or adj=1 for top/right alignment
+       cex = 2, # font size
+       outer = TRUE) # outer = TRUE : to place text at outer margin
>

 

 

> > detach(Cars93) > > # Reset par to the default values at startup > par(op)

 

 

다음번 포스팅에서는 범례(legend) 추가하는 방법에 대해서 알아보겠습니다.

 

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

 

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

 

728x90
반응형
Posted by Rfriend
,