예전 포스팅 중에서 일변량 연속형 변수에 대해 ggplot2로 막대 그래프 그리는 법을 소개했었는데요, 막대 그래프의 훌륭한 대안으로서 점 그래프(Dot Plot)이 있습니다. 

 

Cleveland and McGill (1984) 이  “Graphical Methods for Data Presentation: Full Scale Breaks, Dot Charts, and Multibased Logging.” 이라는 논문에서 막대 그래프 대비 점 그래프가 데이터 해석, 가독성에서 가지는 우수성을 소개하면서 Cleveland Dot Plot 이라고도 많이 불리는 그래프입니다.

 

 

분석에 활용할 데이터는 MASS 패키지 내 Cars93 데이터 프레임에서, 차종(Type), 모델(Model), Max.Price, Min.Price의 4개 변수를 사용하겠으며, 관측치 개수가 많아서 화면 하나에 전부 뿌리기에는 너무 많으므로 차종(Type)의 Level 중에서 "Large", "Midsize", "Small" 만 선별하고 "Compact", "Sproty", "Van"은 제외하도록 하겠습니다.

 

 

> 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(Cars93$Type)

Compact   Large Midsize   Small  Sporty     Van 
     16      11      22      21      14       9 
> 
> # Model, Type, Max.Price, Min.Price 변수만 선택
> # Type 중에서 Large, Midsize, Small만 선택 (Compact, Sortry, Van은 제외)
> 
> Cars93_P <- subset(Cars93, 
+                      select = c(Model, Type, Min.Price, Max.Price), 
+                      subset = (Type %in% c("Large", "Midsize", "Small")))
> str(Cars93_P)
'data.frame':	54 obs. of  4 variables:
 $ Model    : Factor w/ 93 levels "100","190E","240",..: 49 56 1 6 24 54 74 73 35 79 ...
 $ Type     : Factor w/ 6 levels "Compact","Large",..: 4 3 3 3 3 2 2 3 2 3 ...
 $ Min.Price: num  12.9 29.2 30.8 23.7 14.2 19.9 22.6 26.3 33 37.5 ...
 $ Max.Price: num  18.8 38.7 44.6 36.2 17.3 21.7 24.9 26.3 36.3 42.7 ...
> head(Cars93_P)
    Model    Type Min.Price Max.Price
1 Integra   Small      12.9      18.8
2  Legend Midsize      29.2      38.7
4     100 Midsize      30.8      44.6
5    535i Midsize      23.7      36.2
6 Century Midsize      14.2      17.3
7 LeSabre   Large      19.9      21.7

 

 

 

geom_point() 함수를 사용하여 클리브랜드 점 그래프(Cleveland dot plot)을 그려보겠습니다. 

 

aes(y = reorder(Model, Max.Price)) 를 사용해서 y축에 사용할 Model 을 Max.Price 를 기준으로 정렬을 하였기 때문에 아래처럼 Max.Price가 높은 것부터 낮은 것으로 정렬이 된 채로 점 그래프가 제시되었습니다.

 

aes(shape = Type) 을 적용하여서 Type(Large, Midsize, Small) 별로 모양(shape)을 달리해서 제시하였습니다.

 

> # Cleveland dot plot of Max Price of Models with different shape by Type > library(ggplot2) > > ggplot(Cars93_P, aes(x = Max.Price, y = reorder(Model, Max.Price), shape = Type)) + + geom_point(size = 3, colour = "blue") + + theme_bw() + # background 색 없애기 + theme(panel.grid.major.x = element_blank(), # x축 선 없애기 + panel.grid.minor.x = element_blank(), + panel.grid.major.y = element_line(colour="grey90", linetype="dashed")) + + ggtitle("Cleveland dot plot of Max.Price of Models with different shape by Type")

 

 

 

 

 

 

다음으로, Type(Large, Midsize, Small) 별로 facet_grid(Type ~ ., scales="free_y", space="free_y") 을 적용하여 면을 분할을 한 클리브랜드 점 그래프(Cleveland dot plot)을 그려보겠습니다.

 

면 분할해서 그리려면 위의 예처럼 ggplot2 내 aes(reorder)로는 안되구요, 먼저 Type과 Max.Price 순서대로 데이터셋을 따로 정렬해서 요인(factor)으로 levels 를 지정해서 변환해주어야 합니다.  그래프는 상대적으로 쉬운데, 데이터셋 정렬/요인변환이 어려울 수 있겠습니다.

 

