13.4 이차원 밀도 그래프

연속형 데이터를 시각화할 수 있는 방법 중의 하나가 이차원 밀도 그래프 (2D Density Plot) 입니다. ggplot2 패키지에서는 stat_density2d() 함수를 이용하여 이 그래프를 그릴 수 있습니다.

이차원 밀도 그래프 (2D Density Plot)은 2차원 커널 밀도 추정치를 구하여 이를 선으로 연결한 그래프 입니다. 우리가 일상 생활 중에 자주 쉽게 접하는 이차원 밀도 그래프로는 지도의 등고선이나 일기예보등압선 등이 있습니다.

13.4.1 데이터 세트

이번 절에서 사용할 데이터는 뉴욕의 기상을 1973년 5월부터 9월까지 매일 측정한 airquality 데이터 세트로 5월과 7월의 두 달의 Wind, Temp를 사용하겠습니다. (airquality는 시계열 데이터이고, 이전 절에서 airquality 데이터 세트를 사용하여 ggplot2로 (시계열 그래프를 그리는 방법)선 그래프와 시계열 그래프을 설명한 바 있으니 참고하시기 바랍니다)

먼저, airquality 데이터 세트의 데이터 구조를 살펴보겠습니다.

library(ggplot2)

# airquality 구조 
str(airquality)
## 'data.frame':    153 obs. of  11 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        : Factor w/ 5 levels "5","6","7","8",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ Day          : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Month.ch_temp: chr  "5" "5" "5" "5" ...
##  $ Day.ch_temp  : chr  "1" "2" "3" "4" ...
##  $ Month.ch     : chr  "05" "05" "05" "05" ...
##  $ Day.ch       : chr  "01" "02" "03" "04" ...
##  $ Time         : Date, format: "2021-05-01" "2021-05-02" ...

5월과 7월의 데이터만 선별해서 새로운 데이터 세트를 만들어 보겠습니다.

# 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

13.4.2 기본 2차원 밀도 그래프

13.4.2.1 기본 2차원 밀도 그래프

stat_density2d() 함수를 이용하여 WindTemp 데이터로 부터 2차원 커널 밀도 추청을 합니다. 그리고 이를 이용하여 데이터 포인트들에 대한 기본 2차원 밀도 그래프를 작성하면 다음과 같습니다.

air_basic <- ggplot(airquality_May_July, 
                    aes(x = Wind, 
                        y = Temp))
air_basic + 
  stat_density2d() +
  ggtitle("기본 2차원 밀도 그래프 1")
기본 2차원 밀도 그래프 1

Figure 13.33: 기본 2차원 밀도 그래프 1

Go Top

13.4.2.2 데이터 포인트 표시하기

기본 2차원 밀도 그래프에 geom_point() 함수를 이용하여 데이터를 점으로 표시할 수 있습니다.

air_basic <- ggplot(airquality_May_July, 
                    aes(x = Wind, 
                        y = Temp))
air_basic + 
  stat_density2d() +
  geom_point() +
  ggtitle("기본 2차원 밀도 그래프 2")
기본 2차원 밀도 그래프 2

Figure 13.34: 기본 2차원 밀도 그래프 2

Go Top

13.4.2.3 등고선 높이 표시

한편 등고선의 높이(height)..level.. 을 이용하여 등고선의 색으로 다음과 같이 표현할 수도 있습니다.

air_basic +
  stat_density2d(aes(colour = ..level..)) +
  ggtitle("기본 2차원 밀도 그래프 : 등고선 높이 표시")
기본 2차원 밀도 그래프 : 등고선 높이 표시

Figure 13.35: 기본 2차원 밀도 그래프 : 등고선 높이 표시

Go Top

13.4.2.4 ..density..의 이용

fill = 모수에서 ..density..를 다음과 같이 매핑할 수 있습니다.

air_basic +
  stat_density2d(aes(fill = ..density..),
                 geom = "raster",
                 contour = FALSE) +
  ggtitle("기본 2차원 밀도 그래프 : ..density..의 이용 1")
기본 2차원 밀도 그래프 : ..density..의 이용 1

Figure 13.36: 기본 2차원 밀도 그래프 : ..density..의 이용 1

alpha = 모수에서 ..density..를 다음과 같이 매핑할 수 있습니다.

air_basic +
  geom_point() +
  stat_density2d(aes(alpha = ..density..),
                 geom = "tile",
                 contour = FALSE) +
  ggtitle("기본 2차원 밀도 그래프 : ..density..의 이용 2")
기본 2차원 밀도 그래프 : ..density..의 이용 2

Figure 13.37: 기본 2차원 밀도 그래프 : ..density..의 이용 2

Go Top

13.4.2.5 geom_density2d_filled() 함수

geom_density2d_filled() 함수를 이용할 수도 있습니다.

