9  논문 품질 그래프 생성

데이터를 시각화하는 것은 변수 간 다양한 관계를 신속하게 탐색하는 가장 좋은 방법 중 하나이다. R에는 세 가지 주요 그래프 시스템이 있다. R 시각화 시스템에 대해서는 논문 품질 그래프 생성을 마무리하고 9.6 절에서 별도로 자세히 소개되어 있다.

ggplot2 패키지를 도구로 사용하게 되는데, 이는 출판 품질의 그래프를 생성하는 데 가장 효과적이기 때문이다. ggplot2는 그래픽 문법(grammar of graphics)에 기반을 두고 있다. 즉, 모든 그래프는 동일한 구성요소 집합으로 표현된다: 데이터셋, 좌표 시스템, 데이터 점에 대한 시각적 표현인 geoms 집합.

ggplot2를 이해하는 핵심은 그래프를 계층으로 생각하는 것이다. 포토샵(Photoshop), 일러스트레이터(Illustrator), 잉크스케이프(Inkscape)와 같은 이미지 편집 프로그램으로 작업하는 것과 유사하다. 예제를 통해 시작해보자.

먼저 ggplot 함수를 호출하여 R에게 새로운 그래프를 생성할 것임을 알린다. ggplot 함수에 전달하는 모든 인자는 해당 그래프에 전역적으로 적용되는 설정(그래프의 모든 계층에 적용)이 된다.

ggplot에 두 개의 인자를 전달했다. 첫째, ggplot에 그래프에 사용할 데이터가 무엇인지 알려준다. 여기서는 앞에서 불러온 gapminder 데이터이다. 둘째, aes 함수를 사용하여 데이터의 변수를 그래프의 aesthetic 속성에 매핑하는 방법을 ggplot에 알려준다. 여기서는 xy 위치를 설정했다. ggplot에게 gapminder 데이터프레임의 “gdpPercap” 열을 x 축에, “lifeExp” 열을 y 축에 표현하도록 지시한 것이다. aes에 열 이름을 명시적으로 전달하지 않았다는 점에 주목하자(예: x = gapminder[, “gdpPercap”]). 이것이 가능한 이유는 ggplot데이터에 주어진 열 이름을 인식할 만큼 똑똑하기 때문이다!

ggplot 함수를 호출한다고 해서 그래프가 바로 그려지는 것은 아니다:

ggplot에게 데이터를 시각적으로 표현하는 방법을 알려줄 필요가 있다. geom 계층을 추가함으로써 이를 수행할 수 있다. 다음 예제에서는 geom_point를 사용하여 ggplot에게 xy 사이의 관계를 점으로 표현하라고 지시했다.

도전과제

위의 예제를 변경하여 기대수명이 시간에 따라 어떻게 변화했는지 보여주는 그래프를 만들어보자.

힌트: gapminder 데이터셋에는 “year” 열이 있으며, 이것이 x 축에 나타나야 한다.

한 가지 해결책은 다음과 같다:

도전과제

이전 예제와 도전과제에서는 aes 함수를 사용하여 geom 점의 xy 위치를 나타냈다. 또 다른 aesthetic 속성으로 각 점의 색상을 변경할 수 있다. 이전 도전과제 코드를 수정하여 “continent” 열에 따라 각 점의 색상을 다르게 표시해보자. 데이터에서 어떤 추세를 볼 수 있는가? 예상했던 것인가?

이전 예제와 도전과제에서는 aes 함수를 사용하여 geom 점의 xy 위치를 나타냈다. 또 다른 aesthetic 속성으로 점의 색상을 변경할 수 있다. “continent” 열에 따라 각 점의 색상을 다르게 표시하려면 이전 도전과제 코드를 다음과 같이 수정하면 된다. 데이터에서 어떤 추세를 볼 수 있는가? 예상했던 것인가?

9.1 계층

산점도는 시간에 따른 정보를 시각화하는 데 가장 적합한 방법은 아닐 수 있다. 대신 ggplot에게 선 그래프로 데이터를 표현하도록 지시할 수 있다.