> # Type, Max.Price 순서대로 정렬
> Model_Order <- Cars93_P$Model[order(Cars93_P$Type, # Large, Midsize, Small 순서
+                                     -Cars93_P$Max.Price, # 높은것에서 낮은 순서
+                                     decreasing=TRUE)]
> 
> # Model_Order를 요인(factor)으로 변환
> Cars93_P$Model <- factor(Cars93_P$Model, levels=Model_Order)
> 
> # Type별로 면 분할, Max.Price 순서대로 정렬된 Cleveland dot plot
> ggplot(Cars93_P, aes(x = Max.Price, y = Model)) +
+   geom_point(size = 3, aes(colour = Type)) +
+   theme_bw() +
+   theme(panel.grid.major.y = element_blank(), 
+         panel.grid.minor.y = element_blank()) + 
+   facet_grid(Type ~ ., scales="free_y", space="free_y") +
+   ggtitle("Cleveland dot plot of Max.Price of Models with Facets of Type")

 

 

 

 

 

다음으로, 차종(Type)별로 면 분할은 유지하면서 위의 Max.Price 에 더해서 Min.Price 를 추가하고 모양(shape)을 다르게 제시해보겠습니다.

 

이것도 데이터셋을 따로 미리 손을 봐줘야 합니다.  reshape 패키지의 melt() 함수를 사용해서 Max.Price, Min.Price 두 값을 Price_cd (Max.Price, Min.Price)와 Price (value) 의 두개 변수로 녹여서 데이터 구조를 ggplot2의 geom_point()에 사용할 수 있도록 변경하여야 합니다.  (reshape 패키지의 melt(), cast() 함수는 여기서 자세히 설명하기가 힘든데요, 따로 알아보시면 좋겠습니다)

 

 

> #--------
> # Min.Price 추가 
> # melt
> library(reshape)
> Cars93_P_melt <- melt(Cars93_P, idvars = c("Type", "Model"))
Using Model, Type as id variables
> head(Cars93_P_melt)
    Model    Type  variable value
1 Integra   Small Min.Price  12.9
2  Legend Midsize Min.Price  29.2
3     100 Midsize Min.Price  30.8
4    535i Midsize Min.Price  23.7
5 Century Midsize Min.Price  14.2
6 LeSabre   Large Min.Price  19.9
> 
> # 변수명 변경
> Cars93_P_melt <- rename(Cars93_P_melt, c(variable = "Price_cd", value = "Price"))
> head(Cars93_P_melt)
    Model    Type  Price_cd Price
1 Integra   Small Min.Price  12.9
2  Legend Midsize Min.Price  29.2
3     100 Midsize Min.Price  30.8
4    535i Midsize Min.Price  23.7
5 Century Midsize Min.Price  14.2
6 LeSabre   Large Min.Price  19.9
> 
> # Type별로 면 분할, Max.Price 순서대로 정렬, Min.Price추가된 Cleveland dot plot
> ggplot(Cars93_P_melt, aes(x = Price, y = Model)) + 
+   geom_segment(aes(yend=Model, xend=0)) + # 점까지만 선 그리기
+   geom_point(size=3, aes(shape = Price_cd)) + # Price_cd로 모양 구분
+   theme_bw() + # backgroud 색 없애기
+   theme(panel.grid.major.y = element_blank(), # y축 없애기
+         panel.grid.minor.y = element_blank()) + # y축 없애기
+   facet_grid(Type ~ ., scales="free_y", space="free_y") + # Type별로 면 분할
+   ggtitle("Cleveland dot plot of Max, Min Price of Models with Facets of Type")
 

 

 

 

위의 세번째 그래프처럼 Max.Price와 Min.Price를 같은 그래프에 그리는데, 만약 이것을 막대 그래프로 그린다고 상상해 보세요.  막대그래프로 그린다면 지저분하고 해석, 가독성이 클리브랜드 점 그래프 대비 떨어질겁니다. 

 


 

[Reference]

 

Cleveland, William S. 1984. “Graphical Methods for Data Presentation: Full Scale
Breaks, Dot Charts, and Multibased Logging.” The American Statistician, 38:270-280.

 

Dot Plots: A Useful Alternative to Bar Charts, Naomi B. Robbins, Ph.D. March 7, 2006

 

 

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

 

Posted by R Friend R_Friend

댓글을 달아 주세요

  1. 김경찬 2017.02.04 17:02  댓글주소  수정/삭제  댓글쓰기

    와~ 점그래프 그리는건 정말 어렵네요. segment함수의 매개변수 왜 저렇게 두는지도 모르겠고 ㅎㅎ 외우기는 정말 어려운듯하네요ㅠㅠ

    • R Friend R_Friend 2017.02.04 17:23 신고  댓글주소  수정/삭제

      젇 함수를 전부 다 외우지는 못합니다. 필요할 때 블로그 보면서 만들고 싶은 형태 골라서 R scriot 짜요.

      클리브랜드 점 그래프 유용해서 종종 쓰은 편이예요.

      엑셀 그래프 대비 R이 좋은 점이 바로 이런거죠. 데이터 전처리 하고 세부 옵션으로 조정해 가면서 바로 인쇄에 써먹어도 될 정도의 고품질 그래프를 스릴 수 있다는거요.