air_basic +
  geom_point() + 
  geom_density2d_filled(alpha = 0.5) +
  ggtitle("기본 2차원 밀도 그래프 : geom_density2d_filled() 함수 이용")
기본 2차원 밀도 그래프 : geom_density2d_filled() 함수 이용

Figure 13.38: 기본 2차원 밀도 그래프 : geom_density2d_filled() 함수 이용

Go Top

13.4.3 월별로 모양과 색깔 구분하기

월을 나타내는 Month 변수가 정수형이기 때문에 이를 문자형 변수 Month.ch 라는 새로운 문자형 변수로 변환한 다음, 이를 사용해서 이차원 밀도 그래프를 Month.ch 별로 모양(shape = )색깔(color = )을 구분해서 그려보겠습니다.

13.4.3.1 숫자형 Month를 문자형 Month.ch로 변환하기

정수형인 Monthas.character() 함수를 이용하여 다음과 같이 문자형으로 변환시킬 수 있습니다.

# Month를 문자형 변수로 변환
airquality_May_July <- transform(airquality_May_July, 
                                 Month.ch = as.character(Month))
     
sapply(airquality_May_July, class)
##       Month         Day        Wind        Temp    Month.ch 
##    "factor"   "integer"   "numeric"   "integer" "character"

Go Top

13.4.3.2 색 바꾸기

ggplot() 함수 내의 aes() 함수에 colour = 모수를 이용하여 2차원 커널 밀도 곡선과 점의 색을 바꿀 수 있습니다. 여기서는 월별로 그 모양을 바꿔야 하기 때문에 aes() 함수 내에 colour = Month.ch 를 입력해 줍니다.

air_basic1 <- ggplot(airquality_May_July, 
                    aes(x = Wind, 
                        y = Temp,
                        colour = Month.ch))
air_basic1 + 
  stat_density2d() +
  geom_point() +
  ggtitle("2차원 밀도 그래프 : 색 바꾸기")
2차원 밀도 그래프 : 색 바꾸기

Figure 13.39: 2차원 밀도 그래프 : 색 바꾸기

Go Top

13.4.3.3 점의 모양 바꾸기

ggplot() 함수 내의 aes() 함수에 shape = 모수를 이용하여 점의 모양을 바꿀 수 있습니다. 여기서는 월별로 그 모양을 바꿔야 하기 때문에 aes() 함수 내에 shape = Month.ch 를 입력해 줍니다.

air_basic2 <- ggplot(airquality_May_July, 
                    aes(x = Wind, 
                        y = Temp,
                        shape = Month.ch))
air_basic2 + 
  stat_density2d() +
  geom_point() +
  ggtitle("2차원 밀도 그래프 : 점의 모양 바꾸기")
2차원 밀도 그래프 : 점의 모양 바꾸기

Figure 13.40: 2차원 밀도 그래프 : 점의 모양 바꾸기

13.4.3.4 점의 크기 바꾸기

ggplot() 함수 내의 geom_point() 함수에 size = 모수를 이용하여 점의 크기을 바꿀 수 있습니다. 여기서는 월별로 그 모양을 바꿔야 하기 때문에 geom_point() 함수 내에 size = 3 을 입력해 보겠습니다.

air_basic2 + 
  stat_density2d() +
  geom_point(size = 3) +
  ggtitle("2차원 밀도 그래프 : 점의 크기 바꾸기")
2차원 밀도 그래프 : 점의 크기 바꾸기

Figure 13.41: 2차원 밀도 그래프 : 점의 크기 바꾸기

Go Top

13.4.3.5 선의 모양 바꾸기

stat_density2d() 함수 내의 aes() 함수에 linetype = Month.ch 를 입력하여 등고선의 모양을 월 별(Month.ch)로 달리할 수 있습니다.

air_basic2 + 
  stat_density2d(aes(linetype = Month.ch)) +
  geom_point() +
  ggtitle("2차원 밀도 그래프 : 선의 모양 바꾸기")
2차원 밀도 그래프 : 선의 모양 바꾸기

Figure 13.42: 2차원 밀도 그래프 : 선의 모양 바꾸기

Go Top

13.4.4 월별 레이블의 추가

범례가 있기는 하지만 사용자의 가독성을 조금 더 높여주기 위해 2차원 밀도 그래프의 5월, 7월 두 집단의 중앙 부위에 “년/월”을 annotate() 함수를 이용하여 “text”로 레이블을 추가할 수 있습니다.

air_basic2 + 
  stat_density2d() +
  ggtitle("2차원 밀도 그래프 : 레이블의 추가") +
  annotate("text", x=11, y=65, label="1973년 5월", alpha=0.5) + 
  annotate("text", x=9, y= 83, label="1973년 7월", alpha=0.5)
2차원 밀도 그래프 : 레이블의 추가

