Post List

2019년 1월 16일 수요일

ggplot2 기초문법 배우기



본 글은 http://r-statistics.co/ggplot2-Tutorial-With-R.html
페이지의 내용을 해석 및 다소 수정하여 작성되었습니다.


ggplot 학습에 들어가기에 앞서

ggplot2는 R에서 사용할 수있는 가장 우아하고 예술적인 그래픽 프레임 워크입니다. 이 패키지는 멋지게 계획된 구조를 가지고 있습니다. 이 튜토리얼에서는 ggplot을 만드는 데 사용할 수있는 기본 구조를 나타내는 방법을 중점적으로 다룹니다. 그러나 ggplot2에서 플롯을 만드는 방법은 기본 그래픽과 매우 다르므로, 기본 그래픽에 대해 알고있는 것은 잠시 뒤로 두고, 해당 강의를 따라오세요. ggplot을 크게 5 단계로 배워보도록 하겠습니다.


1. 기본 셋업

먼저 ggplot에서 사용할 데이터 세트를 지정해주어야 합니다. 이것은 ggplot(df) 함수를 사용하여 수행됩니다. 여기서 df는 플롯을 만들기 위해 필요한 데이터 프레임입니다. 기본 그래픽과 달리 ggplot은 벡터를 인수로 사용하지 않습니다.

선택에 따라 데이터 세트에서 각 변수를 지정하여 X축 및 Y축과 같은 ggplot(aes() 인수 내부)에 적용할 미학요소(aesthetics)를 추가 할 수 있습니다. 색상, 크기, 모양 및 획이 변경 되어야하는 변수도 여기에 지정할 수 있습니다. 여기에 지정된 미학은 이후에 추가 할 모든 레이어에 적용됩니다.

나중에 레이어를 추가하려는 경우 -선 그래프 상단에 막대형 차트를 그리는 경우- 각 레이어에 서로다른 미학요소를 지정할 수 있습니다.

아래에서는 ggplot2 패키지에서 제공되는 다이아몬드 데이터 세트에서 ggplot을 설정하는 방법에 대한 몇 가지 예를 보여줍니다. 그러나 기하학 레이어를 추가 할 때까지 플롯이 인쇄되지 않습니다.

install.packages('ggplot')
library(ggplot2)
ggplot(diamonds)  # 데이터셋으로 diamonds가 지정됨
ggplot(diamonds, aes(x = carat))  # x축으로 carac이 지정됨
ggplot(diamonds, aes(x = carat, y = price))  # x축으로 carat, y축으로 price가 지정됨
ggplot(diamonds, aes(x = carat, color = cut))  # cut에 따라 색이 서로 다르게 지정됨



aes 인수는 미학요소를 의미합니다. ggplot2는 색상, 크기, 모양, 채우기 등과 함께 플롯의 X 축과 Y 축을 미학으로 간주합니다. 위의 예에서는 cut에 따라 서로 다른 색이 표현됩니다. 색상, 크기 등이 변수에 따라 달라지지 않고  전체에 고정하고자 한다면, aes() 밖에서 해당 값을 지정해야 합니다.

ggplot(diamonds, aes(x = carat), color = "steelblue")
위의 코드를 입력할 경우 전체 색상이 steelblue로 고정됩니다.


2. 레이어

ggplot2의 레이어를 '기하 구조(geoms)'라 합니다. 기본 설정이 완료되면 기하 구조를 다른 구성 위에 추가 할 수 있으며, 이러한 추가는 ‘+’ 기호를 사용합니다. 해당 링크에는 사용 가능한 모든 기하 구조의 목록이 있습니다. (Layers: geoms 참조)

ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() + # layer 1
 geom_smooth()  # later 2