geom_point 계층 대신 geom_line 계층을 추가했다. aesby를 추가하여 ggplot이 각 국가를 선으로 연결하여 표현하도록 했다.

그런데 선과 점을 모두 표시하려면 어떻게 해야 할까? 간단히 그래프에 또 다른 계층을 추가하면 된다.

각 계층이 이전 계층 위에 그려진다는 점에 주목하자. 이번 예제에서는 점이 선 위에 표시되었다. 다음에 표시된 그래프를 보자.

이 예제에서 aesthetic color 매핑이 ggplot의 전역 설정에서 geom_line 계층으로 이동했다. 따라서 더 이상 점에는 적용되지 않는다. 이제 선이 점 위에 그려진 것을 명확히 볼 수 있다.

aesthetic에 값 설정하기

지금까지 (색상같은) aesthetic 를 데이터의 변수로 매핑(mapping)해서 사용하는 법을 살펴봤다. 예를 들어, geom_line(aes(color=continent))을 사용하면, ggplot에서 자동으로 각 대륙별로 다른 색상을 입힌다. 그런데, 모든 선을 파란색으로 바꾸고자 하면 어떨까? geom_line(aes(color="blue")) 명령어가 동작해야 된다고 생각하지만, 사실은 그렇지 않다. 특정 변수에 대한 매핑을 생성하지 않았기 때문에, aes() 함수 밖으로 색상을 명세하는 부분을 예를 들어, geom_line(color="blue")와 같이 빼내기만 하면 된다.

도전과제

앞선 예제에서 점과 선 계층의 순서를 바꿔보자. 어떻게 되는가?

앞선 예제에서 점과 선 계층의 순서를 바꿔보자. 어떻게 되는가?

선이 점 위에 그려진다!

9.2 변환과 통계

ggplot을 사용하면 데이터에 통계 모델을 쉽게 겹칠 수 있다. 이를 시연하기 위해서, 첫번째 예제로 돌아가보자.

현재 1인당 GDP에 몇 가지 극단적인 이상치가 있어서 점 사이의 내재된 관계를 보기 어렵다. scale 함수를 사용하여 y 축 스케일을 조정할 수 있다. 이를 통해 데이터 값과 aesthetic 시각적 표현 사이의 매핑을 제어할 수 있다. alpha 함수를 사용하여 투명도도 조정할 수 있는데, 이는 특히 많은 데이터가 한 곳에 밀집되어 있을 때 유용하다.

그래프를 렌더링하기 전에 log10 함수가 gdpPercap 열 값을 변환했다. 따라서 변환된 스케일에서 10의 거듭제곱 단위마다 1씩 증가한다. 예를 들어, 1인당 GDP 1,000은 y-축에 3, 10,000은 y-축에 4에 대응된다. 로그 변환은 x 축에 넓게 퍼져 있는 데이터를 시각화하는 데 도움이 된다.

aesthetic에 값 설정하기

geom_point(alpha = 0.5)를 사용한 것에 주목하자. 앞서 언급했듯이, aes() 함수 외부에서 설정한 것은 모든 점에 동일한 값이 적용된다. 이 경우 투명도를 지정하는 것은 원하는 바로 문제가 없다. 그러나 다른 aesthetic 설정과 마찬가지로 alpha 투명도를 데이터의 변수에 매핑할 수도 있다. 예를 들어, 각 대륙마다 다른 투명도를 적용하려면 geom_point(aes(alpha = continent))와 같이 코딩하면 된다.

또 다른 계층(geom_smooth)을 추가하여 관계를 단순하게 모델링할 수 있다.

굵은 선의 두께는 geom_smooth 계층의 aesthetic size를 설정하여 조정할 수 있다:

aesthetic을 지정하는 방법에는 두 가지가 있다. 방금 전에는 geom_smooth 함수에 인수로 전달하여 size에 대한 aesthetic을 설정했다. 앞에서는 aes 함수를 사용하여 데이터 변수와 시각적 표현 사이의 매핑을 정의했다.

도전과제

바로 이전 예제에서 점 계층의 점 크기와 색상을 변경해보자.

힌트: aes 함수를 사용하지 않는다.

