재현가능한 과학적 분석을 위한 R

논문 품질 그래프 생성하기

학습 목표

  • ggplot2 팩키지를 사용해서 논문품질 그래프를 생성할 수 있다.
  • 그래픽 문법(Grammar of Graphics)의 기초를 이해한다:
  • 미학 계층
  • 기하 계층
  • 통계량 추가
  • 척도 변환
  • 집단별 색깔입히기 혹은 창으로 구분

데이터를 도식화하는 것이 변수 다양한 관계를 재빨리 탐색하는 최상의 방식 중 하나다.

R에는 세가지 주류 도식화 시스템이 존재한다: 기본 도식화 시스템,lattice 팩키지, ggplot2 팩키지.

ggplot2 팩키지를 학습하는데 이유는 논문품질 그래프 생성에 있어 가장 효과적이기 때문이다.

ggplot2는 그래픽 문법에 기반했다. 즉, 어떤 그래프도 동일한 구성요소 집합으로 표현된다: 데이터 집합, 좌표 시스템, geoms 집합 – 데이터 점에 대한 시각적 표현.

ggplot2를 이해하는 핵심은 그림을 계층으로 사고하는 것이다: 포토샵, 일러스트레이터, 잉크스케이프 같은 이미지 편집 프로그램으로 작업하는 것과 같다.

예제를 가지고 시작해본다:

library(ggplot2)
ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap)) +
  geom_point()

plot of chunk lifeExp-vs-gdpPercap-scatter

그래서, 처음으로 수행하는 작업은 ggplot 함수를 호출하는 것이다. 이 함수가 R에게 새로운 그림을 생성하고, ggplot 함수에 전달하는 어떤 인자도 해당 그림에 전역 선택옵션(그림에 있는 모든 계층에 적용)임을 전달한다.

