그룹(집단, 요인) 간의 데이터 분포 형태, 변화 추이 등을 비교 분석하기에 유용한 방법으로 비교하려는 축을 기준으로 면을 분할하여 그래프를 그룹 간 비교하는 방법이 있습니다.

 

Lattice 패키지에서는 Trellis 를 사용하는데요, ggplot2 패키지에서는 facet_grid() 함수facet_wrap() 함수를 사용하여 면 분할을 구현할 수 있습니다.

 

Base Graphics 패키지에서는 par() 함수를 사용해서 면 분할을 지정해줄 수 있습니다만, x축과 y축의 scale이 들쭉날쭉해서 직접적으로 서로 비교하기가 곤란하거나, y축의 min, max 값이 그룹 간 숫자를 모두 감안해서 자동 설정되는 것이 아니다보니 분석가가 미리 y축 값의 범위를 계산해보고, 혹은 그려보고 나서 y축 값을 세팅해줘야 하므로 lattice나 ggplot2 대비 불편합니다.  따라서 집단간 비교를 위한 면 분할이 필요한 경우 ggplot2나 lattice 패키지를 권합니다.

 

MASS 패키지 내 무게(Weight), 고속도로연비(MPG.highway), 차종(Type, 범주형), 생산국가(Origin, 범주형) 의 4개 변수를 사용해서, x축에 무게(Weight), y축에 고속도로연비(MPG.highway), 그리고 면 분할의 기준으로 범주형 변수인 차종(Type)과 생산국가(Origin) 변수를 사용하겠습니다.

 

facet_grid()를 먼저 예제를 보이고, 그 후에 facet_wrap()의 예제를 들겠습니다.  두 함수가 비슷하면서도 조금 다릅니다.  분석가가 필요로 하는 아웃풋 이미지에 맞게 골라서 사용하면 되겠습니다.

 

 

(1) facet_grid()

 

> # facet_grid()
> ggplot(Cars93, aes(x=Weight, y=MPG.highway)) +
+   geom_point(shape=21, colour="black") +
+   facet_grid(Type ~ .)
 

 


 

> ggplot(Cars93, aes(x=Weight, y=MPG.highway)) +
+   geom_point(shape=21, colour="black") +
+   facet_grid(. ~ Type)

 

 

 

 


 

> ggplot(Cars93, aes(x=Weight, y=MPG.highway)) +
+   geom_point(shape=21, colour="black") +
+   facet_grid(Origin ~ Type)

 

 

 

 

 

 

 

(2) facet_wrap()

 

facet_wrap()는 ncol 또는 nrow 로 행 또는 열의 개수를 분석가가 지정할 수 있어서 좋은 점이 있습니다.

 

> # facet_wrap()
> ggplot(Cars93, aes(x=Weight, y=MPG.highway)) +
+   geom_point(shape=21, colour="black") +
+   facet_wrap( ~ Type, ncol=3)

 

 

 


 

> ggplot(Cars93, aes(x=Weight, y=MPG.highway)) +
+   geom_point(shape=21, colour="black") +
+   facet_wrap(Origin ~ Type, ncol=3)

 

 

 


 

> ggplot(Cars93, aes(x=Weight, y=MPG.highway)) +
+   geom_point(shape=21, colour="black") +
+   facet_wrap(Origin ~ Type, ncol=2)

 

 

 

 

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

 

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

 

 

728x90
반응형
Posted by Rfriend
,

이전 포스팅에서 x축과 y축의 값에 따라 산점도 그리는 방법을 알아보았다면, 이번 포스팅에서는 여기에 더해서 z라는 제 3의 변수에 비례해서 점의 크기를 변화시켜서 그린 그래프가 버블 그래프 (Bubble Chart) 입니다.  산점도가 2차원의 그래프(단, 색깔이나 모양 조건을 추가하면 3차원 정보 제공 가능)라면, 버블 그래프 (Bubble Chart)는 3차원의 그래프가 되어 지면에 보다 많은 정보량을 제공할 수 있는 장점이 있습니다. 

 

ggplot2에서는 산점도, 점 그래프를 그리는 geom_point() 함수와 함께 scale_size_area() 함수를 같이 사용하면 버블 그래프 (Bubble Chart)를 그릴 수가 있습니다.

 

MASS 패키지의 Cars93 데이터 프레임 내에 차 모델명(Model), 차종(Type), 무게(Weight), 고속도로연비(MPG.highway), 가격(Price)의 5개 변수를 사용하여 버블 그래프를 그려보겠습니다.  데이터가 너무 많으면 버블 그래프를 그릴 때 겹쳐 보여서 보기 싫으므로 차종(Type)에서 "compact"와 "large"의 두 종만 선별해서 예를 들어보겠습니다.

 

> 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 ...
 
> levels(Cars93$Type)
[1] "Compact" "Large"   "Midsize" "Small"   "Sporty"  "Van" 
 
 

> table(Cars93$Type) Compact Large Midsize Small Sporty Van 16 11 22 21 14 9

 

 

> # dataset selection

> Cars93_sample <- subset(Cars93, 
+                         select = c("Model", "Type", "Weight", "MPG.highway", "Price"), 
+                         subset = (Type %in% c("Compact", "Large")))
> Cars93_sample
            Model    Type Weight MPG.highway Price
3              90 Compact   3375          26  29.1
7         LeSabre   Large   3470          28  20.8
8      Roadmaster   Large   4105          25  23.7
10        DeVille   Large   3620          25  34.7
12       Cavalier Compact   2490          36  13.4
13        Corsica Compact   2785          34  11.4
18        Caprice   Large   3910          26  18.8
20       Concorde   Large   3515          28  18.4
21        LeBaron Compact   3085          28  15.8
22       Imperial   Large   3570          26  29.5
25         Spirit Compact   2970          27  13.3
30         Vision   Large   3490          28  19.3
33          Tempo Compact   2690          27  11.3
38 Crown_Victoria   Large   3950          26  20.9
43         Accord Compact   3040          31  17.5
52       Town_Car   Large   4055          26  36.1
55            626 Compact   2970          34  16.5
58           190E Compact   2920          29  31.9
65         Altima Compact   3050          30  15.7
68        Achieva Compact   2910          31  13.5
71   Eighty-Eight   Large   3470          28  20.7
74        Sunbird Compact   2575          31  11.1
77     Bonneville   Large   3495          28  24.4
78            900 Compact   2775          26  28.7
82         Legacy Compact   3085          30  19.5
90         Passat Compact   2985          30  20.0
92            240 Compact   2985          28  22.7

 

 

ggplot2의 geom_point()와 scale_size_area() 함수를 사용하여 버블 그래프 (bubble chart)를 그려보겠습니다.  ggplot2는 별도의 설치와 호출이 필요한 패키지이므로 아래와 같이 install.packages()와 library()로 설치 및 호출을 먼저 해야 합니다.

 

> install.packages("ggplot2")
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/ggplot2_1.0.1.zip'
Content type 'application/zip' length 2676272 bytes (2.6 MB)
downloaded 2.6 MB

package ‘ggplot2’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\user\AppData\Local\Temp\RtmpKeoxEa\downloaded_packages
> library(ggplot2) 

 

 

 

x축에는 무게(Weight)를, y축에는 고속도로연비(MPG.highway)를, 원의 크기는 가격(Price)를 설정하였습니다.  그리고 겹치는 부분이 있어서 alpha=0.5 로 해서 반투명하게 하였습니다. scale_size_area 에서 원의 크기의 최대값(max)을 15개 한정을 지었으며, geom_text() 함수를 활용해 vjust=1로 해서 x축 값에 align되고 y값은 MPG.highway값에 살짝 조정을 가해서 label로는 모델명(Model) 변수값을 가져다가 라벨링을 하였습니다.

 

> # Bubble chart with scale_size_area and label
> ggplot(Cars93_sample, aes(x=Weight, y=MPG.highway)) + 
+   geom_point(aes(size=Price), shape=21, colour="grey90", fill="yellow", , alpha=0.5) +
+   scale_size_area(max_size = 15) + # 범례 없애려면 guide=FALSE
+   geom_text(aes(y=as.numeric(MPG.highway)-sqrt(Price)/10, label=Model), 
+             vjust=1, colour="grey40", size=3) + 
+   ggtitle("Bubble chart with scale_size_area and label") 
 
 

 

 

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

 

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

 

  

728x90
반응형
Posted by Rfriend
,