geom_point()는 산점도를 의미하며, geom_smooth()는 관계를 나타내는 그래프이며, 두개의 레이어가 플롯에 추가되었습니다. X축 Y축, 색상이 ggplot() 설정 자체에서 정의되었으므로(ggplot 내 aes에서 정의), 이 두 레이어는 이러한 미학을 따르게 됩니다. 즉 점도표와 그래프가 cut에 따라 그룹화되어 그룹별로 다른 색을 나타내게 됩니다. X 및 Y축과 점의 색상이 cut 변수의 값에 따라 달라지며, 범례가 자동으로 추가되었습니다. 만일 cut 변수에 따라 여러 개의 스무딩 라인을 사용하는 대신, 하나의 라인 아래로 모든 커브를 통합하고자 하려면, 다음과 같이 하면 됩니다.

ggplot(diamonds, aes(x = carat, y = price)) +
 geom_point(aes(color = cut)) +
 geom_smooth()


aes() 내부에서는 X축과 Y축만을 정의하였고, geom_point() 내부의 미학적 요소에 color=cut을 추가함에 따라 점도표는 cut에 따라 다른 색을, geom_smooth() 내부에는 미학적 요소를 추가하지 않음에 따라 하나의 색으로 표현됩니다. cut 데이터 별로 점의 색깔을, color 데이터 별로 점의 모양을 다르게 표현하는 복잡한 작업도 ggplot()을 사용하면 쉽게 해결할 수 있습니다.

ggplot(diamonds, aes(x = carat, y = price, color = cut, shape = color)) +
 geom_point()


aes() 미학 내에 색상에 해당하는 color는 cut, 모양에 해당하는 shape에는 color 데이터를 지정해 줍니다.


3. 라벨

그래프를 그렸으며, 기본 제목을 추가하고 X축 및 Y축 제목을 변경하는 방법은, 라벨을 지정하는 labs 레이어를 사용하여 수행 할 수 있습니다. 그러나 라벨의 크기, 색상을 조작하는 것은 'Theme'의 일입니다. (이에 대해서는 다음 항목에서 다룹니다.)

gg = ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() +
 labs(title="Scatterplot", x="Carat", y="Price")
print(gg)


플롯의 메인 타이틀 및 X,Y축 레이블이 지정됩니다.
4. 테마 라벨의 크기를 조정하려면 plot.title, axis.text.x 및 axis.text.y를 설정하여 theme() 함수 내에 사용하면 되며, 이는 element_text() 내부에서 지정해야합니다. element_blank()로 설정하면 해당 라벨은 완전히 사라집니다. 범례의 제목을 지정하는 법은 약간 복잡합니다. 만일 범례가 색상을 의미한다면(그룹별로 색이 다르게 표현된 경우), scale_color_discrete() 함수 내에서 name을 지정하여 변경할 수 있습니다.

gg1 = gg +
 theme(plot.title = element_text(size = 30, face = "bold"),
       axis.text.x = element_text(size = 15),
       axis.text.y = element_text(size = 15),
       axis.title.x = element_text(size = 25),
       axis.title.y = element_text(size = 25)) +
 scale_color_discrete(name = "Cut of diamonds")
print(gg1)




항목
내용
세부 항목
세부 내용
plot.title
그림 제목
element_text(size = 30, face = "bold")
사이즈 30, 굵게 표시
axis.text.x
X축 범례
element_text(size = 15)
사이즈 15
axis.text.y
Y축 범례
element_text(size = 15)
사이즈 15
axis.title.x
X축 제목
element_text(size = 25)
사이즈 25
axis.title.y
Y축 제목
element_text(size = 25)
사이즈 25
scale_color_discrete
색상 범례
name = "Cut of diamonds"
이름 지정


그룹별로 색상이 아닌 모양이 다르게 표현된 범례라면 scale_shape_discrete(name="legend title") 혹은 scale_shape_continuous(name="legend title")를 사용하여 범례의 이름을 변경할 수 있습니다. 이산 변수일 경우에는 discrete, 연속 변수일 경우에는 continuous를 사용합니다.

ggplot(diamonds, aes(x = carat, y = price, color = cut, shape = color)) +
 geom_point() +
 scale_color_discrete(name = "Cut of diamonds") +
 scale_shape_discrete(name = 'Color of diamonds')



5. 면 (Facets) 이전 차트에서는 동일한 차트에 다른 모든 cut 값을 표시하는 산점도를 사용했습니다. 각기 다른 cut 값을 각각의 차트에 표현하는 방법은 다음과 같습니다.