ggplot에 인자를 두개 전달했다. 먼저, ggplot에 그림에 사용할 데이터가 무엇인지 전달한다; 번 예제에서 앞에서 불러온 gapminder데이터. 두번째 인자를 aes함수에 전달했는데, ggplot에게 데이터에 나온 변수를 도식화하는 그림의 미학적인 속성에 매핑하는 방법을 전달한다; 이번 경우에는 xy 위치. 여기서 ggplotgapminder데이터프레임 “lifeExp” 칼럼을 x-축에, “gdpPercap” 칼럼을 y-축에 도식화한다. 명시적으로 aes에 칼럼명을 전달(예를 들어, x = gapminder[, “lifeExp”])하지 않은 것에 주목한다. 이것이 가능한 이유는ggplot` 함수가 데이터에 존재하는 칼럼을 식별할만큼 똑똑하기 때문이다!

그 자체로, ggplot함수를 호출한다고 도식화가 바로 되는 것은 아니다:

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap))

plot of chunk unnamed-chunk-2

ggplot 함수에 데이터를 시각적으로 표현하는 방법을 전달할 필요가 있다. geom 계층을 추가해서 작업이 수행된다. 본 사례에서, geom_point를 사용했다; xy 사이 관계를 시각적으로 산점도 형태로 표현하도록 ggplot에게 전달한다:

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap)) +
  geom_point()

plot of chunk lifeExp-vs-gdpPercap-scatter2

도전과제 1

상기예제를 변경해서, 기대수명이 시간에 따라 어떻게 변해왔는지 시각화하는 그림을 생성한다:

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap)) + geom_point()

힌트: gapminder 데이터셋에 “year”라는 칼럼이 있는데, x-축에 나타나야 된다.

도전과제 2

이전 예제와 도전과제에서, aes 함수를 사용해서 geom 산점도로 xy 지점을 각 점에 대해 표현했다. 변경할 수 있는 또다른 미학적 속성은 각 점에 대한 색깔이다. 앞선 도전과제 코드를 변경해서 “continent” 대륙별로 각 점에 을 입힌다. 데이터에서 어떤 경향성을 볼 수 있는가? 예상했던 경향성인가?

계층

산점도가 아마도 시간에 따라 변하는 정보를 시각화하는데 최선은 아니다. 대신에, ggplot에 선그림(line plot)으로 데이터를 시각화한다:

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country, color=continent)) +
  geom_line()

plot of chunk lifeExp-line

geom_point 계층을 추가하는 대신에, geom_line 계층을 추가했다. 미학적으로 by를 추가해서, ggplot이 각 국가를 직선으로 연결해서 도식화한다.

하지만, 직선과 점을 함께 시각화하려고 하면 어떨까? 단순히, 또다른 계층을 그림에 추가하면 된다:

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country, color=continent)) +
  geom_line() + geom_point()

plot of chunk lifeExp-line-point

각 계층은 이전 계층 위에 도식화됨에 주목한다. 이번 예제에서, 점이 직선 위에 도식화되었다. 다음에 도식화한 시연이 나와있다:

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country)) +
  geom_line(aes(color=continent)) + geom_point()

plot of chunk lifeExp-layer-example-1

이번 예제에서, 미학적색상 매핑이 ggplot에 전역으로 설정된 점 선택옵션에서 geom_line 계층으로 이동했다. 그래서, 해당 점에는 더이상 적용되지 않는다. 이제 분명하게 직선 위에 점이 도식화된 것을 확인할 수 있다.

도전과제 3

앞선 예제에서 점과 직선 계층을 뒤바꾼다. 어떻게 될까요?

변환과 통계량

ggplot으로 데이터 위에 통계적 모형을 쉽게 겹치게 할 수 있다. 이를 시연하기 위해서, 첫번째 예제로 되돌아간다:

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap, color=continent)) +
  geom_point()

plot of chunk lifeExp-vs-gdpPercap-scatter3

현재, 일인당 GDP에 일부 심각한 이상점이 있어 점사이 내재된 관계를 보기 힘들다. scale 척도함수를 사용해서 y-축 척도를 변경한다. 이러한 제어를 통해 데이터 값과 미학적인 시각값 사이 매핑을 제어한다.

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap)) +
  geom_point() + scale_y_log10()

plot of chunk axis-scale

그림에 렌더링하기 전에 log10 함수가 gdpPercap 칼럼값에 변환을 시켰다. 그래서, 각 자리수 10은 변환된 척도에 1씩 증가에 대응된다. 예를 들어, 1인당 GDP 1,000은 y-축에 3, 10,000은 y-축에 4에 대응된다. 로그 변환은 y-축에 흩어진 데이터 시각화를 쉽게 도와준다.

또다른 계층(geom_smooth)을 추가해서 관계를 단순히 적합시킬 수 있다:

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap)) +
  geom_point() + scale_y_log10() + geom_smooth(method="lm")

plot of chunk lm-fit

굵은 선은 geom_smooth 계층에 미학적인 크기를 설정해서 조정할 수 있다:

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap)) +
  geom_point() + scale_y_log10() + geom_smooth(method="lm", size=1.5)

plot of chunk lm-fit2

미학적인 항목을 명세할 수 있는 방식이 두개 있다. 바로 앞에서 geom_smooth 함수에 인자로 전달해서 크기에 대한 미학적인 설정을 했다. 앞에서는 aes 함수를 사용해서 데이터 변수와 시각적 표현 사이 매핑으로 정의했다.

도전과제 4

바로 앞 예제에서 점 계층에 나온 점 크기와 색상을 변경하라.

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

다중-창 그림

앞에서 그림 하나에 모든 국가에 대해 시간의 변화에 따른 기대수명 변화를 시각화했다. 대안으로, 패싯(facet) 창 계층을 추가해서, 그림을 여러개 창으로 쪼갤 수도 있다:

ggplot(data = gapminder, aes(x = year, y = lifeExp, color=continent)) +
  geom_line() + facet_wrap( ~ country)

plot of chunk facet

facet_wrap 계층은 “공식”을 인자로 받는데, (~) 틸드로 표기한다. gapminder 데이터셋 국가별 칼럼에 유일한 값 각각에 대해 별도 창에 도식화하게 한다.

텍스트 변경하기

논문 출판으로 그림을 깔끔하게 만들려면, 텍스트 요소를 일부 변경할 필요가 있다. x-축이 너무 난잡하고, y-축은 데이터프레임 칼럼명이 아닌 “Life expectancy”으로 적혀야 된다.

몇개 다른 계층을 추가함으로써 텍스트를 변경할 수 있다. theme 계층이 각 축에 대한 텍스트, 전반적인 텍스트 크기를 제어한다. 축 라벨을 변경하는 특수 계층도 있다. 범례 제목을 변경하려면, scales 계층을 사용한다.

ggplot(data = gapminder, aes(x = year, y = lifeExp, color=continent)) +
  geom_line() + facet_wrap( ~ country) +
  xlab("Year") + ylab("Life expectancy") + ggtitle("Figure 1") +
  scale_fill_discrete(name="Continent") +
  theme(axis.text.x=element_blank(), axis.ticks.x=element_blank())

plot of chunk theme

지금까지 ggplot2로 작업할 수 있는 것을 살짝 맛봤다. RStudio는 다양한 계층에 대한 정말 유용한 cheat sheet를 제공한다. 더 자세한 문서는 ggplot2 웹사이트에 공개되어 있다. 마지막으로, 무언가 변경하는 방법에 대해 잘 모르겠으면, 구글 검색창에 연관된 질문을 올리면, 변경해서 바로 사용할 수 있는 재사용가능한 코드가 StackOverflow 사이트에 올라와 있을 것이다!

도전과제 5

대륙별로 채워진 1인당 GPD 밀도 그래프를 생성하라.

고급: - x-축을 변경해서 쭉 펼쳐진 데이터를 좀더 보기좋게 시각화하라. - 패싯 계층을 추가해서 연도별로 밀도 그래프를 창에 도식화하라.

도전과제 해답

도전과제 1에 대한 해답

상기예제를 변경해서, 기대수명이 시간에 따라 어떻게 변해왔는지 시각화하는 그림을 생성한다:

ggplot(data = gapminder, aes(x = year, y = lifeExp)) + geom_point()

plot of chunk ch1-sol

도전과제 2에 대한 해답

이전 예제와 도전과제에서, aes 함수를 사용해서 geom 산점도로 xy 지점을 각 점에 대해 표현했다. 변경할 수 있는 또다른 미학적 속성은 각 점에 대한 색깔이다. 앞선 도전과제 코드를 변경해서 “continent” 대륙별로 각 점에 을 입힌다. 데이터에서 어떤 경향성을 볼 수 있는가? 예상했던 경향성인가?

ggplot(data = gapminder, aes(x = year, y = lifeExp, color=continent)) +
  geom_point()

plot of chunk ch2-sol

도전과제 3에 대한 해답

앞선 예제에서 점과 직선 계층을 뒤바꾼다. 어떻게 될까요?

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country)) +
 geom_point() + geom_line(aes(color=continent))

plot of chunk ch3-sol

이제야 비로소 직선이 점위에 그려진다!

도전과제 4에 대한 해답

바로 앞 예제에서 점 계층에 나온 점 크기와 색상을 변경하라.

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

ggplot(data = gapminder, aes(x = lifeExp, y = gdpPercap)) +
 geom_point(size=3, color="orange") + scale_y_log10() +
 geom_smooth(method="lm", size=1.5)

plot of chunk ch4-sol

도전과제 5에 대한 해답

대륙별로 채워진 1인당 GPD 밀도 그래프를 생성하라.

고급: - x-축을 변경해서 쭉 펼쳐진 데이터를 좀더 보기좋게 시각화하라. - 패싯 계층을 추가해서 연도별로 밀도 그래프를 창에 도식화하라.

ggplot(data = gapminder, aes(x = gdpPercap, fill=continent)) +
 geom_density(alpha=0.6) + facet_wrap( ~ year) + scale_x_log10()

plot of chunk ch5-sol