Figure 13.43: 2차원 밀도 그래프 : 레이블의 추가

Go Top

13.4.5 등고선 효과 추가하기

그림이 조금 재미가 없네요… 등고선에 그래디언트 효과를 줘서 히트맵 형태로 표현을 해 보겠습니다.

stat_density2d() 함수 내에 aes() 함수를 이용하여 등고선 효과를 추가합니다.

그리고, scale_fill_gradient() 함수와 scale_alpha() 함수도 추가해 줍니다.

# 2차원 밀도 그래프 : 등고선 효과
air_basic2 + 
  stat_density2d(aes(                 
     fill = ..level.., 
     alpha = ..level..), 
     size = 0.01, 
     bins = 20,                                    # 등고선 간격 조절
     geom = "polygon") +
  scale_fill_gradient(low = "green", high = "red") + 
  scale_alpha(range = c(0, 0.5), guide = FALSE)             +
  ggtitle("2차원 밀도 그래프 : 등고선 효과 1") +
  annotate("text", x=11, y=65, label="1973년 5월", alpha=0.5) + 
  annotate("text", x=9, y= 83, label="1973년 7월", alpha=0.5)
2차원 밀도 그래프 : 등고선 효과 1

Figure 13.44: 2차원 밀도 그래프 : 등고선 효과 1

그래도 뭔가 불만이 있네요.. 등고선을 없애고 부드럽게 표현해 보겠습니다. ggplot() 함수 내의 colour = Month.ch을 제거하고 다시 한번 더 그려보지요…

# 2차원 밀도 그래프 : 등고선 효과
air_basic +
  stat_density2d(aes(fill = ..level.., 
                     alpha = ..level..), 
                     size = 0.01, 
                     bins = 20,   # 등고선 간격 조절
                     geom = "polygon") +
  scale_fill_gradient(low = "green", high = "red") + 
  scale_alpha(range = c(0, 0.5), guide = FALSE)             +
  ggtitle("2차원 밀도 그래프 : 등고선 효과 2") +
  annotate("text", x=11, y=65, label="1973년 5월", alpha=0.5) + 
  annotate("text", x=9, y= 83, label="1973년 7월", alpha=0.5)
2차원 밀도 그래프 : 등고선 효과 2

Figure 13.45: 2차원 밀도 그래프 : 등고선 효과 2

참고로 aes() 함수 내의 bins = 는 등고선 간의 간격 갯수라고 이해하면 좋겠습니다. 간격의 갯수가 많아질수록 등고선의 간격이 좁아지겠지요…. bins의 값을 5, 10, 15, 20, 25, 30 등으로 수정하면서 다시 그려보기 바랍니다.

Go Top

13.4.6 facet_wrap() 함수 이용

한번 더 해 보지요… 이번에는 앞에서 제거한 Month.ch 변수를 facet_wrap() 함수 안에 추가해서 그림을 다시 그려보겠습니다. 그러면 5월과 7월의 지도가 따로 그려지겠지요…

# 2차원 밀도 그래프 : facet_wrap() 함수 이용
ggplot(data=airquality_May_July, aes(x=Wind, y=Temp)) +
#  geom_point(size=4) + 
  stat_density2d(
    aes(fill = ..level.., 
        alpha = ..level..), 
        size = 0.01, 
        bins = 20,                                    # 등고선 간격 조절
        geom = "polygon") +
  scale_fill_gradient(low = "green", high = "red") + 
  scale_alpha(range = c(0, 0.5), guide = FALSE)             +
  ggtitle("2D desity plot of Wind and Tmep, at1973. May/July by Colour") +
  annotate("text", x=11, y=65, label="May, 1973", alpha=1.5, color = "blue") + 
  annotate("text", x=9, y= 83, label="July, 1973", alpha=1.5, color = "blue") +
  facet_wrap(vars(Month.ch))
2차원 밀도 그래프 : facet_wrap() 함수 이용

Figure 13.46: 2차원 밀도 그래프 : facet_wrap() 함수 이용

Go Top

연습문제

1. Cars93 데이터 세트의 Weight (x 축)와 MPG.highwat (y축) 데이터를 이용한 2차원 커널 밀도 그래프를 작성하시오.

library(MASS)
ggplot(Cars93, 
          aes(x = Weight, 
              y = MPG.highway)) +
  stat_density2d() 

2. 1.에서의 그래프를 자동차 구동방식(DriveTrain) 별로 색을 달리하고, 각 자동차 구동방식(DriveTrain) 별로 facet_wrap() 함수를 이용하여 2차원 커널 밀도 그래프를 작성하시오.

library(MASS)
ggplot(Cars93, 
          aes(x = Weight, 
              y = MPG.highway,
              colour = DriveTrain)) +
 stat_density2d() +
  facet_wrap( ~ DriveTrain)

Go Top