산점도는 두 변수간의 관계를 파악하는데 굉장히 유용한 시각화 방법입니다.  그리고 산점도 행렬은 다수의 변수들 간의 관계를 한눈에 파악하는데 유용한 시각화 방법이구요.

 

이전 포스팅에서

- ggplot2의 geom_point() 함수를 이용한 한개 변수의 산점도 그리기

- corrplot 패키지를 이용한 상관계수 행렬 그림 그리기

를 소개했었습니다.

 

ggplot2로 두 변수만 가지고 산점도는 유연하게 그릴 수 있는데요, 3개 이상의 변수를 가지고 산점도 행렬을 그리기는 매우 힘이 듭니다. (프로그래밍을 해야 합니다)  따라서 산점도 행렬은 plot() 함수를 써서 한방에 그리는 것이 제일 편하구요,

 

이번 포스팅에서는 Base Graphics 패키지 내에 pairs() 함수를 이용해서 산점도 행렬에 몇가지 사용자 정의 함수를 추가하여 히스토그램도 집어 넣고 상관계수 숫자도 포함시키는 방법을 소개하겠습니다.  산점도 행렬에 많은 추가 정보를 담을 수 있어서 매우 보기에 좋고 유용합니다. 사용자 정의 함수는 pairs() 도움말(help)을 참조하였습니다.

 

 

예제로 사용한 데이터는 뉴욕의 1973년도 공기의 질을 측정한 airquality 데이터셋의 Ozone, Solar.R, Wind, Temp 4개의 변수가 되겠습니다.

 

> str(airquality)
'data.frame':	153 obs. of  6 variables:
 $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
 $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
 $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
 $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ...
 $ Month  : int  5 5 5 5 5 5 5 5 5 5 ...
 $ Day    : int  1 2 3 4 5 6 7 8 9 10 ...
> 

> # 1~4번째 변수만 선택

> airquality_1 <- airquality[,c(1:4)]
> str(airquality_1)
'data.frame':	153 obs. of  4 variables:
 $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
 $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
 $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
 $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ... 

 

 

결측값이 있으면 상관계수를 구할 때 NA 값이 나오므로, 결측값 여부 확인하고 결측값이 있는 행은 삭제한 후에 산점도 행렬을 그려보겠습니다.

 

> # 결측값 개수 확인
> sum(is.na(airquality_1$Ozone)) # 37
[1] 37
> sum(is.na(airquality_1$Solar.R)) # 7
[1] 7
> sum(is.na(airquality_1$Wind)) # 0
[1] 0
> sum(is.na(airquality_1$Temp)) # 0
[1] 0
> 
> # 결측값 있는 상태에서 상관계수 계산했을 때
> cor(airquality_1)
        Ozone Solar.R       Wind       Temp
Ozone       1      NA         NA         NA
Solar.R    NA       1         NA         NA
Wind       NA      NA  1.0000000 -0.4579879
Temp       NA      NA -0.4579879  1.0000000
> 
> # 결측값 있는 행 전체 삭제
> airquality_2 <- na.omit(airquality_1)
> str(airquality_2)
'data.frame':	111 obs. of  4 variables:
 $ Ozone  : int  41 36 12 18 23 19 8 16 11 14 ...
 $ Solar.R: int  190 118 149 313 299 99 19 256 290 274 ...
 $ Wind   : num  7.4 8 12.6 11.5 8.6 13.8 20.1 9.7 9.2 10.9 ...
 $ Temp   : int  67 72 74 62 65 59 61 69 66 68 ...
 - attr(*, "na.action")=Class 'omit'  Named int [1:42] 5 6 10 11 25 26 27 32 33 34 ...
  .. ..- attr(*, "names")= chr [1:42] "5" "6" "10" "11" ...
> sum(is.na(airquality_2$Ozone)) # 0
[1] 0
> sum(is.na(airquality_2$Solar.R)) # 0
[1] 0 

 

 

 

산점도 행렬의 대각선에 히스토그램을 추가하는 사용자 정의 함수입니다.  pairs() 도움말(help)에 나와있는 사용자 정의함수 그대로 가져왔습니다.  아래 사용자 정의 함수를 카피해서 사용하시기 바랍니다.

 

## put histograms on the diagonal
panel.hist <- function(x, ...)
{
  usr <- par("usr"); on.exit(par(usr))
  par(usr = c(usr[1:2], 0, 1.5) )
  h <- hist(x, plot = FALSE)
  breaks <- h$breaks; nB <- length(breaks)
  y <- h$counts; y <- y/max(y)
  rect(breaks[-nB], 0, breaks[-1], y, col = "cyan", ...)

 

# source: help(pairs)

 

 

 

다음으로 산점도 행렬의 위쪽에 상관계수 숫자를 집어넣는 사용자 정의 함수입니다.  이 또한 pairs() 도움말(help)에 나와있는 사용자 정의함수 그대로 가져왔습니다.  아래 사용자 정의 함수를 카피해서 사용하시기 바랍니다.

 

## put (absolute) correlations on the upper panels,
## with size proportional to the correlations.
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
  usr <- par("usr"); on.exit(par(usr))
  par(usr = c(0, 1, 0, 1))
  r <- abs(cor(x, y))
  txt <- format(c(r, 0.123456789), digits = digits)[1]
  txt <- paste0(prefix, txt)
  if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
  text(0.5, 0.5, txt, cex = cex.cor * r)

 

# source : help(pairs)

 

 

 

다음으로 산점도에 선형 회귀선을 추가하는 사용자 정의 함수입니다.  이는 R Graphics Cookbook (원스턴 챙 지음, 이제원 옮김)을 참조하였습니다.  아래 사용자 정의 함수를 카피해서 사용하시기 바랍니다.

 

## put linear regression line on the scatter plot
panel.lm <- function(x, y, col=par("col"), bg=NA, pch=par("pch"),
                     cex=1, col.smooth="black", ...) {
  points(x, y, pch=pch, col=col, bg=bg, cex=cex)
  abline(stats::lm(y~x), col=col.smooth, ...)

 

 

 

이제 준비가 다 되었습니다.  airquality의 4개 변수 간의 산점도 행렬, 상관계수 숫자, 히스토그램을 하나의 도표로 나타내보겠습니다.

 

> ## 산점도 행렬(scatter-plot matrix), 상관계수(correlation), 히스토그램(histogram) > pairs(airquality_2, + lower.panel = panel.lm, # 아래쪽 산점도에 선형 직선 추가 + upper.panel = panel.cor, # 위쪽에는 상관계수 숫자 (상관계수에 크기 비례) + diag.panel = panel.hist, # 대각선에는 히스토그램 + pch="*", # 점 모양은 * 로 + main = "scatter-plot matrix, correlation coef., histogram" + )

 

 

 

 

 

 

보너스로, pairs() 함수를 사용해서 범주(그룹)별로 점의 색깔을 달리하는 방법도 소개하겠습니다.  이 역시 pairs() 함수 도움말(help)에 있는 R script 를 가져왔습니다.  도움말(help)이 정말 도움이 많이 됩니다. ^^  사용한 데이터는 그 유명한 Iris 데이터가 되겠습니다.

 

> # 범주(그룹)을 색깔로 구분하여 산점도 행렬 그리기
> pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species",
+       pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)])

 

 

 * R script source : help(pairs)

 

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

 

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

 

728x90
반응형
Posted by Rfriend
,

다수의 변수간 상관관계를 파악하려고 할 때, 회귀분석에서 종속변수와 독립변수간 선형관계를 파악하거나 독립변수간 다중공선성을 파악하려고 할 때 사용하는 분석 기법이 상관계수 행렬이며, 시각화 방법이 산점도 행렬과 상관계수 행렬 Plot (correlation matrix plot) 입니다.

 

이전 포스팅에서 ggplot2의 geom_point() 산점도를 다루었으며,

 

다음 포스팅에서는 Base Graphics 패키지의 pairs() 함수를 사용한 산점도 행렬을 소개하였고,

 

이번 포스팅에서는 상관계수 행렬 Plot을 중심으로 해서 corrplot 패키지 사용법을 알아보겠습니다. 

 

 

예제로 사용한 데이터는 뉴욕의 1973년도 공기의 질을 측정한 airquality 데이터셋의 Ozone, Solar.R, Wind, Temp 4개의 변수가 되겠습니다.

 

 

> str(airquality)
'data.frame':	153 obs. of  6 variables:
 $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
 $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
 $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
 $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ...
 $ Month  : int  5 5 5 5 5 5 5 5 5 5 ...
 $ Day    : int  1 2 3 4 5 6 7 8 9 10 ...
> 

> # Month, Day는 빼기