바로 이전 예제에서 점 계층의 점 크기와 색상을 변경해보자. 힌트: aes 함수를 사용하지 않는다.

도전과제

도전과제 4a를 수정하여 점의 모양을 바꾸고 대륙별로 색상을 다르게 하되, 대륙별로 추세선도 표시되도록 해보자. 힌트: 색상 인수를 aesthetic 내부로 이동시킨다.

도전과제 4a를 수정하여 점의 모양을 바꾸고 대륙별로 색상을 다르게 하되, 대륙별로 추세선도 표시되도록 해보자. 힌트: 색상 인수를 aesthetic 내부로 이동시킨다.

9.3 다중-패널 그래프

앞에서는 하나의 그래프에 모든 국가에 대한 시간의 흐름에 따른 기대수명 변화를 시각화했다. 대안으로 facet 계층을 추가하여 그래프를 여러 개의 패널로 나눌 수 있다. 이번에는 국가명이 “A” 또는 “Z”로 시작하는 국가에만 초점을 맞춰보자.

유용한 팁

데이터의 부분 집합을 추출하는 것으로 시작해보자. substr 함수를 사용하여 문자열의 일부를 추출할 수 있다. 이 경우에는 gapminder$country 벡터의 시작과 끝 위치 문자를 추출한다. %in% 연산자를 사용하면 여러 개의 비교를 간단하게 수행할 수 있다. (이 경우 starts.with %in% c("A", "Z")starts.with == "A" | starts.with == "Z"와 동일하다)

facet_wrap 계층은 틸드(~)로 표시되는 “공식”을 인수로 받는다. gapminder 데이터셋의 country 열에 있는 각 고유값에 대해 별도의 패널로 그래프를 생성한다.

9.4 텍스트 수정하기

출판용 그래프를 만들기 위해서는 텍스트 요소를 일부 변경해야 할 필요가 있다. x 축이 너무 복잡하고, y 축은 데이터프레임 열 이름이 아닌 “Life expectancy”로 표시되어야 한다.

몇 가지 다른 계층을 추가하여 텍스트를 수정할 수 있다. theme 계층은 각 축의 텍스트와 전반적인 텍스트 크기를 제어한다. 축, 그래프 제목, 범례는 labs() 함수를 사용하여 설정할 수 있다. 범례 제목은 aes() 함수에서 지정한 것과 동일한 이름을 사용한다. 따라서 색상 범례 제목은 color = "Continent"가 되고, 채우기(fill) 범례는 fill = "MyTitle"이 된다.

9.5 그래프 저장하기

ggsave() 함수를 사용하여 ggplot으로 생성한 그래프를 로컬 컴퓨터에 저장할 수 있다. 출판을 위한 고품질 그래픽을 생성하기 위해 그래프의 크기와 해상도를 ggsave() 함수의 인수(width, height, dpi)로 전달할 수 있다. 앞에서 생성한 그래프를 저장하려면 먼저 lifeExp_plot 변수에 그래프를 할당한 다음 ggsave() 함수를 사용하여 png 형식으로 results 디렉터리에 저장하도록 지정한다. (작업 디렉터리에 results/ 폴더가 생성되어 있어야 한다.)

ggsave() 함수에는 두 가지 좋은 점이 있다. 첫째, 기본값으로 가장 최근에 생성한 그래프가 저장되므로 plot 인수를 생략하면 ggplot으로 생성한 마지막 그래프가 자동으로 저장된다. 둘째, 저장되는 그래프 이미지 형식이 파일 확장자(예: .png 또는 .pdf)에 따라 결정된다. 필요한 경우 device 인수를 사용하여 명시적으로 파일 형식을 지정할 수도 있다.

지금까지 ggplot2의 기본을 살펴보았다. RStudio는 다른 계층 사용법에 대한 참고자료로 유용한 치트 시트를 제공하고 있으며, ggplot2 웹사이트에는 추가 기능에 대한 자세한 정보가 있다. 마지막으로, 어떻게 수정해야 할지 모르겠다면 구글 검색을 통해 Stack Overflow에서 재사용 가능한 코드와 함께 관련 질문과 답변을 쉽게 찾을 수 있다.