gg1 + facet_wrap( ~ cut, ncol = 3)



facet_wrap() 함수를 이용하여 cut 별로 다른 그래프로 표현하였으며, ncol 변수를 통해 3개의 열에 나타내었습니다. 두가지 변수에 따라 그래프를 분할할 수도 있습니다. 아래의 코드에서 ‘~’를 기준으로 color와 cut에 따라 그래프가 분할됩니다.

gg1 + facet_wrap(color ~ cut)


color는 총 7개 변수, cut은 총 5개 변수가 있으므로 7 X 5, 총 35개 그래프가 나타나며, X축과 Y축은 gg1에서 지정한 것과 같이 Carat과 Price가 설정되었습니다.


facet_wrap()에서 X축과 Y축의 축척은 기본적으로 모든 점을 수용하도록 고정됩니다. 위의 그림은 모든 X축이 1~5, Y축이 0~15000으로 설정되어 있습니다. 만일 scales = free 인수를 설정할 경우 축척이 고정되지 않고 각 그림에 따라 다르게 설정됩니다.

gg1 + facet_wrap(color ~ cut, scales="free")

scales=free 인수를 추가할 경우 각 그림의 X축이 다르게 설정되었습니다.
두개 변수에 따른 비교를 위해서는 facet_wrap() 보다는 facet_grid() 함수가 더욱 깔끔한 그림을 나타냅니다. 사용방법은 위와 동일하게 facet_grid(formula) 입니다.

gg1 + facet_grid(color ~ cut)


전체 그래프의 행은 ‘~’ 표시의 좌측의 color 변수가(D, E, F, G, H, I, J), 열은 우측의 cut 변수가(Fair, Good, Very Good…) 지정되며, facet_wrap()에 비해 비교하기가 훨씬 쉬운 모습입니다.


6. 일반적으로 사용되는 그래프들

6.1 시계열

> head(economics)
# A tibble: 6 x 6
 date         pce pop psavert uempmed unemploy
       <int>       <int>
1 1967-07-01  507. 198712    12.5     4.5     2944
2 1967-08-01  510. 198911    12.5     4.7     2945
3 1967-09-01  516. 199113    11.7     4.6     2958
4 1967-10-01  513. 199311    12.5     4.9     3143
5 1967-11-01  518. 199498    12.5     4.7     3066
6 1967-12-01  526. 199657    12.1     4.8     3018

ggplot(economics, aes(x = date, y = uempmed)) +
 geom_line()


geom_line()은 선형 그래프를 나타내며, 이를 통해 시계열 자료를 표현할 수 있습니다.


6.2 여러개의 시계열 데이터를 그리기

방법1 : 여러 레이어에 시계열 그래프를 계속 추가합니다. 방법2: reshape2 패키지의 melt() 함수를 사용하여 데이터 구조를 변경한 후, geom_line() 레이어를 추가하고 변수에 따라 color가 다르게 미학을 설정합니다. melt() 함수 사용법 방법3: tidyr 패키지의 gather() 함수를 사용하여 데이터 구조를 변경한 후, geom_line() 레이어를 추가하고 변수에 따라 color가 다르게 미학을 설정합니다. gather() 함수 사용법


# Approach 1:
ggplot(economics) +
 geom_line(aes(x = date, y = pce, color = "pcs")) +
 geom_line(aes(x = date, y = unemploy, col = "unemploy"))

# Approach 2:
install.packages('reshape2')
library(reshape2)

df = melt(economics[, c("date", "pce", "unemploy")], id = "date")
ggplot(df) +
 geom_line(aes(x = date, y = value, color = variable))

# Approach 3:
install.packages('tidyr')
library(tidyr)

df2 = gather(economics[, c("date", "pce", "unemploy")],
            key = pce, value = unemploy, -date)
ggplot(df2) +
 geom_line(aes(x = date, y = unemploy, color = pce))