> airquality_1 <- airquality[,c(1:4)]
> 
> str(airquality_1)
'data.frame':	153 obs. of  4 variables:
 $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
 $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
 $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
 $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ...

 

 

 

 

상관계수 분석을 할 때 결측값이 있으면 NA 값이 나오게 되므로 사전에 결측값 처리하는 것이 필요합니다.  Ozone과 Solar.R이 결측값이 각각 37개, 7개 있다보니 아래처럼 상관계수가 NA가 나왔습니다.

 

> # 결측값 확인
> sum(is.na(airquality_1$Ozone)) # 37
[1] 37
> sum(is.na(airquality_1$Solar.R)) # 7
[1] 7
> sum(is.na(airquality_1$Wind)) # 0
[1] 0
> sum(is.na(airquality_1$Temp)) # 0
[1] 0
> # 결측값 있는 상태에서 상관계수 계산했을 때
> cor(airquality_1)
        Ozone Solar.R       Wind       Temp
Ozone       1      NA         NA         NA
Solar.R    NA       1         NA         NA
Wind       NA      NA  1.0000000 -0.4579879
Temp       NA      NA -0.4579879  1.0000000

 

 

 

 

na.omit() 함수를 사용하여 결측값이 있는 행 전체를 삭제한 후에 상관계수를 구해보면 아래와 같습니다.  corrplot 패키지의 corrplot() 함수는 상관계수 행렬 데이터셋을 가지고 그래프를 그리므로 아래처럼 결측값을 제거한 후의 데이터셋을 가지고 미리 상관계수 행렬을 계산해두어야 합니다.

 

 

> # 결측값 있는 행 전체 삭제
> airquality_2 <- na.omit(airquality_1)
> str(airquality_2)
'data.frame':	111 obs. of  4 variables:
 $ Ozone  : int  41 36 12 18 23 19 8 16 11 14 ...
 $ Solar.R: int  190 118 149 313 299 99 19 256 290 274 ...
 $ Wind   : num  7.4 8 12.6 11.5 8.6 13.8 20.1 9.7 9.2 10.9 ...
 $ Temp   : int  67 72 74 62 65 59 61 69 66 68 ...
 - attr(*, "na.action")=Class 'omit'  Named int [1:42] 5 6 10 11 25 26 27 32 33 34 ...
  .. ..- attr(*, "names")= chr [1:42] "5" "6" "10" "11" ...
> sum(is.na(airquality_2$Ozone)) # 0
[1] 0
> sum(is.na(airquality_2$Solar.R)) # 0
[1] 0
> # 상관계수 계산
> airquality_cor <- cor(airquality_2)
> airquality_cor
             Ozone    Solar.R       Wind       Temp
Ozone    1.0000000  0.3483417 -0.6124966  0.6985414
Solar.R  0.3483417  1.0000000 -0.1271835  0.2940876
Wind    -0.6124966 -0.1271835  1.0000000 -0.4971897
Temp     0.6985414  0.2940876 -0.4971897  1.0000000
 

 

 

 

corrplot 패키지는 별도의 설치 및 호출이 필요한 패키지이므로 아래의 절차를 거칩니다.

 

> install.packages("corrplot")
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/corrplot_0.73.zip'
Content type 'application/zip' length 2680505 bytes (2.6 MB)
downloaded 2.6 MB

package ‘corrplot’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\user\AppData\Local\Temp\Rtmpk1gkRL\downloaded_packages
> library(corrplot) 

 

 

 

산점도 행렬 그림 (scatter matrix plot)을 복습해보자면 아래와 같습니다.

 

> # scatter plot matrix
> plot(airquality_2)

 

 

 

 

 

correlation plot의 method 에는 method = c("circle", "square", "ellipse", "number", "shade", "color", "pie") 등이 있으며, method별로 하나씩 예를 들어보겠습니다.

 

 

> corrplot(airquality_cor, method="circle")
 

 

 

> corrplot(airquality_cor, method="square")

 

 

 

  

> corrplot(airquality_cor, method="ellipse")

 

 

 

 

> corrplot(airquality_cor, method="number")

 

 

 

 

> corrplot(airquality_cor, method="shade")

 

 

 

 

> corrplot(airquality_cor, method="color")

 

 

 

 

> corrplot(airquality_cor, method="pie")

 

 

 

 

마지막으로 mehtod="shade", 상관관계 방향성 제시, 대각선 값 미제시, 상관계수 숫지 검정색으로 해서 추가해서 corrplot을 그려보겠습니다.  order 는 FPC(First Principle Component), hclust(hierarchical clustering), AOE(Angular Order of Engenvectors) 등이 있으며, 정렬 기준을 지정해주면 같은 색깔 끼리 뭉쳐서 보일 수 있도록 정렬을 시켜줘서 보기에, 해석하기에 더 좋게 보여줍니다.

 

> # corrplot
> corrplot(airquality_cor, 
+          method="shade", # 색 입힌 사각형
+          addshade="all", # 상관관계 방향선 제시
+          # shade.col=NA, # 상관관계 방향선 미제시
+          tl.col="red", # 라벨 색 지정
+          tl.srt=30, # 위쪽 라벨 회전 각도
+          diag=FALSE, # 대각선 값 미제시
+          addCoef.col="black", # 상관계수 숫자 색
+          order="FPC" # "FPC": First Principle Component
+                      # "hclust" : hierarchical clustering
+                      # "AOE" : Angular Order of Eigenvectors
+          )

 

 

 

 

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

 

-----------

 

(참고) pairs() 함수를 활용한 '산점도 행렬 + 상관계수 행렬 + 히스토그램' 그리기 ☞ http://rfriend.tistory.com/83

 

-----------

 

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

 

728x90
반응형
Posted by Rfriend
,

ggplot2로 막대그래프를 그렸는데 데이터가 양수와 음수로 구분이 되는 경우 그래프의 가독성을 높이기 위해서 양수냐, 음수냐에 따라 색상을 다르게 하고 싶을 때가 있습니다.

 

이번 포스팅에서는 R에 내장되어 있는 airquaility 데이터셋 (뉴욕의 1973년 5월~9월까지의 daily air quality measurements) 에서 5월달 온도(Temp) 만을 가져온 후에, 5월달 daily 온도의 1차 차분 데이터를 만들어서 막대그래프를 그려보도록 하겠습니다.

 

> str(airquality) 'data.frame': 153 obs. of 6 variables: $ Ozone : int 41 36 12 18 NA 28 23 19 8 NA ... $ Solar.R: int 190 118 149 313 NA NA 299 99 19 194 ... $ Wind : num 7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ... $ Temp : int 67 72 74 62 56 66 65 59 61 69 ... $ Month : int 5 5 5 5 5 5 5 5 5 5 ... $ Day : int 1 2 3 4 5 6 7 8 9 10 ... > sum(is.na(airquality$Temp)) [1] 0

>

> # 5월 온도만 선택
> May <- subset(airquality, select = c(Month, Day, Temp), subset = (Month == "5"))

>

 

 

온도의 1차 차분은 diff(변수, lag=차수) 함수를 사용합니다.  아래는 1차 차분을 하였으므로 5월1일은 빼고, 5월2일부터 5월31일까지의 날짜만 가져온 후에, 날짜와 온도 1차 차분한 값을 data frame으로 묶었습니다.  그 후에 ifelse() 함수를 사용해서 온도 1차 차분 값이 0 이상이면 "PLUS", 0 미만이면 "MINUS"라는 구분자 변수를 새로 생성하였습니다. 

 

> # 온도의 1차 차분
> May_Temp_Diff <- diff(May$Temp, lag=1)
> May_Temp_Diff
 [1]   5   2 -12  -6  10  -1  -6   2   8   5  -5  -3   2 -10   6   2  -9  11  -6  -3  14 -12   0  -4   1  -1  10  14  -2
[30]  -3
 
 

> # 5월2일 ~ 5월31일 날짜 변수 > May_Day <- May[c(2:31), c("Day")] > May_Day [1] 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 >

 

> May_Temp_Diff.df <- data.frame(May_Day, May_Temp_Diff) > May_Temp_Diff.df May_Day May_Temp_Diff 1 2 5 2 3 2 3 4 -12 4 5 -6 5 6 10 6 7 -1 7 8 -6 8 9 2 9 10 8 10 11 5 11 12 -5 12 13 -3 13 14 2 14 15 -10 15 16 6 16 17 2 17 18 -9 18 19 11 19 20 -6 20 21 -3 21 22 14 22 23 -12 23 24 0 24 25 -4 25 26 1 26 27 -1 27 28 10 28 29 14 29 30 -2 30 31 -3 >