도전과제 (심화)

가용한 연도 기간동안 각 대륙 간 기대수명을 비교하는 상자 그림(boxplot)을 생성한다.

  • y축의 이름을 “기대수명”으로 변경한다.
  • x축 레이블은 제거한다.

가능한 해법 중 하나는 다음과 같다. xlab()ylab()은 각각 x축과 y축 레이블을 설정한다. 축의 제목, 텍스트, 눈금은 테마의 속성이며 theme() 호출 내에서 수정되어야 한다.

9.5.1 R

9.6 R 시각화 시스템

동일한 시각화 산출물을 제작한다고 하더라도 철학에 따라 차이점이 있다. 크게 시각화 도구는 명령형과 선언형으로 나눠지고 그래프 문법을 따르는 ggplot의 경우 선언형에 해당된다.

시각화 도구
  • 명령형(imperative): “방법(how)”에 초점, Processing, OpenGL, prefuse
  • 선언형(declarative): “무엇(what)”에 초점, D3, ggplot2, Protovis

R은 역사가 오래된 검증된 언어라 보니 그 시대의 컴퓨팅 환경과 축적된 지적자산이 반영되어 다양한 시각화 시스템이 존재한다. 가장 대표적으로 3가지 시각화 시스템을 이해하면 실무적으로 충분하다.

  • 베이스(Base) 시각화 시스템
  • lattice 시각화 시스템: 클리블랜드(Cleveland)의 Trellis Graphics에서 출발
  • ggplot 시각화 시스템: 윌킨슨(Wilkinson)의 Grammar of Graphics에서 출발

2017년 3월 기준 R 팩키지를 시각화 시스템으로 구분하면 다음과 같다. 현재는 ggplot이 후발주자의 이점을 발휘하여 대세로 자리잡았고 이는 ggplot2 패키지 기여자 수, 코드 길이, 연관된 패키지 수를 확인하면 쉽게 파악할 수 있다.

시각화 시스템 패키지 개수
Base 시각화 5,612
lattice 시각화 3,654
ggplot 시각화 1,566

9.6.1 Base 시각화 시스템

R을 설치하면 내장되어 있는 Base 시각화 시스템은 화가의 팔레트(Artist Palallete) 모형으로 빈 도화지 캔버스 위에 화가가 그림을 그리는 것과 동일한 방식으로 시각화 산출물을 만들어 나간다. plot() 혹은 유사한 시각화 함수로 시작해서 텍스트(text), 선(line), 점(point), 축(axis) 등을 표현하는데 주석(Annotation) 함수를 활용한다.

따라서, 사람이 사고하는 방식으로 시각화 산출물을 만들어 나가 편리하지만, 시각화 산출물을 다시 그리려고 하면 처음부터 다시 해야 되기 때문에 시각화 산출물을 만드는 초기부터 시간을 갖고 잘 설계해 나가야 된다. 그리고, 시각화 산출물이 생성되면 다른 것으로 변환하기 어려운 단점이 있고, 그래픽 언어가 아니라 일련의 R 명령어 묶음에 불과하다.

# 1. Base 시각화 시스템---------------------------------------
data(mtcars)
with(mtcars, plot(disp, mpg))
그림 9.1: Base 시각화 시스템

9.6.2 lattice 시각화 시스템

lattice 시각화 시스템은 lattice 패키지를 통해 설치되고, 함수 호출(xyplot(), bwplot() 등)을 통해 시각화 산출물을 생성하게 된다. 조건에 따라 일변량 혹은 다변량 변수를 시각화하는데 유용하다. 즉, 특정 범주형 변수 수준에 따라 두 변수간의 관계를 시각적으로 표현하는 것을 예로 들 수 있다. 전체 시각화 산출물 결과는 여백(margin), 공간 등은 자동으로 한번에 정해져서, 화면에 다수 시각화 산출물을 배치할 때 유용하다.

하지만, 함수호출 한번으로 전체 시각화 산출물을 명세하는 것이 쉽지는 않다. 특히 주석(Annotation)을 시각화 산출물에 다는 것이 그다지 직관적이지는 않다. 그리고 lattice 함수를 통해 시각화 산출물이 만들어지면 더 이상 추가하는 것은 불가능하다.