3가지 방법 모두 동일한 결과가 얻어짐이 확인됩니다.
ggplot2의 단점은 동일한 플롯에서 여러 개의 Y축을 가져올 수 없다는 것입니다. 같은 스케일에서 여러 개의 시계열을 그릴 경우 시리즈 중 일부가 작게 나타날 수 있습니다. 이를 방지하려면 facet_wrap() 함수에서 scale=’free’로 인수를 지정하면 됩니다.

df = melt(economics[, c("date", "pce", "unemploy", "psavert")], id = "date")
ggplot(df) +
 geom_line(aes(x = date, y = value, color = variable)) +
 facet_wrap( ~ variable, scales = "free")


6.3 막대형 차트 기본적으로 ggplot은 '카운트' 막대형 차트를 만듭니다. 즉, X 변수에 지정한 항목의 빈도를 계산하고 그 값을 그립니다. 이 형식에서는 Y 변수를 지정할 필요가 없습니다. 그러나, Y 변수에 주어진 절대값의 막대형 차트를 만들고 싶다면 geom_bar() 내부에 stat = "identity"를 설정해주면 됩니다.

> mtcars$cyl
[1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4

plot1 = ggplot(mtcars, aes(x = cyl)) +
 geom_bar()
print(plot1)


mtcars의 cyl 열에는 4, 6, 8의 변수가 존재하며, geom_bar()를 이용할 경우 변수들의 개수를 구하여 막대형 차트로 표현하게 됩니다.



df = data.frame(var = c("a", "b", "c"), nums = c(1:3))
plot2 = ggplot(df, aes(x = var, y = nums)) +
 geom_bar(stat = "identity")
print(plot2)


stat=’identity’를 지정할 경우 y변수로 지정된 nums열의 값, 즉 1,2,3에 맞게 막대형 차트가 그려지게 됩니다.


6.4 커스텀 레이아웃 gridExtra 패키지는 하나의 그림 안에 여러개의 ggplot 그림이 그려지게 합니다.

install.packages('gridExtra')
library(gridExtra)
grid.arrange(plot1, plot2, ncol = 2)



6.5 좌표 뒤집기

df = data.frame(var = c("a", "b", "c"), nums = c(1:3))
ggplot(df, aes(x = var, y = nums)) +
 geom_bar(stat = "identity") +
 coord_flip() +
 labs(title = "Coordinates are flipped")


coord_flip() 함수를 추가할 경우, X축과 Y축의 뒤바뀌게 됩니다.


6.6 X축과 Y축 값 제한 조정하기 X축과 Y 값에 한계를 주는데는 다음 3가지 방법이 있습니다.

  1. Using coord_cartesian(xlim=c(x1,x2))
  2. Using xlim(c(x1,x2))
  3. Using scale_x_continuous(limits=c(x1,x2))

2번과 3번 방법은 지정한 축 한계를 초과하는 데이터를  삭제합니다. 따라서 평활선을 추가하면 결과가 왜곡됩니다. 1번(coord_cartesian) 방법은 데이터를 삭제하지 않는 대신 차트의 특정 영역을 확대합니다.

ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() +
 geom_smooth() +
 coord_cartesian(ylim = c(0, 10000)) +
 labs(title="Coord_cartesian zoomed in!")


y축의 한계를 0부터 10000까지 설정하였으며, coord_cartesian() 함수를 사용할 경우 전체 플롯 중 해당 영역 부분 만큼을 확대하여 보여줍니다. 따라서 geom_smooth()로 나타난 평활선은 전체 데이터를 기준으로 작성되어 y축의 한계를 넘어서는 모습을 보입니다.



ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() +
 geom_smooth() +
 ylim(c(0, 10000)) +
 labs(title="Datapoints deleted: Note the change in smoothing lines!")

Warning messages:
1: Removed 5222 rows containing non-finite values (stat_smooth).
2: Removed 5222 rows containing missing values (geom_point).

xlim()을 사용하거나 scale_x_continuous()를 사용할 경우, 한계값을 초과하는 5222개의 데이터는 삭제된 후 데이터가 표시됩니다. 따라서 평활선도 표시된 점들을 바탕으로 그려지기에 y축의 한계를 벗어나지 않습니다.


6.7 테마 바꾸기

기본 ggplot2 테마 외에도 여러 테마 중 하나를 사용하여 플롯의 모양과 느낌을 변경할 수 있습니다.

  1. theme_gray()
  2. theme_bw()
  3. theme_linedraw()
  4. theme_light()
  5. theme_minimal()
  6. theme_classic()
  7. theme_void()

ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() +
 geom_smooth() +
 theme_bw() +
 labs(title="bw Theme")


6.8 범례 삭제 및 위치 변경

theme(legend.position = "none")을 설정하여 범례를 제거 할 수 있습니다. none 대신에 top을 지정한다면, 즉 theme(legend.position = "top")으로 설정하면 플롯 주변에서 범례를 이동할 수 있습니다. legend.postion()을 플롯 안의 좌표로 설정하면 범례를 플롯 내부에 배치 할 수도 있습니다. legend.justification() 역시 범례의 위치를 지정합니다.
.
p1 = ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() +
 theme(legend.position = "none") +
 labs(title = "legend.position = 'none'")

p2 = ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() +
 theme(legend.position = "top") +
 labs(title = "legend.position = 'top'")

p3 = ggplot(diamonds, aes(x = carat, y = price, color = cut)) +
 geom_point() +
 labs(title = "legend.position = 'coords inside plot'") +
 theme(legend.position = c(1,0), legend.justification = c(1,0))

grid.arrange(p1, p2, p3, ncol = 3)

첫번째 그림은 범례가 삭제되었으며, 두번째 그림은 그림 상단에 위치합니다. 세번째 그림은 범례가 그림 내부에 위치하며, 그 지점은 X축에서 1, Y축에서 0 지점입니다.


6.9 눈금선
그림의 배경색 및 주 눈금선, 보조 눈금선의 색도 바꿀 수 있습니다.

ggplot(mtcars, aes(x=cyl)) +
 geom_bar(fill='darkgoldenrod2') +
 theme(panel.background = element_rect(fill = 'steelblue'),
       panel.grid.major = element_line(color = "firebrick", size = 3),
       panel.grid.minor = element_line(color = "blue", size = 1))

항목
내용
세부 항목
세부 내용
panel.background
그림 바탕색
element_rect(fill = 'steelblue')
색 변경
panel.grid.major
주 눈금선
element_line(color = "firebrick", size = 3)
색 및 사이즈 변경
panel.grid.minor
보조 눈금선
element_line(color = "blue", size = 1)
색 및 사이즈 변경

6.10 플롯 여백 및 배경
플롯과 배경 간의 여백 및 색을 지정할 수도 있습니다.

ggplot(mtcars, aes(x = cyl)) +
 geom_bar(fill = "firebrick") +
 theme(plot.background = element_rect(fill = "steelblue"),
       plot.margin = unit(c(2, 4, 1, 3), "cm"))

plot.margin()을 통해 여백 공간을 설정할 수 있으며, 4개 숫자는 각각 위, 오른쪽, 아래, 왼쪽에 해당하는 값입니다.


6.11 텍스트

geom_text()를 통해 플롯 내에 텍스트를 추가할 수 있습니다.

ggplot(mtcars, aes(x = cyl)) +
 geom_bar() +
 geom_text(aes(label = 'This text is at x = 3 & y = 13',
               x = 3, y = 13,
               vjust = 'inward', hjust = 'inward'),
           size = 11)

aes() 내부의 label을 통헤 입력하고자 하는 텍스트를, X와 Y에 원하는 좌표를 설정할 수 있습니다. vjust와 hjust는 글의 정렬 기준을 의미하며, inward는 문단을 플롯의 가운데로 정렬합니다. size를 통해 텍스트의 크기를 변경할 수도 있습니다.


6.12 그림의 저장

plot1 = ggplot(mtcars, aes(x = cyl)) +
 geom_bar()
ggsave("myggplot.png", plot = plot1)

ggsave() 함수를 통해 plot1에 저장된 그림을 ‘myggplot.png’ 이름으로 저장할 수 있습니다.

댓글 없음:

댓글 쓰기