> # 온도 차분 plus, minus 여부 구분자 변수 생성

> attach(May_Temp_Diff.df) > May_Temp_Diff.df$plus_minus <- ifelse(May_Temp_Diff >= 0, "PLUS", "MINUS") > May_Temp_Diff.df May_Day May_Temp_Diff plus_minus 1 2 5 PLUS 2 3 2 PLUS 3 4 -12 MINUS 4 5 -6 MINUS 5 6 10 PLUS 6 7 -1 MINUS 7 8 -6 MINUS 8 9 2 PLUS 9 10 8 PLUS 10 11 5 PLUS 11 12 -5 MINUS 12 13 -3 MINUS 13 14 2 PLUS 14 15 -10 MINUS 15 16 6 PLUS 16 17 2 PLUS 17 18 -9 MINUS 18 19 11 PLUS 19 20 -6 MINUS 20 21 -3 MINUS 21 22 14 PLUS 22 23 -12 MINUS 23 24 0 PLUS 24 25 -4 MINUS 25 26 1 PLUS 26 27 -1 MINUS 27 28 10 PLUS 28 29 14 PLUS 29 30 -2 MINUS 30 31 -3 MINUS 

 
> detach(May_Temp_Diff.df)

 

 

ggplot2 패키지는 사용자가 추가로 설치해야 합니다.  intall.packages()함수로 설치하고 library() 함수로 호출해보겠습니다.

 

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

 

 

 

이제 준비가 다 되었습니다.  1차 차분한 5월달의 온도에 대해서 양수(전날 보다 온도 상승)는 빨간색, 음수(전날보다 온도 하락)는 파란색으로 막대 그래프를 그려보겠습니다.  aes(fill=구분자 변수) 함수를 사용하고, 색깔지정은 scale_fill_manual(values=c(색깔1, 색깔2)) 로 지정해주면 됩니다.

 

> # 양수는 빨간색, 음수는 파란색으로 막대 색 구분
> ggplot(data=May_Temp_Diff.df, aes(x=May_Day, y=May_Temp_Diff, fill=plus_minus)) + 
+   geom_bar(stat="identity", position="identity", colour="white", width=0.2) + # width 막대 폭 좁게
+   scale_fill_manual(values=c("blue", "red"), guide=FALSE) + # guide=F 범례 생략
+   ggtitle("1st order differenced Temp of May")

 

 

 

 

 

 

막대 폭이 너무 가늘어서 보기 싫다면, 막대 폭을 좀더 넓히고 싶다면 geom_bar(width=숫자) 함수를 사용하면 됩니다.

 

> # width 막대 폭 넓게
> ggplot(data=May_Temp_Diff.df, aes(x=May_Day, y=May_Temp_Diff, fill=plus_minus)) + 
+   geom_bar(stat="identity", position="identity", colour="white", width=1) + # width 막대 폭 넓게 
+   scale_fill_manual(values=c("blue", "red"), guide=FALSE) + # guide=F 범례 생략
+   ggtitle("1st order differenced Temp of May")

 

 

 

 

 

다음으로, 위의 그래프에서 보면 ggplot2 가 알아서 x축을 10, 20, 30으로 해서 10일 간격으로 설정해서 그래프를 그렸는데요, 이를 좀더 세분화하고 싶다면 scale_x_continuous(breaks=c(숫자, 숫자...)) 로 지정해주면 됩니다.

 

> # x축 세분화
> ggplot(data=May_Temp_Diff.df, aes(x=May_Day, y=May_Temp_Diff, fill=plus_minus)) + 
+   geom_bar(stat="identity", position="identity", colour="white", width=0.5) + 
+   scale_fill_manual(values=c("blue", "red"), guide=FALSE) + 
+   ggtitle("1st order differenced Temp of May") + 
+   scale_x_continuous(breaks=c(5, 10, 15, 20, 25, 30)) # x축 세분화

 

 

 

 

 

마지막으로, x축과 y축의 라벨 이름이 위에 보면 변수명이 그래도 들어가 있는데요, 좀더 이해하기 쉽도록 xlab(), ylab() 함수를 추가하여 x축, y축 라벨을 변경해보도록 하겠습니다.

 

> # modification of x label, y label
> ggplot(data=May_Temp_Diff.df, aes(x=May_Day, y=May_Temp_Diff, fill=plus_minus)) + 
+   geom_bar(stat="identity", position="identity", colour="white", width=0.5) + 
+   scale_fill_manual(values=c("blue", "red"), guide=FALSE) + 
+   ggtitle("1st order differenced Temp of May") + 
+   scale_x_continuous(breaks=c(5, 10, 15, 20, 25, 30)) + 
+   xlab("Day of May, 1973") + 
+   ylab("Temp difference from previous day")

 

 

 

 

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

 

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

 

 

728x90
반응형
Posted by Rfriend
,

DB에 들어있는 데이터를 내렸을 때, 설문조사 데이터를 받았을 때, 원천 거래 데이터를 받았을 때, 혹은 분석 과정 중의 데이터 셋이 분석가가 하고자 하는 통계분석, 데이터마이닝 분석이나 ggplot2 등의 그래프/시각화를 위해 필요한 데이터 구조로 딱 맞아떨어지지 않는 경우가 굉장히 많습니다.

 

이때 필요한 것이 데이터를 분석 목적, 기법에 맞게 자유자재로 변형하여 재구조화하는 일입니다.  

 

엑셀에서 Pilvot Table 생성하는 것이 제일 이해하기 쉬운 예가 될거 같습니다.  세로로 길게 늘어서 있는 원 데이터를 가로와 세로로 틀을 잡아 주고, 가운데에는 value 값에 대해서 개수를 센다든지, 합계를 낸다든지, 평균을 구한다든지 하는 함수를 적용하는 것을 해보셨을 겁니다. 

 

비유를 해보자면, 레고블록으로 높이 세워진 탑을 모양과 색깔별로 레고 블록을 잘 분해한 다음에, 이를 재료로 해서 가로와 세로로 넓게 펴고 높이는 낮추어서 새로운 탑을 만드는 것이라고 생각해보는 것도 이해하는데 도움이 될거 같습니다.

 

이때 데이터 재구조화하는 기준 변수를 무엇으로 하느냐, 가로로 길게 늘어뜨릴 변수는 또 무엇으로 하느냐, 가운데에 값을 볼 때 무슨 함수를 사용해서 값을 계산해서 볼 것이냐에 따라서 다양한 경우의 수가 발생하게 됨에 따라 말로 모든 것을 설명하는 것이 무리가 있습니다.  따라서 아래에 reshape 패키지의 melt(), cast() 함수를 몇 가지 경우의 수에 적용해 보면서 원래 값이 이후에 어떻게 바뀌는지를 유심히 보시고, 필요한 상황에 맞는 R script를 참고하시면 되겠습니다.

 

 

[ reshape 패키지 내 melt()함수, cast() 함수 사용 데이터 재구조화 예시 ]

 

 

 

 

예제로 사용할 데이터는 MASS 패키지에 내장되어 있는 Cars93 데이터 프레임의 차종(Type), 제조국(Origin), 도시 연비(MPG.city), 고속도로 연비(MPG.highway) 4개의 변수를 사용해서 몇가지의 경우의 수를 조합해 가면서 데이터를 녹였다가 (melt) 재구조화 (cast) 를 해보겠습니다.

 

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

 

 

데이터 양이 너무 많으면 melt(), cast()를 적용했을 때 데이터 구조가 변화하는 모양을 보기가 쉽지 않기 때문에 차종(Type) 중에서 개수가 적은 "Compact"와 "Van" 만 선별해서 예제로 사용하겠습니다.

 

 

> table(Cars93$Type)

Compact   Large Midsize   Small  Sporty     Van 
     16      11      22      21      14       9 
> 
> Cars93_sample <- subset(Cars93, 
+                         select = c(Type, Origin, MPG.city, MPG.highway), 
+                         subset = (Type %in% c("Compact", "Van"))) 
> 
> Cars93_sample
      Type  Origin MPG.city MPG.highway