키보드 자판으로 통계모형을 R로 표현하는 방법처럼 변수들을 lattice 시각화 시스템에서 공식으로 표현할 수 있다는 점은 큰 장점 중 하나이다.

library(lattice)
# 2. Lattice 시각화 시스템---------------
xyplot(mpg ~ disp | am, data=mtcars, layout=c(2,1))
그림 9.2: Lattice 시각화 시스템

9.6.3 ggplot 시각화 시스템

ggplot 시각화 시스템은 ggplot2 패키지를 통해 설치가 가능하다. Base 시각화 시스템과 lattice 시각화 시스템의 장점을 취사선택해서 개발된 것으로 보는 견해도 있다. 그래픽 문법(Grammar of Graphic)에 기반하고 있으며, lattice 시각화 시스템처럼 공백, 텍스트, 제목 등을 자동으로 설정하고, Base 시각화 시스템에서 지원하는 다양한 그래픽 요소를 추가하는 것도 가능하다. 전반적으로 lattice 느낌이 나지만 사용하기는 직관적이며 다양한 그래픽 요소를 추가하는 것도 쉽다. 물론 ggplot에서 자동으로 설정하는 것도 원하는 설정으로 바꾸는 것도 가능하다.

# 3. ggplot 시각화 시스템----------------
ggplot(data=mtcars, mapping=aes(x=disp, y=mpg)) + 
  geom_point() +
  geom_smooth(method="lm", se=FALSE)
그림 9.3: ggplot 시각화 시스템

9.6.4 grid 시각화 시스템

grid 시각화 시스템은 latticeggplot의 기반이 되는 시각화 시스템으로 R 버전 1.8.0 부터 Base 패키지의 일부가 되었다.1 grid_0.7-4에서 Base 패키지 일부가 되어 버전이 Base 패키지에 맞춰 버전이 급상승했다.

grid 시각화 시스템을 사용해서 위와 동일하게 상기 그래프를 그리면 다음과 같다. grid 시스템을 숙달하기까지 시간이 걸리지만, 익숙해지면 장점이 상당하다.

library(grid)
x <- mtcars$disp
y <- mtcars$mpg

pushViewport(plotViewport())
pushViewport(dataViewport(x, y))
grid.rect()
grid.xaxis()
grid.yaxis()
grid.points(x, y)
grid.text("mtcars$disp", x = unit(-3, "lines"), rot = 90)
grid.text("mtcars$mpg", y = unit(-3, "lines"), rot = 0)
popViewport(2)
그림 9.4: grid 시각화 시스템

9.7 요약

R에는 그래프 문법에 기반한 ggplot2를 비롯하여 출판 품질 그래프를 생성할 수 있는 다양한 시각화 시스템이 존재한다. ggplot2는 레이어 개념을 사용하여 데이터, 좌표계, 시각적 요소(geom)를 조합함으로써 그래프를 생성하는데 이미지 편집 프로그램으로 유명한 포토샵이나 일러스트레이터와 유사한 방식이다.

ggplot2를 사용하여 그래프를 생성할 때는 데이터와 aes를 매핑하고, geom 레이어를 추가하여 시각적 요소를 지정한다. 필요에 따라 좌표계 변환, 작은 창 분할, 테마 설정 등을 통해 그래프를 맞춤형 제작이 가능하고, ggsave() 함수를 사용하여 생성된 그래프를 다양한 형식으로 저장할 수 있다.

ggplot2 외에도 R에는 Base 시각화 시스템, lattice 시각화 시스템 등 다양한 옵션이 존재한다. Base 시각화 시스템은 그래프를 그리는 기본적인 함수를 제공하며, lattice는 격자 그래픽(Trellis Graphics)에 기반하여 조건부 플롯을 생성하는 데 특화되어 있다. 한편 grid 시각화 시스템은 latticeggplot의 기반이 되는 저수준 시각화 도구로, 보다 유연하고 강력한 그래픽을 생성할 수 있다.


  1. R package grid disappeared?↩︎