3  Compact non-USA       20          26
12 Compact     USA       25          36
13 Compact     USA       25          34
16     Van     USA       18          23
17     Van     USA       15          20
21 Compact     USA       23          28
25 Compact     USA       22          27
26     Van     USA       17          21
33 Compact     USA       22          27
36     Van     USA       15          20
43 Compact non-USA       24          31
55 Compact non-USA       26          34
56     Van non-USA       18          24
58 Compact non-USA       20          29
65 Compact non-USA       24          30
66     Van non-USA       17          23
68 Compact     USA       24          31
70     Van     USA       18          23
74 Compact     USA       23          31
78 Compact non-USA       20          26
82 Compact non-USA       23          30
87     Van non-USA       18          22
89     Van non-USA       17          21
90 Compact non-USA       21          30
92 Compact non-USA       21          28
> dim(Cars93_sample)
[1] 25  4

 

 



  reshape 패키지의 melt(), cast() 함수를 이용한 데이터 재구조화


 

R의 reshape 패키지는 별도의 설치가 필요합니다. 

 

# reshape package installation, library
> install.packages("reshape")

> library(reshape)

 

 

 

이제 melt(data, id.vars, measure.vars) 함수를 사용해서 기존 데이터셋을 녹여보도록 하겠습니다. 

 

> # melt()
> Cars93_sample_melt <- melt(data = Cars93_sample, 
+                            id.vars = c("Type", "Origin"), 
+                            measure.vars = c("MPG.city", "MPG.highway"))
> 
> Cars93_sample_melt
      Type  Origin    variable value
1  Compact non-USA    MPG.city    20
2  Compact     USA    MPG.city    25
3  Compact     USA    MPG.city    25
4      Van     USA    MPG.city    18
5      Van     USA    MPG.city    15
6  Compact     USA    MPG.city    23
7  Compact     USA    MPG.city    22
8      Van     USA    MPG.city    17
9  Compact     USA    MPG.city    22
10     Van     USA    MPG.city    15
11 Compact non-USA    MPG.city    24
12 Compact non-USA    MPG.city    26
13     Van non-USA    MPG.city    18
14 Compact non-USA    MPG.city    20
15 Compact non-USA    MPG.city    24
16     Van non-USA    MPG.city    17
17 Compact     USA    MPG.city    24
18     Van     USA    MPG.city    18
19 Compact     USA    MPG.city    23
20 Compact non-USA    MPG.city    20
21 Compact non-USA    MPG.city    23
22     Van non-USA    MPG.city    18
23     Van non-USA    MPG.city    17
24 Compact non-USA    MPG.city    21
25 Compact non-USA    MPG.city    21
26 Compact non-USA MPG.highway    26
27 Compact     USA MPG.highway    36
28 Compact     USA MPG.highway    34
29     Van     USA MPG.highway    23
30     Van     USA MPG.highway    20
31 Compact     USA MPG.highway    28
32 Compact     USA MPG.highway    27
33     Van     USA MPG.highway    21
34 Compact     USA MPG.highway    27
35     Van     USA MPG.highway    20
36 Compact non-USA MPG.highway    31
37 Compact non-USA MPG.highway    34
38     Van non-USA MPG.highway    24
39 Compact non-USA MPG.highway    29
40 Compact non-USA MPG.highway    30
41     Van non-USA MPG.highway    23
42 Compact     USA MPG.highway    31
43     Van     USA MPG.highway    23
44 Compact     USA MPG.highway    31
45 Compact non-USA MPG.highway    26
46 Compact non-USA MPG.highway    30
47     Van non-USA MPG.highway    22
48     Van non-USA MPG.highway    21
49 Compact non-USA MPG.highway    30
50 Compact non-USA MPG.highway    28
> dim(Cars93_sample_melt)
[1] 50  4

 

 

 

 

이렇게 melt()함수를 사용해 녹인 데이터를 cast()함수를 사용해서 재구조화 해보겠습니다.  세로와 가로에 무슨 변수를 넣을지가 결정되었다면 아래의 예제를 참고해서 원하는 구조에 맞게 R script를 작성하시면 되겠습니다. (말로 설명하기가 쉽지가 않습니다 ^^;) function 란에는 R에서 사용할 수 있는 통계량 함수를 사용하면 되며, 이번 예제에서는 평균(mean) 함수를 사용하였습니다. 

 

> # cast()
> options(digits=3) # 소숫점 너무 밑에 까지 나오지 않도록 설정
> 
> # 한개의 id.var 기준(세로) & variable(가로) 조합의 value 값에 mean 함수 적용
> cast(data = Cars93_sample_melt, Type ~ variable, fun = mean)
     Type MPG.city MPG.highway
1 Compact     22.7        29.9
2     Van     17.0        21.9 
> cast(data = Cars93_sample_melt, Origin ~ variable, fun = mean)
   Origin MPG.city MPG.highway
1     USA     20.6        26.8
2 non-USA     20.7        27.2
> 

 > # 두개의 id.var 기준(세로) & variable(가로) 조합의 value 값에 mean 함수 적용

> cast(data = Cars93_sample_melt, Type + Origin ~ variable, fun = mean)
     Type  Origin MPG.city MPG.highway
1 Compact     USA     23.4        30.6
2 Compact non-USA     22.1        29.3
3     Van     USA     16.6        21.4
4     Van non-USA     17.5        22.5
> 

 > # 한개의 id.var 기준(세로) & 다른 id.var + variable (가로) 조합의 value 값에 mean 함수 적용

> cast(data = Cars93_sample_melt, Type ~ Origin + variable, fun = mean)
     Type USA_MPG.city USA_MPG.highway non-USA_MPG.city non-USA_MPG.highway
1 Compact         23.4            30.6             22.1                29.3
2     Van         16.6            21.4             17.5                22.5
> cast(data = Cars93_sample_melt, Origin ~ Type + variable, fun = mean)
   Origin Compact_MPG.city Compact_MPG.highway Van_MPG.city Van_MPG.highway
1     USA             23.4                30.6         16.6            21.4
2 non-USA             22.1                29.3         17.5            22.5
> 

 > # 한개의 id.var + variable (세로) & 다른 id.var (가로) 조합의 value 값에 mean 함수 적용

> cast(data = Cars93_sample_melt, Type + variable ~ Origin, fun = mean)
     Type    variable  USA non-USA
1 Compact    MPG.city 23.4    22.1
2 Compact MPG.highway 30.6    29.3
3     Van    MPG.city 16.6    17.5
4     Van MPG.highway 21.4    22.5

 > cast(data = Cars93_sample_melt, Origin + variable ~ Type, fun = mean)

   Origin    variable Compact  Van
1     USA    MPG.city    23.4 16.6
2     USA MPG.highway    30.6 21.4
3 non-USA    MPG.city    22.1 17.5
4 non-USA MPG.highway    29.3 22.5

 

 

 


  reshape2 패키지의 acast() 함수를 이용한 데이터 재구조화



> library(gcookbook)

> data(cabbage_exp)

> cabbage_exp

  Cultivar Date Weight        sd  n         se

1      c39  d16   3.18 0.9566144 10 0.30250803

2      c39  d20   2.80 0.2788867 10 0.08819171

3      c39  d21   2.74 0.9834181 10 0.31098410

4      c52  d16   2.26 0.4452215 10 0.14079141

5      c52  d20   3.11 0.7908505 10 0.25008887

6      c52  d21   1.47 0.2110819 10 0.06674995

> #install.packages("reshape2")

> library(reshape2)

> cabbage_exp_cast <- acast(data = cabbage_exp

+                           , Cultivar ~ Date

+                           , value.var = 'Weight'

+                           , fun.aggregate = mean

+                           #, fill = 0 # if you want to fill the missing value with '0'

+                           , drop = TRUE)

> cabbage_exp_cast

     d16  d20  d21

c39 3.18 2.80 2.74

c52 2.26 3.11 1.47

 




  tidyverse 패키지의 spread() 함수를 이용한 데이터 재구조화



> # load data

> library(gcookbook)

> data(cabbage_exp)

> cabbage_exp

  Cultivar Date Weight        sd  n         se

1      c39  d16   3.18 0.9566144 10 0.30250803

2      c39  d20   2.80 0.2788867 10 0.08819171

3      c39  d21   2.74 0.9834181 10 0.31098410

4      c52  d16   2.26 0.4452215 10 0.14079141

5      c52  d20   3.11 0.7908505 10 0.25008887

6      c52  d21   1.47 0.2110819 10 0.06674995

> # reshape data using tidyverse

> library(tidyverse)

> # melt first (long format)

> cabbage_exp_melt <- cabbage_exp %>% 

+   group_by(Cultivar, Date) %>%

+   summarise(Weight = mean(Weight))

> # cast second (wide format)

> cabbage_exp_cast <- spread(cabbage_exp_melt, key = c("Date"), value = "Weight", fill = 0)

> print(cabbage_exp_cast)

# A tibble: 2 x 4

# Groups:   Cultivar [2]

  Cultivar   d16   d20   d21

  <fct>    <dbl> <dbl> <dbl>

1 c39       3.18  2.8   2.74

2 c52       2.26  3.11  1.47

 


 

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

 

728x90
반응형
Posted by Rfriend
,

거래 원 데이터 (transaction raw data)를 받으면 분석 용도에 맞게 데이터 전처리를 할 때 보통 하는 일이 특정 기준 (가령, 고객 ID, 상품 ID, 채널 ID 등)에 대해 데이터를 집계(합계, 평균, 분산 등의 함수를 적용)하는 작업을 하게 됩니다. 

 

R에는 aggregate() 라는 함수가 있습니다만, 기존에 SQL에 익숙한 분석가라면 R 에서 SQL 문을 사용할 수 있게 해주는 sqldf package를 사용하면 쉽고 빠르게 집계를 할 수 있겠습니다. 

 

(단, sqldf 가 performance 이슈가 있으니 데이터 사이즈가 크다면, 그리고 데이터 처리 속도가 중요한 경우라면 sqldf 는 부적할 수도 있다는 점은 고려하셔야 겠습니다.)

 

R sqldf package 소개자료에 보면

  - Perform SQL Selects on R Data Frames
  - Manipulate R data frames using SQL

이라고 되어 있습니다.

 

 

 

 

그럼, sqldf package의 여러 기능, 함수 중에서 데이터 집계 관련한 함수만 몇 가지 선별하여서 소개하도록 하겠습니다.

 

실습에 사용할 데이터는 MASS 패키지에 내장된 Cars93 데이터 프레임의 자동차 유형(Type), 도시 연비(MPG.city), 고속도로 연비(MPG.highway) 를 사용하겠습니다.

 

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

 

 

 

R의 aggregate() 함수로 차종(Type)별 도시 연비(MPG.city)와 고속도로 연비(MPG.highway)의 평균을 구해보겠습니다. 

 

> # aggregate

> R_aggregate_mean <- aggregate(Cars93[,c(7,8)], + by = list(Car_Type = Cars93$Type), # list + FUN = mean, # function + na.rm = TRUE)

> > R_aggregate_mean Car_Type MPG.city MPG.highway 1 Compact 22.68750 29.87500 2 Large 18.36364 26.72727 3 Midsize 19.54545 26.72727 4 Small 29.85714 35.47619 5 Sporty 21.78571 28.78571 6 Van 17.00000 21.88889 

 

 

 

 

이번에는 install.packages()함수와 library()함수를 사용하여 sqldf Package 를 설치하고 호출한 후에, sqldf 패키지를 사용하여 위와 같이 차종(Type)별 도시 연비(MPG.city)와 고속도로 연비(MPG.highway)의 평균을 구해보겠습니다.

 

> install.packages("sqldf")
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/sqldf_0.4-10.zip'
Content type 'application/zip' length 71825 bytes (70 KB)
downloaded 70 KB

package ‘sqldf’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\user\AppData\Local\Temp\Rtmp4i7Dhq\downloaded_packages
> library(sqldf)
필요한 패키지를 로딩중입니다: gsubfn
필요한 패키지를 로딩중입니다: proto
필요한 패키지를 로딩중입니다: RSQLite
필요한 패키지를 로딩중입니다: DBI
Warning messages:
1: 패키지 ‘sqldf’는 R 버전 3.2.2에서 작성되었습니다 
2: 패키지 ‘gsubfn’는 R 버전 3.2.2에서 작성되었습니다 
3: 패키지 ‘RSQLite’는 R 버전 3.2.2에서 작성되었습니다 
4: 패키지 ‘DBI’는 R 버전 3.2.2에서 작성되었습니다 

 

> R_sqldf_1 <- sqldf('
+                  select "Type" as "Car_Type", 
+                  avg("MPG.city") as "mean_MPG.city", 
+                  avg("MPG.highway") as "mean_MPG.highway"  
+                  from Cars93 
+                  group by Type
+                  order by Type
+                  ')
> R_sqldf_1
  Car_Type mean_MPG.city mean_MPG.highway
1  Compact      22.68750         29.87500
2    Large      18.36364         26.72727
3  Midsize      19.54545         26.72727
4    Small      29.85714         35.47619
5   Sporty      21.78571         28.78571
6      Van      17.00000         21.88889

 

 

R의 aggregate()함수로 만든 평균과 sqldf로 만든 평균 데이터 셋을 차종(Type) 을 key로 항 merge 한 후에 두 값들이 서로 같은지 한번 점검해보겠습니다.

 

> # 두개 데이터 셋 Merge, 동일 여부 check
> Type_mean <- merge(R_aggregate_mean, R_sqldf_1, by = 'Car_Type')
> Type_mean <- transform(Type_mean, 
+                        gap_MPG.city = MPG.city - mean_MPG.city, 
+                        gap_MPG.highway = MPG.highway - mean_MPG.highway)
> 
> Type_mean
  Car_Type MPG.city MPG.highway mean_MPG.city mean_MPG.highway gap_MPG.city gap_MPG.highway
1  Compact 22.68750    29.87500      22.68750         29.87500            0               0
2    Large 18.36364    26.72727      18.36364         26.72727            0               0
3  Midsize 19.54545    26.72727      19.54545         26.72727            0               0
4    Small 29.85714    35.47619      29.85714         35.47619            0               0
5   Sporty 21.78571    28.78571      21.78571         28.78571            0               0
6      Van 17.00000    21.88889      17.00000         21.88889            0               0

 

얼핏 보면 R의 aggregate() 함수와 sqldf 가 서로 큰 차이가 없거나 혹은 aggregate()함수가 더 편하다고 느낄 수도 있겠습니다.  그런데, 아래의 경우처럼 다수의 함수들(count, sum, avg, variance, stdev, min, max 등)을 그룹 변수에 대해서 구분해서 집계를 할 경우에는, 그리고 SQL에 익숙한 사용자라면 sqldf 패키지를 사용하는게 편할 수 있을 것입니다 

 

 

> # SQL의 aggregation 함수 사용하기
> R_sqldf_2 <- sqldf('
+                    select "Type" as "Car_Type", 
+                    count("MPG.city") as "count_MPG.city", 
+                    sum("MPG.city") as "sum_MPG.city", 
+                    
+                    avg("MPG.city") as "mean_MPG.city", 
+                    variance("MPG.city") as "variance_MPG.city", 
+                    stdev("MPG.city") as "stdev_MPG.city", 
+                    
+                    min("MPG.city") as "min_MPG.city", 
+ 
+                    max("MPG.city") as "max_MPG.city"
+                    
+                    from Cars93 
+                    group by Type
+                    order by Type desc
+                    ')
> 
> # count :  행의 개수
> # sum : 합계
> # avg : 평균
> # var : 분산
> # stddev : 표준편차
> # min : 최소값
> # max : 최대값
> # order by xx desc : 내림차순 정렬
> 
> R_sqldf_2
  Car_Type count_MPG.city sum_MPG.city mean_MPG.city variance_MPG.city stdev_MPG.city min_MPG.city max_MPG.city
1      Van              9          153      17.00000          1.500000       1.224745           15           18
2   Sporty             14          305      21.78571         15.258242       3.906180           17           30
3    Small             21          627      29.85714         37.328571       6.109711           22           46
4  Midsize             22          430      19.54545          3.593074       1.895540           16           23
5    Large             11          202      18.36364          2.254545       1.501514           16           20
6  Compact             16          363      22.68750          3.695833       1.922455           20           26

 

 

변수명을 SQL 문 내에서 바로 부여하는 것도 편리합니다.  그리고 SQL에 능숙한 분석가라면 subquery를 사용해서 한방에 query를 다 돌려서 원하는 데이터셋을 만들어낼 수도 있겠습니다.  (단, sqldf는 속도는 희생될 수 있음)

 

 

그렇다고 sqldf가 데이터 집계를 하는데 있어 모든 통계량을 다 한번에 할 수 있는것은 아닙니다.  R에서는 아래 처럼 median, quantile 을 1줄만에 처리할 수 있는 반면에, 이것과 동일한 결과를 얻으려면 SQL로는 참 어렵습니다.

 

> # R로 median, quantile 지정해서 구하기
> R_aggregate_median <- aggregate(Cars93[,c(7,8)], by = list(Car_Type = Cars93$Type), FUN = median)
> R_aggregate_median
  Car_Type MPG.city MPG.highway
1  Compact     23.0        30.0
2    Large     19.0        26.0
3  Midsize     19.0        26.5
4    Small     29.0        33.0
5   Sporty     22.5        28.5
6      Van     17.0        22.0
> 
> quantile_MPG.city <- quantile(Cars93[,c("MPG.city")], c(0, .01, .05, .1, .25, .5, .75, .9, .95, .99, 1))
> quantile_MPG.city
   0%    1%    5%   10%   25%   50%   75%   90%   95%   99%  100% 
15.00 15.00 16.60 17.00 18.00 21.00 25.00 29.00 31.40 42.32 46.00

 

sqldf 가 편하다고 했다가, 그냥 R 함수가 편하다가 했다가 오락가락 하는 것처럼 보일 수도 있겠는데요, 위의 예제를 보시고 데이터 전처리, 분석의 목적, 상황에 맞게 sqldf와 aggregate() 함수, R 함수를 선별해서 사용하시면 되겠습니다.

 

 

{dplyr} package의 summarise(n = n()), tally(), count() 함수를 사용한 집계 방법은 http://rfriend.tistory.com/240  포스팅을 참고하세요.

 

 

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

 

728x90
반응형
Posted by Rfriend
,

시간의 흐름에 따른 그룹/집단 별 관측값 혹은 비율의 변화를 누적해서 볼 수 있는 그래프가 누적 영역 그래프 (Stacked Area Plot) 입니다.   아마 엑셀에서 많이 보았을 법한 그래프 일것이라고 생각합니다.

 

2007년부터 2014년까지의 한국 수/출입 무역량 (단위: 1 B$) 데이터를 가지고 수출과 수입으로 구분하여서 ggplot2의 geom_area() 함수를 사용하여 누적 영역 그래프(Stacked Area Plot) 를 그려보도록 하겠습니다.

 

아래는 2007년부터 2014년까지의 한국 수/출입 무역량 (단위: 1 B$) 데이터를 링크해두었습니다.

(☞ 한국 수/출입 무역량 데이터 다운로드  trade_stat_07_14.csv)

* 출처 : 국가무역통계 KOSIS, http://kosis.kr/statisticsList/statisticsList_01List.jsp?vwcd=MT_ZTITLE&parmTabId=M_01_01#SubCont)

 

그래프를 그리기에 딱 맞는 형식이 아니므로 csv 데이터를 불러들인 다음에

 -> sqldf 패키지를 활용해 Year 단위로 수출입 실적을 집계

 -> 이때 단위를 1000$ -> 1B$ 로 바꿔주기 위해 1,000,000 으로 나눠줌

을써 데이터를 필요에 맞게 집계해보겠습니다.

 

> trade_stat <- read.csv("C:/Users/user/Documents/R/trade_stat_07_14.csv", # 경로 설정 + header = TRUE) > > > trade_stat <- transform(trade_stat, Year = substr(Time, 1, 4)) > > sapply(trade_stat, class) Time export_amt import_amt Year "numeric" "integer" "integer" "factor" > > library(sqldf) > # 한국 수/출입 무역금액, 단위: 1B$ > trade_stat_Year <- sqldf('select Year, + sum(export_amt)/100000 as exp_amt_Year, + sum(import_amt)/100000 as imp_amt_Year + from trade_stat + group by Year + order by Year + ') > trade_stat_Year Year exp_amt_Year imp_amt_Year 1 2007 3714 3568 2 2008 4220 4352 3 2009 3635 3230 4 2010 4663 4252 5 2011 5552 5244 6 2012 5478 5195 7 2013 5596 5155 8 2014 5726 5255

 

 

 

여기까지 했는데도 누적 영역 그래프를 그리기에 딱 맞는 데이터 형태가 아니라서 reshape 패키지의 melt() 함수를 사용하여 데이터를 현재의 가로로 늘어져있는 exp_amt_Year, imp_amt_Year 변수를 -> 세로로 세워서 데이터 구조를 변경해보겠습니다.

 

그 다음에 variable -> trade_cd (수입, 수출 구분 코드), value -> amount_B (무역금액, 단위 : 1B$) 로 변수명을 변경하였습니다.

 

> # 데이터 구조 녹이기(melt) - 세로로 세우기
> library(reshape)
> trade_stat_Year_melt <- melt(trade_stat_Year, idvars = c("Year"))
Using Year as id variables
> trade_stat_Year_melt
   Year     variable value
1  2007 exp_amt_Year  3714
2  2008 exp_amt_Year  4220
3  2009 exp_amt_Year  3635
4  2010 exp_amt_Year  4663
5  2011 exp_amt_Year  5552
6  2012 exp_amt_Year  5478
7  2013 exp_amt_Year  5596
8  2014 exp_amt_Year  5726
9  2007 imp_amt_Year  3568
10 2008 imp_amt_Year  4352
11 2009 imp_amt_Year  3230
12 2010 imp_amt_Year  4252
13 2011 imp_amt_Year  5244
14 2012 imp_amt_Year  5195
15 2013 imp_amt_Year  5155
16 2014 imp_amt_Year  5255
> 
> # 변수명 변경
> trade_stat_Year_melt <- rename(trade_stat_Year_melt, c(variable="trade_cd", value="amount_B"))
> trade_stat_Year_melt
   Year     trade_cd amount_B
1  2007 exp_amt_Year     3714
2  2008 exp_amt_Year     4220
3  2009 exp_amt_Year     3635
4  2010 exp_amt_Year     4663
5  2011 exp_amt_Year     5552
6  2012 exp_amt_Year     5478
7  2013 exp_amt_Year     5596
8  2014 exp_amt_Year     5726
9  2007 imp_amt_Year     3568
10 2008 imp_amt_Year     4352
11 2009 imp_amt_Year     3230
12 2010 imp_amt_Year     4252
13 2011 imp_amt_Year     5244
14 2012 imp_amt_Year     5195
15 2013 imp_amt_Year     5155
16 2014 imp_amt_Year     5255

 

 

 

이제 드디어 누적 영역 그래프를 그릴 데이터 셋 준비가 다 되었군요.  ggplot2의 geom_area() 함수를 사용하여 우선 값 기준으로 그리고, 다음으로 비율 기준으로도 그려보겠습니다.

 

geom_area(colour=NA)로 하고 geom_line(position="stack")으로 해서 양 옆에 선은 트여주고, 영역 간 경계선은 그려주었습니다.

 

> # 누적 영역 그래프 그리기
> ggplot(trade_stat_Year_melt, aes(x=Year, y=amount_B, fill=trade_cd, group=trade_cd)) +
+   geom_area(colour=NA, alpha=0.5) + # alpha 투명도
+   scale_fill_brewer(palette="Blues") +
+   geom_line(position="stack", size=0.3) + 
+   ggtitle("Stacked Area Plot of Trade (Import, Export) from 2007 to 2014")
ymax not defined: adjusting position using y instead
 

 

 

 

aes(arder=desc()) 를 사용하여 위의 영역 구분 그룹의 순서를 바꿀 수도 있습니다.  위의 예제에서는 exp_amt_Year (수출액)이 아래에 위치했습니다만, 아래 예제에서는 exp_amt_Year(수출액)이 위로 위치가 바뀌었음을 알 수 있습니다.

 

> # 누적 영역 순서 바꾸기
> library(plyr) # desc() 함수 사용 위해 필요
> ggplot(trade_stat_Year_melt, aes(x=Year, y=amount_B, fill=trade_cd, group=trade_cd, 
+                                  order=desc(trade_cd))) + # 누적 영역 순서 내림차순 정렬
+   geom_area(colour=NA, alpha=0.5) + # alpha 투명도
+   scale_fill_brewer(palette="Blues") +
+   geom_line(position="stack", size=0.3) + 
+   ggtitle("Stacked Area Plot of Trade (Import, Export) from 2007 to 2014")
ymax not defined: adjusting position using y instead

 

 

 

 

 

 


 

 

이번에는 비율 기준으로 해서 누적 영역 그래프를 그려보겠습니다.  이를 위해서는 데이터셋에서 Year 별로 비율을 계산해주어야 합니다.  데이터 프레임에서 사칙연산을 써가면서 transform() 함수로 step-by-step 해나갈 수도 있는데요, plyr패키지의 ddply() 함수를 사용하면 놀랍도록 간편하게 원하는 비율 값을 구할 수 있습니다.

 

> #-----
> # 비율 누적 영역 그래프 그리기
> # 비율 계산하기
> library(plyr)
> 
> trade_stat_Year_melt_prop <- ddply(trade_stat_Year_melt, 
+                                    "Year", transform, 
+                                    trade_prop = round(100*amount_B/sum(amount_B),1))
> 
> trade_stat_Year_melt_prop
   Year     trade_cd amount_B trade_prop
1  2007 exp_amt_Year     3714       51.0
2  2007 imp_amt_Year     3568       49.0
3  2008 exp_amt_Year     4220       49.2
4  2008 imp_amt_Year     4352       50.8
5  2009 exp_amt_Year     3635       52.9
6  2009 imp_amt_Year     3230       47.1
7  2010 exp_amt_Year     4663       52.3
8  2010 imp_amt_Year     4252       47.7
9  2011 exp_amt_Year     5552       51.4
10 2011 imp_amt_Year     5244       48.6
11 2012 exp_amt_Year     5478       51.3
12 2012 imp_amt_Year     5195       48.7
13 2013 exp_amt_Year     5596       52.1
14 2013 imp_amt_Year     5155       47.9
15 2014 exp_amt_Year     5726       52.1
16 2014 imp_amt_Year     5255       47.9

 

 

 

 

위의 trade_prop 변수를 활용해서 비율 누적 영역 그래프(Propostion stacked area plot)을 그려보도록 하겠습니다.  값을 기준으로 했을 때와 script는 동일하며, y값 자리에 trade_prop (수출입 무역 비율) 변수로 바꾸어주기만 하면 됩니다.

 

그래프 뒤에 단위 격자가 보이도록 geom_area(alpha=0.5) 로 해서 약간 투명하게 처리했습니다.

 

> # 비율 누적 영역 그래프 그리기
> library(plyr) # desc() 함수 사용 위해 필요
> ggplot(trade_stat_Year_melt_prop, aes(x=Year, y=trade_prop, fill=trade_cd, group=trade_cd, 
+                                  order=desc(trade_cd))) + # 누적 영역 순서 내림차순 정렬
+   geom_area(colour=NA, alpha=0.5) + # alpha 투명도
+   scale_fill_brewer(palette="Blues") +
+   geom_line(position="stack", size=0.3) + 
+   ggtitle("Stacked Area Plot of Trade Proportion (Import, Export) from 2007 to 2014")
ymax not defined: adjusting position using y instead

 

 

 

 

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

 

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

 

 

728x90
반응형
Posted by Rfriend
,

예전 포스팅 중에서 일변량 연속형 변수에 대해 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를 같은 그래프에 그리는데, 만약 이것을 막대 그래프로 그린다고 상상해 보세요.  막대그래프로 그린다면 지저분하고 해석, 가독성이 클리브랜드 점 그래프 대비 떨어질겁니다. 

 

Python 의 Plotly 모듈을 사용해서 클리브랜드 점 그래프 (Cleveland Dot Plot in Python using Plotly) 그리는 방법은 https://rfriend.tistory.com/802 를 참고하세요. 

 


 

[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

 

 

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

 

728x90
반응형
Posted by Rfriend
,

 

2개의 연속형 변수를 가지고 그릴 수 있는 그래프 중에 이차원 밀도 그래프 (2D Density Plot) 을 ggplot2의 stat_density2d() 함수를 이용하여 그려보겠습니다. 

 

 

이차원 밀도 그래프 (2D Density Plot)은 2D 커널 밀도 추정치를 구해서 같은 추정치를 선으로 연결한 그래프 입니다. 

 

 

우리가 일상 생활 중에 자주 쉽게 접하는 이차원 밀도 그래프의 예로는 지도의 등고선이나 일기예보할 때 쓰는 등압선이 있습니다.

 

 

[ 기상청 등압선 얘시 ]

 

 

* 출처: 기상청, http://www.kma.go.kr/weather/images/analysischart.jsp

 

 

이번에 R로 예를 들  데이터는 뉴욕의 기상을 19 73년 5월부터 9월까지 매일 측정한 airquality 데이터 프레임에서 5월달과 7월달 두 달의 Wind, Temp를 사용하겠습니다.

 

(airquality는 시계열 데이터이고, 이전 포스팅에서 airquality 데이터 프레임을 사용하여 ggplot2로 시계열 그래프 그래프 그리는 법 설명하였으니 참고하시기 바랍니다)

 

먼저, airquality의 데이터 구조를 살펴보고, 5월달과 7월달 데이터만 선별해서 새로운 데이터 프레임을 만들어보겠습니다.

 

 

> # airquality 구조
> str(airquality)
'data.frame':	153 obs. of  6 variables:
 $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
 $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
 $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
 $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ...
 $ Month  : int  5 5 5 5 5 5 5 5 5 5 ...
 $ Day    : int  1 2 3 4 5 6 7 8 9 10 ...
> 
> # 5월과 7월만 선택
> airquality_May_July <- subset(airquality, 
+                               select = c(Month, Day, Wind, Temp), 
+                               subset = (Month %in% c(5, 7)))
 
>
>
> head(airquality_May_July)
  Month Day Wind Temp
1     5   1  7.4   67
2     5   2  8.0   72
3     5   3 12.6   74
4     5   4 11.5   62
5     5   5 14.3   56
6     5   6 14.9   66
>
>
> tail(airquality_May_July)
   Month Day Wind Temp
87     7  26  8.6   82
88     7  27 12.0   86
89     7  28  7.4   88
90     7  29  7.4   86
91     7  30  7.4   83
92     7  31  9.2   81

 

 

 

이제 이차원 밀도 그래프 (2D Density Plot)을 그려보겠습니다.  그리고 5월과 7월달의 Month를 색깔로 구분하여 보겠습니다.

 

이때 조심해야 할 것이 있습니다.  aes() 에 shape이나 colour 에는 범주형변수(factor)가 들어가야 합니다.  만약 연속형 변수가 들어가면  "Error: A continuous variable can not be mapped to shape" 라는 에러 메시지가 뜹니다.

 

> # 2차원 밀도 그래프 : 모양과 색깔로 구분
> # 연속형 변수라서 error
> ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, shape=Month)) +
+   geom_point() + 
+   stat_density2d() +
+   ggtitle("2D desity plot of Wind and Tmep, at May and July")
Error: A continuous variable can not be mapped to shape

 

 

 

Month를 Month.ch라는 새로운 문자형 변수로 변환해, 이를 사용해서 이차원 밀도 그래프를 Month별로 모양과 색깔을 구분해서 그려보겠습니다.  

 

> # Month를 문자형 변수로 변환
> airquality_May_July <- transform(airquality_May_July, Month.ch = as.character(Month))
> 
> sapply(airquality_May_July, class)
      Month         Day        Wind        Temp    Month.ch 
  "integer"   "integer"   "numeric"   "integer" "character"
> 
> head(airquality_May_July)
  Month Day Wind Temp Month.ch
1     5   1  7.4   67        5
2     5   2  8.0   72        5
3     5   3 12.6   74        5
4     5   4 11.5   62        5
5     5   5 14.3   56        5
6     5   6 14.9   66        5

 

 

 

stat_density2d() 함수로 커널 밀도 추정치를 계산해서 2차원 밀도 그래프를 그리면,

 

> # 2차원 밀도 그래프 : Month를 모양으로 구분
> ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, shape=Month.ch)) +
+   geom_point(size=4) + 
+   stat_density2d() +
+   ggtitle("2D desity plot of Wind and Tmep, May/July by Shape")
> 

 

 


 

> # 2차원 밀도 그래프 : Month를 색깔로 구분 > ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, colour=Month.ch)) + + geom_point(size=4) + + stat_density2d() + + ggtitle("2D desity plot of Wind and Tmep, at May/July by Colour")

 

 

 

 

 

 

 

 

이번에는 (범례가 있기는 합니다만) 사용자의 가독성을 조금 더 높여주기 위해 2차원 밀도 그래프의 5월, 7월 두 집단의 중앙 부위에 년/월을 annotate()의 "text"로 라벨을 추가해 보겠습니다.

 

> # 2차원 밀도 그래프 : Month를 색깔로 구분, 년/월 라벨 추가
> ggplot(data=airquality_May_July, aes(x=Wind, y=Temp, colour=Month.ch)) +
+   geom_point(size=4) + 
+   stat_density2d() +
+   ggtitle("2D desity plot of Wind and Tmep, at1973. May/July by Colour") +
+   annotate("text", x=11, y=65, label="1973.May", alpha=0.5) + 
+   annotate("text", x=9, y= 83, label="1973.July", alpha=0.5)

 

 

 

 

 

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

 

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

 

728x90
반응형
Posted by Rfriend
,