9  레이어(Layers)

9.1 소개

Chapter 1 에서 산점도, 막대 차트, 상자 그림을 만드는 방법 그 이상을 배웠습니다. ggplot2로 어떤 유형의 플롯이든 만드는 데 사용할 수 있는 기초를 배웠습니다.

이 장에서는 레이어드 그래픽 문법(layered grammar of graphics)에 대해 배우면서 그 기초를 확장할 것입니다. 심미적 매핑, 기하학적 객체, 패싯에 대해 더 깊이 파고드는 것으로 시작하겠습니다. 그런 다음 플롯을 생성할 때 ggplot2가 내부적으로 수행하는 통계적 변환에 대해 배울 것입니다. 이러한 변환은 막대 플롯의 막대 높이나 상자 그림의 중앙값과 같이 플롯할 새 값을 계산하는 데 사용됩니다. 또한 플롯에 지옴이 표시되는 방식을 수정하는 위치 조정(position adjustments)에 대해서도 배울 것입니다. 마지막으로 좌표계를 간략하게 소개할 것입니다.

이러한 각 레이어에 대한 모든 단일 함수와 옵션을 다루지는 않겠지만, ggplot2가 제공하는 가장 중요하고 일반적으로 사용되는 기능을 안내하고 ggplot2를 확장하는 패키지를 소개할 것입니다.

9.1.1 선수 지식

이 장은 ggplot2에 중점을 둡니다. 이 장에서 사용되는 데이터셋, 도움말 페이지, 함수에 액세스하려면 다음 코드를 실행하여 tidyverse를 로드하세요:

library(tidyverse)
#> Warning: package 'ggplot2' was built under R version 4.5.2
#> Warning: package 'readr' was built under R version 4.5.2

9.2 심미적 매핑

“그림의 가장 큰 가치는 우리가 결코 볼 것이라고 예상하지 못했던 것을 알아차리게 할 때이다.” — 존 튜키(John Tukey)

ggplot2 패키지와 함께 제공되는 mpg 데이터 프레임에는 38개의 자동차 모델에 대한 234개의 관측값이 포함되어 있음을 기억하세요.

mpg
#> # A tibble: 234 × 11
#>   manufacturer model displ  year   cyl trans      drv     cty   hwy fl   
#>   <chr>        <chr> <dbl> <int> <int> <chr>      <chr> <int> <int> <chr>
#> 1 audi         a4      1.8  1999     4 auto(l5)   f        18    29 p    
#> 2 audi         a4      1.8  1999     4 manual(m5) f        21    29 p    
#> 3 audi         a4      2    2008     4 manual(m6) f        20    31 p    
#> 4 audi         a4      2    2008     4 auto(av)   f        21    30 p    
#> 5 audi         a4      2.8  1999     6 auto(l5)   f        16    26 p    
#> 6 audi         a4      2.8  1999     6 manual(m5) f        18    26 p    
#> # ℹ 228 more rows
#> # ℹ 1 more variable: class <chr>

mpg의 변수 중 일부는 다음과 같습니다:

  1. displ: 자동차의 엔진 크기(리터 단위). 수치형 변수입니다.

  2. hwy: 고속도로에서의 자동차 연비(갤런당 마일, mpg). 연비가 낮은 자동차는 연비가 높은 자동차보다 같은 거리를 이동할 때 더 많은 연료를 소비합니다. 수치형 변수입니다.

  3. class: 자동차 유형. 범주형 변수입니다.

다양한 자동차 class에 대해 displhwy 사이의 관계를 시각화하는 것으로 시작해 봅시다. 수치형 변수를 xy 심미성에 매핑하고 범주형 변수를 colorshape 같은 심미성에 매핑하는 산점도로 이를 수행할 수 있습니다.

# 왼쪽
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point()

# 오른쪽
ggplot(mpg, aes(x = displ, y = hwy, shape = class)) +
  geom_point()
#> Warning: The shape palette can deal with a maximum of 6 discrete values because more
#> than 6 becomes difficult to discriminate
#> ℹ you have requested 7 values. Consider specifying shapes manually if you
#>   need that many of them.
#> Warning: Removed 62 rows containing missing values or values outside the scale range
#> (`geom_point()`).

나란히 놓인 두 개의 산점도. 둘 다 자동차의 고속도로 연비 대 엔진 크기를  시각화하며 음의 연관성을 보여줍니다. 왼쪽 플롯에서는 class가 color  심미성에 매핑되어 각 클래스에 대해 서로 다른 색상이 나타납니다.  오른쪽 플롯에서는 class가 shape 심미성에 매핑되어 suv를 제외한  각 클래스에 대해 서로 다른 플롯 문자 모양이 나타납니다.  각 플롯에는 색상 또는 모양과 클래스 변수 수준 간의 매핑을 보여주는  범례가 함께 제공됩니다.

나란히 놓인 두 개의 산점도. 둘 다 자동차의 고속도로 연비 대 엔진 크기를  시각화하며 음의 연관성을 보여줍니다. 왼쪽 플롯에서는 class가 color  심미성에 매핑되어 각 클래스에 대해 서로 다른 색상이 나타납니다.  오른쪽 플롯에서는 class가 shape 심미성에 매핑되어 suv를 제외한  각 클래스에 대해 서로 다른 플롯 문자 모양이 나타납니다.  각 플롯에는 색상 또는 모양과 클래스 변수 수준 간의 매핑을 보여주는  범례가 함께 제공됩니다.

classshape에 매핑될 때 두 가지 경고가 발생합니다:

1: The shape palette can deal with a maximum of 6 discrete values because more than 6 becomes difficult to discriminate; you have 7. Consider specifying shapes manually if you must have them. (모양 팔레트는 최대 6개의 이산 값을 처리할 수 있습니다. 6개 이상은 구별하기 어렵기 때문입니다. 7개가 있습니다. 꼭 필요하다면 모양을 수동으로 지정하는 것을 고려하세요.)

2: Removed 62 rows containing missing values (geom_point()). (결측값이 포함된 62개 행이 제거되었습니다 (geom_point()).)

기본적으로 ggplot2는 한 번에 6개의 모양만 사용하므로 모양 심미성을 사용할 때 추가 그룹은 플롯되지 않습니다. 두 번째 경고는 이와 관련이 있습니다. 데이터셋에 62대의 SUV가 있는데 플롯되지 않았습니다.

마찬가지로 class를 점의 크기와 투명도를 제어하는 size 또는 alpha 심미성에 매핑할 수도 있습니다.

# 왼쪽
ggplot(mpg, aes(x = displ, y = hwy, size = class)) +
  geom_point()
#> Warning: Using size for a discrete variable is not advised.

# 오른쪽
ggplot(mpg, aes(x = displ, y = hwy, alpha = class)) +
  geom_point()
#> Warning: Using alpha for a discrete variable is not advised.

나란히 놓인 두 개의 산점도. 둘 다 자동차의 고속도로 연비 대 엔진 크기를  시각화하며 음의 연관성을 보여줍니다. 왼쪽 플롯에서는 class가 size  심미성에 매핑되어 각 클래스에 대해 서로 다른 크기가 나타납니다.  오른쪽 플롯에서는 class가 alpha 심미성에 매핑되어 각 클래스에 대해  서로 다른 알파(투명도) 수준이 나타납니다.  각 플롯에는 크기 또는 알파 수준과 클래스 변수 수준 간의 매핑을 보여주는  범례가 함께 제공됩니다.

나란히 놓인 두 개의 산점도. 둘 다 자동차의 고속도로 연비 대 엔진 크기를  시각화하며 음의 연관성을 보여줍니다. 왼쪽 플롯에서는 class가 size  심미성에 매핑되어 각 클래스에 대해 서로 다른 크기가 나타납니다.  오른쪽 플롯에서는 class가 alpha 심미성에 매핑되어 각 클래스에 대해  서로 다른 알파(투명도) 수준이 나타납니다.  각 플롯에는 크기 또는 알파 수준과 클래스 변수 수준 간의 매핑을 보여주는  범례가 함께 제공됩니다.

이 두 가지 모두 경고를 발생시킵니다:

Using alpha for a discrete variable is not advised. (이산 변수에 알파를 사용하는 것은 권장되지 않습니다.)

순서가 없는 이산(범주형) 변수(class)를 순서가 있는 심미성(size 또는 alpha)에 매핑하는 것은 일반적으로 좋은 생각이 아닙니다. 사실 존재하지 않는 순위를 암시하기 때문입니다.

심미성을 매핑하면 나머지는 ggplot2가 처리합니다. 심미성에 사용할 합리적인 척도(scale)를 선택하고 수준과 값 사이의 매핑을 설명하는 범례를 구성합니다. x와 y 심미성의 경우 ggplot2는 범례를 만들지 않고 눈금 표시와 레이블이 있는 축 선을 만듭니다. 축 선은 범례와 동일한 정보를 제공합니다. 위치와 값 사이의 매핑을 설명합니다.

변수 매핑에 의존하여 모양을 결정하는 대신 지옴 함수의 인수(aes() 외부)로 지옴의 시각적 속성을 수동으로 설정할 수도 있습니다. 예를 들어 플롯의 모든 점을 파란색으로 만들 수 있습니다:

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(color = "blue")

자동차의 고속도로 연비 대 엔진 크기의 산점도로 음의 연관성을  보여줍니다. 모든 점은 파란색입니다.

여기서 색상은 변수에 대한 정보를 전달하지 않고 플롯의 모양만 변경합니다. 해당 심미성에 맞는 값을 선택해야 합니다:

  • 문자열로 된 색상 이름, 예: color = "blue"
  • mm 단위의 점 크기, 예: size = 1
  • 숫자로 된 점 모양, 예: shape = 1, Figure 9.1 에 표시된 대로.
모양과 그것을 나타내는 숫자 사이의 매핑: 0 - 빈 사각형,  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 - 채워진 역삼각형.
Figure 9.1: R에는 숫자로 식별되는 26개의 내장 모양이 있습니다. 일부 중복되어 보이는 것이 있습니다. 예를 들어 0, 15, 22는 모두 정사각형입니다. 차이점은 colorfill 심미성의 상호 작용에서 비롯됩니다. 빈 모양(0–14)은 color에 의해 결정되는 테두리가 있습니다. 꽉 찬 모양(15–20)은 color로 채워집니다. 채워진 모양(21–25)은 color의 테두리가 있고 fill로 채워집니다. 모양은 유사한 모양을 서로 옆에 유지하도록 배열되어 있습니다.

지금까지 점 지옴을 사용할 때 산점도에서 매핑하거나 설정할 수 있는 심미성에 대해 논의했습니다. https://ggplot2.tidyverse.org/articles/ggplot2-specs.html의 심미적 사양 비네트에서 가능한 모든 심미적 매핑에 대해 자세히 알아볼 수 있습니다.

플롯에 사용할 수 있는 특정 심미성은 데이터를 나타내는 데 사용하는 지옴에 따라 다릅니다. 다음 섹션에서는 지옴에 대해 더 깊이 파고들 것입니다.

9.2.1 연습문제

  1. hwydispl의 산점도를 만드는데, 점들을 분홍색으로 채워진 삼각형으로 만드세요.

  2. 다음 코드가 파란색 점이 있는 플롯을 생성하지 않은 이유는 무엇입니까?

    ggplot(mpg) + 
      geom_point(aes(x = displ, y = hwy, color = "blue"))
  3. stroke 심미성은 무엇을 합니까? 어떤 모양과 함께 작동합니까? (힌트: ?geom_point를 사용하세요)

  4. aes(color = displ < 5)와 같이 변수 이름이 아닌 다른 것에 심미성을 매핑하면 어떻게 됩니까? 참고로 x와 y도 지정해야 합니다.

9.3 기하학적 객체(Geometric objects)

이 두 플롯은 어떻게 유사합니까?

두 개의 플롯이 있습니다. 왼쪽 플롯은 자동차의 고속도로 연비 대 엔진  크기의 산점도이고 오른쪽 플롯은 이 변수들 간의 관계의 궤적을 따르는  매끄러운 곡선을 보여줍니다. 매끄러운 곡선 주변의 신뢰 구간도  표시됩니다.

두 개의 플롯이 있습니다. 왼쪽 플롯은 자동차의 고속도로 연비 대 엔진  크기의 산점도이고 오른쪽 플롯은 이 변수들 간의 관계의 궤적을 따르는  매끄러운 곡선을 보여줍니다. 매끄러운 곡선 주변의 신뢰 구간도  표시됩니다.

두 플롯 모두 동일한 x 변수, 동일한 y 변수를 포함하며 동일한 데이터를 설명합니다. 하지만 플롯은 동일하지 않습니다. 각 플롯은 데이터를 나타내기 위해 다른 기하학적 객체, 지옴(geom)을 사용합니다. 왼쪽 플롯은 점 지옴을 사용하고 오른쪽 플롯은 데이터에 적합된 매끄러운 선인 매끄러운(smooth) 지옴을 사용합니다.

플롯의 지옴을 변경하려면 ggplot()에 추가하는 지옴 함수를 변경하세요. 예를 들어 위의 플롯을 만들기 위해 다음 코드를 사용할 수 있습니다:

# 왼쪽
ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point()

# 오른쪽
ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_smooth()
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

ggplot2의 모든 지옴 함수는 지옴 레이어에서 로컬로 정의되거나 ggplot() 레이어에서 전역적으로 정의된 mapping 인수를 취합니다. 그러나 모든 심미성이 모든 지옴과 작동하는 것은 아닙니다. 점의 모양을 설정할 수는 있지만 선의 “모양”을 설정할 수는 없습니다. 시도하면 ggplot2는 해당 심미적 매핑을 조용히 무시합니다. 반면에 선의 선형(linetype)을 설정할 있습니다. geom_smooth()는 선형에 매핑한 변수의 각 고유 값에 대해 다른 선형을 가진 다른 선을 그립니다.

# 왼쪽
ggplot(mpg, aes(x = displ, y = hwy, shape = drv)) + 
  geom_smooth()

# 오른쪽
ggplot(mpg, aes(x = displ, y = hwy, linetype = drv)) + 
  geom_smooth()

자동차의 고속도로 연비 대 엔진 크기의 두 플롯. 데이터는 매끄러운 곡선으로 표현됩니다. 왼쪽에는 세 개의 매끄러운  곡선이 모두 동일한 선형으로 있습니다. 오른쪽에는 각 구동 방식 유형에  대해 다른 선형(실선, 파선, 긴 파선)을 가진 세 개의 매끄러운 곡선이  있습니다. 두 플롯 모두 매끄러운 곡선 주변의 신뢰 구간도 표시됩니다.

자동차의 고속도로 연비 대 엔진 크기의 두 플롯. 데이터는 매끄러운 곡선으로 표현됩니다. 왼쪽에는 세 개의 매끄러운  곡선이 모두 동일한 선형으로 있습니다. 오른쪽에는 각 구동 방식 유형에  대해 다른 선형(실선, 파선, 긴 파선)을 가진 세 개의 매끄러운 곡선이  있습니다. 두 플롯 모두 매끄러운 곡선 주변의 신뢰 구간도 표시됩니다.

여기서 geom_smooth()는 자동차의 구동 방식을 설명하는 drv 값에 따라 자동차를 세 개의 선으로 분리합니다. 한 선은 4 값을 가진 모든 점을 설명하고, 한 선은 f 값을 가진 모든 점을 설명하며, 한 선은 r 값을 가진 모든 점을 설명합니다. 여기서 4는 4륜 구동, f는 전륜 구동, r은 후륜 구동을 나타냅니다.

이것이 이상하게 들린다면 원시 데이터 위에 선을 겹쳐 놓고 drv에 따라 모든 것을 색칠하면 더 명확하게 만들 수 있습니다.

ggplot(mpg, aes(x = displ, y = hwy, color = drv)) + 
  geom_point() +
  geom_smooth(aes(linetype = drv))

자동차의 고속도로 연비 대 엔진 크기의 플롯. 데이터는 점(구동 방식별로  색상 지정됨)과 매끄러운 곡선(선형도 구동 방식에 따라 결정됨)으로  표현됩니다. 매끄러운 곡선 주변의 신뢰 구간도 표시됩니다.

이 플롯에는 동일한 그래프에 두 개의 지옴이 포함되어 있음을 주목하세요.

geom_smooth()와 같은 많은 지옴은 단일 기하학적 객체를 사용하여 여러 행의 데이터를 표시합니다. 이러한 지옴의 경우 group 심미성을 범주형 변수로 설정하여 여러 객체를 그릴 수 있습니다. ggplot2는 그룹화 변수의 각 고유 값에 대해 별도의 객체를 그립니다. 실제로 ggplot2는 심미성을 이산 변수에 매핑할 때마다( linetype 예제와 같이) 이러한 지옴에 대해 데이터를 자동으로 그룹화합니다. group 심미성 자체는 지옴에 범례나 구별되는 특징을 추가하지 않기 때문에 이 기능에 의존하는 것이 편리합니다.

# 왼쪽
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_smooth()

# 가운데
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_smooth(aes(group = drv))

# 오른쪽
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_smooth(aes(color = drv), show.legend = FALSE)

세 개의 플롯, 각각 y축에 고속도로 연비, x축에 자동차 엔진 크기가 있으며,  데이터는 매끄러운 곡선으로 표현됩니다. 첫 번째 플롯에는 이 두 변수만 있고, 가운데 플롯에는 구동 방식의 각 수준에  대해 세 개의 별도 매끄러운 곡선이 있으며, 오른쪽 플롯에는 구동 방식의  각 수준에 대해 동일한 세 개의 별도 매끄러운 곡선이 있을 뿐만 아니라  이 곡선들이 다른 색상으로 플롯됩니다.  매끄러운 곡선 주변의 신뢰 구간도 표시됩니다.

세 개의 플롯, 각각 y축에 고속도로 연비, x축에 자동차 엔진 크기가 있으며,  데이터는 매끄러운 곡선으로 표현됩니다. 첫 번째 플롯에는 이 두 변수만 있고, 가운데 플롯에는 구동 방식의 각 수준에  대해 세 개의 별도 매끄러운 곡선이 있으며, 오른쪽 플롯에는 구동 방식의  각 수준에 대해 동일한 세 개의 별도 매끄러운 곡선이 있을 뿐만 아니라  이 곡선들이 다른 색상으로 플롯됩니다.  매끄러운 곡선 주변의 신뢰 구간도 표시됩니다.

세 개의 플롯, 각각 y축에 고속도로 연비, x축에 자동차 엔진 크기가 있으며,  데이터는 매끄러운 곡선으로 표현됩니다. 첫 번째 플롯에는 이 두 변수만 있고, 가운데 플롯에는 구동 방식의 각 수준에  대해 세 개의 별도 매끄러운 곡선이 있으며, 오른쪽 플롯에는 구동 방식의  각 수준에 대해 동일한 세 개의 별도 매끄러운 곡선이 있을 뿐만 아니라  이 곡선들이 다른 색상으로 플롯됩니다.  매끄러운 곡선 주변의 신뢰 구간도 표시됩니다.

매핑을 지옴 함수에 넣으면 ggplot2는 이를 해당 레이어에 대한 로컬 매핑으로 취급합니다. 이 매핑을 사용하여 해당 레이어에 대해서만 전역 매핑을 확장하거나 덮어씁니다. 이를 통해 다른 레이어에 다른 심미성을 표시할 수 있습니다.

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color = class)) + 
  geom_smooth()

자동차의 고속도로 연비 대 엔진 크기의 산점도, 여기서 점들은 자동차  클래스에 따라 색상이 지정됩니다. 고속도로 연비 대 엔진 크기 간 관계의  궤적을 따르는 매끄러운 곡선이 그 주위의 신뢰 구간과 함께 겹쳐져  있습니다.

동일한 아이디어를 사용하여 각 레이어에 대해 다른 data를 지정할 수 있습니다. 여기서는 빨간 점과 열린 원을 사용하여 2인승 자동차를 강조 표시합니다. geom_point()의 로컬 데이터 인수는 해당 레이어에 대해서만 ggplot()의 전역 데이터 인수를 덮어씁니다.

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point() + 
  geom_point(
    data = mpg |> filter(class == "2seater"), 
    color = "red"
  ) +
  geom_point(
    data = mpg |> filter(class == "2seater"), 
    shape = "circle open", size = 3, color = "red"
  )

자동차의 고속도로 연비 대 엔진 크기의 산점도, 여기서 2인승 자동차는  빨간 점과 열린 원으로 강조 표시됩니다.

지옴은 ggplot2의 기본 구성 요소입니다. 지옴을 변경하여 플롯의 모양을 완전히 바꿀 수 있으며, 서로 다른 지옴은 데이터의 서로 다른 특징을 드러낼 수 있습니다. 예를 들어 아래의 히스토그램과 밀도 플롯은 고속도로 마일리지의 분포가 이봉형이고 오른쪽으로 치우쳐 있음을 보여주는 반면, 상자 그림은 두 개의 잠재적인 이상치를 보여줍니다.

# 왼쪽
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(binwidth = 2)

# 가운데
ggplot(mpg, aes(x = hwy)) +
  geom_density()

# 오른쪽
ggplot(mpg, aes(x = hwy)) +
  geom_boxplot()

세 개의 플롯: 고속도로 마일리지의 히스토그램, 밀도 플롯, 상자 그림.

세 개의 플롯: 고속도로 마일리지의 히스토그램, 밀도 플롯, 상자 그림.

세 개의 플롯: 고속도로 마일리지의 히스토그램, 밀도 플롯, 상자 그림.

ggplot2는 40개 이상의 지옴을 제공하지만 이것이 만들 수 있는 모든 가능한 플롯을 커버하는 것은 아닙니다. 다른 지옴이 필요한 경우 먼저 확장 패키지를 살펴보고 다른 누군가가 이미 구현했는지 확인하는 것이 좋습니다(샘플링은 https://exts.ggplot2.tidyverse.org/gallery/ 참조). 예를 들어 ggridges 패키지(https://wilkelab.org/ggridges)는 릿지라인(ridgeline) 플롯을 만드는 데 유용하며, 이는 범주형 변수의 여러 수준에 대해 수치형 변수의 밀도를 시각화하는 데 유용할 수 있습니다. 다음 플롯에서는 새 지옴(geom_density_ridges())을 사용했을 뿐만 아니라 동일한 변수를 여러 심미성(drvy, fill, color에)에 매핑하고 심미성(alpha = 0.5)을 설정하여 밀도 곡선을 투명하게 만들었습니다.

library(ggridges)

ggplot(mpg, aes(x = hwy, y = drv, fill = drv, color = drv)) +
  geom_density_ridges(alpha = 0.5, show.legend = FALSE)
#> Picking joint bandwidth of 1.28

후륜 구동, 전륜 구동, 4륜 구동 자동차의 고속도로 마일리지에 대한 밀도 곡선이 별도로 플롯되었습니다. 분포는 후륜 및 4륜 구동 자동차의 경우 이봉형이고 대략 대칭이며 전륜 구동 자동차의 경우 단봉형이고 오른쪽으로 치우쳐 있습니다.

ggplot2가 제공하는 모든 지옴과 패키지의 모든 함수에 대한 포괄적인 개요를 얻을 수 있는 가장 좋은 곳은 참조 페이지입니다: https://ggplot2.tidyverse.org/reference. 단일 지옴에 대해 더 자세히 알아보려면 도움말을 사용하세요(예: ?geom_smooth).

9.3.1 연습문제

  1. 선 차트를 그리기 위해 어떤 지옴을 사용하겠습니까? 상자 그림은? 히스토그램은? 영역 차트는?

  2. 이 장의 앞부분에서 설명 없이 show.legend를 사용했습니다:

    ggplot(mpg, aes(x = displ, y = hwy)) +
      geom_smooth(aes(color = drv), show.legend = FALSE)

    여기서 show.legend = FALSE는 무엇을 합니까? 제거하면 어떻게 됩니까? 앞에서 왜 이것을 사용했다고 생각합니까?

  3. geom_smooth()se 인수는 무엇을 합니까?

  4. 다음 그래프를 생성하는 데 필요한 R 코드를 다시 작성하세요. 플롯에서 범주형 변수가 사용되는 곳은 drv입니다.

    이 그림에는 3x2 그리드로 배열된 6개의 산점도가 있습니다. 모든 플롯에서  y축은 자동차의 고속도로 연비이고 x축은 엔진 크기입니다. 첫 번째 플롯은  모든 점을 검은색으로 표시하고 매끄러운 곡선을 그 위에 겹쳐 놓았습니다.  두 번째 플롯도 점이 모두 검은색이며 구동 방식의 각 수준에 대해 별도의  매끄러운 곡선이 겹쳐져 있습니다. 세 번째 플롯에서 점과 매끄러운  곡선은 구동 방식의 각 수준에 대해 서로 다른 색상으로 표현됩니다.  네 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되지만 전체 데이터에 적합된 단일 매끄러운 선만 있습니다.  다섯 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되고 구동 방식의 각 수준에 대해 다른 선형을 가진 별도의 매끄러운  곡선이 적합됩니다. 그리고 마지막으로 여섯 번째 플롯에서 점은  구동 방식의 각 수준에 대해 서로 다른 색상으로 표현되며 두꺼운 흰색  테두리가 있습니다.

    이 그림에는 3x2 그리드로 배열된 6개의 산점도가 있습니다. 모든 플롯에서  y축은 자동차의 고속도로 연비이고 x축은 엔진 크기입니다. 첫 번째 플롯은  모든 점을 검은색으로 표시하고 매끄러운 곡선을 그 위에 겹쳐 놓았습니다.  두 번째 플롯도 점이 모두 검은색이며 구동 방식의 각 수준에 대해 별도의  매끄러운 곡선이 겹쳐져 있습니다. 세 번째 플롯에서 점과 매끄러운  곡선은 구동 방식의 각 수준에 대해 서로 다른 색상으로 표현됩니다.  네 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되지만 전체 데이터에 적합된 단일 매끄러운 선만 있습니다.  다섯 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되고 구동 방식의 각 수준에 대해 다른 선형을 가진 별도의 매끄러운  곡선이 적합됩니다. 그리고 마지막으로 여섯 번째 플롯에서 점은  구동 방식의 각 수준에 대해 서로 다른 색상으로 표현되며 두꺼운 흰색  테두리가 있습니다.

    이 그림에는 3x2 그리드로 배열된 6개의 산점도가 있습니다. 모든 플롯에서  y축은 자동차의 고속도로 연비이고 x축은 엔진 크기입니다. 첫 번째 플롯은  모든 점을 검은색으로 표시하고 매끄러운 곡선을 그 위에 겹쳐 놓았습니다.  두 번째 플롯도 점이 모두 검은색이며 구동 방식의 각 수준에 대해 별도의  매끄러운 곡선이 겹쳐져 있습니다. 세 번째 플롯에서 점과 매끄러운  곡선은 구동 방식의 각 수준에 대해 서로 다른 색상으로 표현됩니다.  네 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되지만 전체 데이터에 적합된 단일 매끄러운 선만 있습니다.  다섯 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되고 구동 방식의 각 수준에 대해 다른 선형을 가진 별도의 매끄러운  곡선이 적합됩니다. 그리고 마지막으로 여섯 번째 플롯에서 점은  구동 방식의 각 수준에 대해 서로 다른 색상으로 표현되며 두꺼운 흰색  테두리가 있습니다.

    이 그림에는 3x2 그리드로 배열된 6개의 산점도가 있습니다. 모든 플롯에서  y축은 자동차의 고속도로 연비이고 x축은 엔진 크기입니다. 첫 번째 플롯은  모든 점을 검은색으로 표시하고 매끄러운 곡선을 그 위에 겹쳐 놓았습니다.  두 번째 플롯도 점이 모두 검은색이며 구동 방식의 각 수준에 대해 별도의  매끄러운 곡선이 겹쳐져 있습니다. 세 번째 플롯에서 점과 매끄러운  곡선은 구동 방식의 각 수준에 대해 서로 다른 색상으로 표현됩니다.  네 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되지만 전체 데이터에 적합된 단일 매끄러운 선만 있습니다.  다섯 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되고 구동 방식의 각 수준에 대해 다른 선형을 가진 별도의 매끄러운  곡선이 적합됩니다. 그리고 마지막으로 여섯 번째 플롯에서 점은  구동 방식의 각 수준에 대해 서로 다른 색상으로 표현되며 두꺼운 흰색  테두리가 있습니다.

    이 그림에는 3x2 그리드로 배열된 6개의 산점도가 있습니다. 모든 플롯에서  y축은 자동차의 고속도로 연비이고 x축은 엔진 크기입니다. 첫 번째 플롯은  모든 점을 검은색으로 표시하고 매끄러운 곡선을 그 위에 겹쳐 놓았습니다.  두 번째 플롯도 점이 모두 검은색이며 구동 방식의 각 수준에 대해 별도의  매끄러운 곡선이 겹쳐져 있습니다. 세 번째 플롯에서 점과 매끄러운  곡선은 구동 방식의 각 수준에 대해 서로 다른 색상으로 표현됩니다.  네 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되지만 전체 데이터에 적합된 단일 매끄러운 선만 있습니다.  다섯 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되고 구동 방식의 각 수준에 대해 다른 선형을 가진 별도의 매끄러운  곡선이 적합됩니다. 그리고 마지막으로 여섯 번째 플롯에서 점은  구동 방식의 각 수준에 대해 서로 다른 색상으로 표현되며 두꺼운 흰색  테두리가 있습니다.

    이 그림에는 3x2 그리드로 배열된 6개의 산점도가 있습니다. 모든 플롯에서  y축은 자동차의 고속도로 연비이고 x축은 엔진 크기입니다. 첫 번째 플롯은  모든 점을 검은색으로 표시하고 매끄러운 곡선을 그 위에 겹쳐 놓았습니다.  두 번째 플롯도 점이 모두 검은색이며 구동 방식의 각 수준에 대해 별도의  매끄러운 곡선이 겹쳐져 있습니다. 세 번째 플롯에서 점과 매끄러운  곡선은 구동 방식의 각 수준에 대해 서로 다른 색상으로 표현됩니다.  네 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되지만 전체 데이터에 적합된 단일 매끄러운 선만 있습니다.  다섯 번째 플롯에서 점은 구동 방식의 각 수준에 대해 서로 다른 색상으로  표현되고 구동 방식의 각 수준에 대해 다른 선형을 가진 별도의 매끄러운  곡선이 적합됩니다. 그리고 마지막으로 여섯 번째 플롯에서 점은  구동 방식의 각 수준에 대해 서로 다른 색상으로 표현되며 두꺼운 흰색  테두리가 있습니다.

9.4 패싯(Facets)

Chapter 1 에서 범주형 변수를 기반으로 데이터의 한 부분집합을 각각 표시하는 하위 플롯으로 플롯을 분할하는 facet_wrap()을 사용한 패싯에 대해 배웠습니다.

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point() + 
  facet_wrap(~cyl)

자동차의 고속도로 연비 대 엔진 크기의 산점도로, 실린더 수에 따라  패싯되었으며 패싯은 두 행에 걸쳐 있습니다.

두 변수의 조합으로 플롯을 패싯하려면 facet_wrap()에서 facet_grid()로 전환하세요. facet_grid()의 첫 번째 인수도 공식이지만, 이제는 양면 공식인 rows ~ cols입니다.

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point() + 
  facet_grid(drv ~ cyl)

자동차의 고속도로 연비 대 엔진 크기의 산점도로, 행은 실린더 수에 따라,  열은 구동 방식 유형에 따라 패싯되었습니다. 그 결과 12개 패싯의 4x3  그리드가 생성됩니다. 5기통 및 4륜 구동, 4 또는 5기통 및 전륜 구동과  같은 일부 패싯에는 관측값이 없습니다.

기본적으로 각 패싯은 x축과 y축에 대해 동일한 척도와 범위를 공유합니다. 이는 패싯 간에 데이터를 비교할 때 유용하지만 각 패싯 내의 관계를 더 잘 시각화하고 싶을 때는 제한적일 수 있습니다. 패싯 함수의 scales 인수를 "free_x"로 설정하면 열 전체에서 x축의 척도를 다르게 할 수 있고, "free_y"는 행 전체에서 y축의 척도를 다르게 할 수 있으며, "free"는 둘 다 허용합니다.

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point() + 
  facet_grid(drv ~ cyl, scales = "free")

자동차의 고속도로 연비 대 엔진 크기의 산점도로, 행은 실린더 수에 따라,  열은 구동 방식 유형에 따라 패싯되었습니다. 그 결과 12개 패싯의 4x3  그리드가 생성됩니다. 5기통 및 4륜 구동, 4 또는 5기통 및 전륜 구동과  같은 일부 패싯에는 관측값이 없습니다. 행 내의 패싯은 동일한 y 척도를  공유하고 열 내의 패싯은 동일한 x 척도를 공유합니다.

9.4.1 연습문제

  1. 연속형 변수로 패싯하면 어떻게 됩니까?

  2. 위의 facet_grid(drv ~ cyl)가 있는 플롯의 빈 셀은 무엇을 의미합니까? 다음 코드를 실행하세요. 결과 플롯과 어떤 관련이 있습니까?

    ggplot(mpg) + 
      geom_point(aes(x = drv, y = cyl))
  3. 다음 코드는 어떤 플롯을 만듭니까? .은 무엇을 합니까?

    ggplot(mpg) + 
      geom_point(aes(x = displ, y = hwy)) +
      facet_grid(drv ~ .)
    
    ggplot(mpg) + 
      geom_point(aes(x = displ, y = hwy)) +
      facet_grid(. ~ cyl)
  4. 이 섹션의 첫 번째 패싯 플롯을 가져오세요:

    ggplot(mpg) + 
      geom_point(aes(x = displ, y = hwy)) + 
      facet_wrap(~ cyl, nrow = 2)

    색상 심미성 대신 패싯을 사용할 때의 장점은 무엇입니까? 단점은 무엇입니까? 더 큰 데이터셋이 있는 경우 균형이 어떻게 바뀔 수 있습니까?

  5. ?facet_wrap을 읽어보세요. nrow는 무엇을 합니까? ncol은 무엇을 합니까? 개별 패널의 레이아웃을 제어하는 다른 옵션은 무엇입니까? facet_grid()에는 왜 nrowncol 인수가 없습니까?

  6. 다음 플롯 중 구동 방식이 다른 자동차 간의 엔진 크기(displ)를 비교하기 더 쉬운 것은 무엇입니까? 이는 패싯 변수를 행이나 열에 배치할 때 무엇을 말해줍니까?

    ggplot(mpg, aes(x = displ)) + 
      geom_histogram() + 
      facet_grid(drv ~ .)
    
    ggplot(mpg, aes(x = displ)) + 
      geom_histogram() +
      facet_grid(. ~ drv)
  7. facet_grid() 대신 facet_wrap()을 사용하여 다음 플롯을 다시 만드세요. 패싯 레이블의 위치가 어떻게 바뀝니까?

    ggplot(mpg) + 
      geom_point(aes(x = displ, y = hwy)) +
      facet_grid(drv ~ .)

9.5 통계적 변환

geom_bar() 또는 geom_col()로 그린 기본 막대 차트를 고려해 보세요. 다음 차트는 cut별로 그룹화된 diamonds 데이터셋의 다이아몬드 총 개수를 표시합니다. ggplot2 패키지에 있는 diamonds 데이터셋에는 각 다이아몬드의 price, carat, color, clarity, cut을 포함한 약 54,000개의 다이아몬드 정보가 포함되어 있습니다. 차트는 품질이 낮은 컷보다 품질이 높은 컷의 다이아몬드가 더 많이 사용 가능함을 보여줍니다.

ggplot(diamonds, aes(x = cut)) + 
  geom_bar()

다이아몬드의 각 컷 수에 대한 막대 차트. 대략 Fair 1500개, Good 5000개,  Very Good 12000개, Premium 14000개, Ideal 22000개의 컷 다이아몬드가  있습니다.

x축에는 차트가 diamonds의 변수인 cut을 표시합니다. y축에는 개수(count)를 표시하지만 개수는 diamonds의 변수가 아닙니다! 개수는 어디에서 왔을까요? 산점도와 같은 많은 그래프는 데이터셋의 원시 값을 플롯합니다. 막대 차트와 같은 다른 그래프는 플롯할 새 값을 계산합니다:

  • 막대 차트, 히스토그램, 빈도 다각형은 데이터를 비닝(binning)한 다음 각 빈에 속하는 포인트 수인 빈 카운트를 플롯합니다.

  • 스무더(smoothers)는 데이터에 모델을 적합시킨 다음 모델의 예측을 플롯합니다.

  • 상자 그림은 분포의 5가지 요약 수치를 계산한 다음 그 요약을 특별히 포맷된 상자로 표시합니다.

그래프에 대한 새 값을 계산하는 데 사용되는 알고리즘을 스탯(stat), 통계적 변환(statistical transformation)의 줄임말이라고 합니다. Figure 9.2geom_bar()에서 이 프로세스가 작동하는 방식을 보여줍니다.

막대 차트를 만드는 세 단계를 보여주는 그림.  1단계. geom_bar()는 diamonds 데이터셋으로 시작합니다. 2단계.  geom_bar()는 count 스탯으로 데이터를 변환하여 cut 값과 count 데이터셋을  반환합니다. 3단계. geom_bar()는 변환된 데이터를 사용하여 플롯을  구축합니다. cut은 x축에, count는 y축에 매핑됩니다.
Figure 9.2: 막대 차트를 만들 때는 먼저 원시 데이터로 시작한 다음, 각 막대의 관측값 수를 계산하기 위해 집계하고, 마지막으로 계산된 변수를 플롯 심미성에 매핑합니다.

stat 인수의 기본값을 검사하여 지옴이 사용하는 스탯을 알 수 있습니다. 예를 들어 ?geom_barstat의 기본값이 “count”임을 보여주며, 이는 geom_bar()stat_count()를 사용한다는 의미입니다. stat_count()geom_bar()와 같은 페이지에 문서화되어 있습니다. 아래로 스크롤하면 “Computed variables(계산된 변수)”라는 섹션에서 countprop라는 두 가지 새로운 변수를 계산한다고 설명합니다.

모든 지옴에는 기본 스탯이 있고, 모든 스탯에는 기본 지옴이 있습니다. 즉, 일반적으로 기본 통계적 변환에 대해 걱정하지 않고 지옴을 사용할 수 있습니다. 그러나 스탯을 명시적으로 사용해야 하는 세 가지 이유가 있습니다:

  1. 기본 스탯을 재정의하고 싶을 수 있습니다. 아래 코드에서는 geom_bar()의 스탯을 count(기본값)에서 identity로 변경합니다. 이렇게 하면 막대의 높이를 y 변수의 원시 값에 매핑할 수 있습니다.

    diamonds |>
      count(cut) |>
      ggplot(aes(x = cut, y = n)) +
      geom_bar(stat = "identity")

    다이아몬드의 각 컷 수에 대한 막대 차트. 대략 Fair 1500개, Good 5000개,  Very Good 12000개, Premium 14000개, Ideal 22000개의 컷 다이아몬드가  있습니다.

  2. 변환된 변수에서 심미성으로의 기본 매핑을 재정의하고 싶을 수 있습니다. 예를 들어 개수보다는 비율의 막대 차트를 표시하고 싶을 수 있습니다:

    ggplot(diamonds, aes(x = cut, y = after_stat(prop), group = 1)) + 
      geom_bar()

    다이아몬드의 각 컷 비율에 대한 막대 차트. 대략 Fair 다이아몬드는 0.03,  Good 0.09, Very Good 0.22, Premium 0.26, Ideal 0.40을 차지합니다.

    스탯에 의해 계산될 수 있는 변수를 찾으려면 geom_bar() 도움말에서 “computed variables”라는 제목의 섹션을 찾으세요.

  3. 코드에서 통계적 변환에 더 큰 주의를 끌고 싶을 수 있습니다. 예를 들어 각 고유 x 값에 대한 y 값을 요약하는 stat_summary()를 사용하여 계산 중인 요약에 주의를 끌 수 있습니다:

    ggplot(diamonds) + 
      stat_summary(
        aes(x = cut, y = depth),
        fun.min = min,
        fun.max = max,
        fun = median
      )

    y축에 깊이(depth)가 있고 x축에 다이아몬드의 컷(cut, 수준: fair,  good, very good, premium, ideal)이 있는 플롯. 컷의 각 수준에 대해  해당 컷 범주의 다이아몬드에 대한 최소 깊이에서 최대 깊이까지 수직선이  뻗어 있으며, 중간 깊이는 선 위에 점으로 표시됩니다.

ggplot2는 사용할 수 있는 20개 이상의 스탯을 제공합니다. 각 스탯은 함수이므로 일반적인 방법(예: ?stat_bin)으로 도움말을 얻을 수 있습니다.

9.5.1 연습문제

  1. stat_summary()와 관련된 기본 지옴은 무엇입니까? 스탯 함수 대신 지옴 함수를 사용하도록 이전 플롯을 어떻게 다시 작성할 수 있습니까?

  2. geom_col()은 무엇을 합니까? geom_bar()와 어떻게 다릅니까?

  3. 대부분의 지옴과 스탯은 거의 항상 함께 사용되는 쌍으로 제공됩니다. 모든 쌍의 목록을 만드세요. 공통점은 무엇입니까? (힌트: 문서를 읽어보세요.)

  4. stat_smooth()는 어떤 변수를 계산합니까? 어떤 인수가 동작을 제어합니까?

  5. 비율 막대 차트에서 group = 1을 설정해야 했습니다. 이유는 무엇입니까? 즉, 이 두 그래프의 문제점은 무엇입니까?

    ggplot(diamonds, aes(x = cut, y = after_stat(prop))) + 
      geom_bar()
    ggplot(diamonds, aes(x = cut, fill = color, y = after_stat(prop))) + 
      geom_bar()

9.6 위치 조정(Position adjustments)

막대 차트와 관련된 마법이 하나 더 있습니다. color 심미성이나 더 유용하게는 fill 심미성을 사용하여 막대 차트에 색을 입힐 수 있습니다:

# 왼쪽
ggplot(mpg, aes(x = drv, color = drv)) + 
  geom_bar()

# 오른쪽
ggplot(mpg, aes(x = drv, fill = drv)) + 
  geom_bar()

자동차의 구동 유형에 대한 두 개의 막대 차트. 첫 번째 플롯에서 막대에는  색상이 있는 테두리가 있습니다. 두 번째 플롯에서는 색상으로 채워져  있습니다. 막대의 높이는 각 drv 범주의 자동차 수에 해당합니다.

자동차의 구동 유형에 대한 두 개의 막대 차트. 첫 번째 플롯에서 막대에는  색상이 있는 테두리가 있습니다. 두 번째 플롯에서는 색상으로 채워져  있습니다. 막대의 높이는 각 drv 범주의 자동차 수에 해당합니다.

채우기 심미성을 class와 같은 다른 변수에 매핑하면 어떻게 되는지 주목하세요. 막대가 자동으로 쌓입니다. 각 색상 사각형은 drvclass의 조합을 나타냅니다.

ggplot(mpg, aes(x = drv, fill = class)) + 
  geom_bar()

자동차의 구동 유형에 대한 분할된 막대 차트로, 각 막대는 자동차  클래스에 대한 색상으로 채워집니다. 막대의 높이는 각 구동 범주의 자동차  수에 해당하며, 색상 세그먼트의 높이는 주어진 구동 유형 수준 내에서  주어진 클래스 수준을 가진 자동차 수를 나타냅니다.

스태킹(stacking)은 position 인수에 의해 지정된 위치 조정을 사용하여 자동으로 수행됩니다. 누적 막대 차트를 원하지 않는 경우 "identity", "dodge", "fill"의 세 가지 다른 옵션 중 하나를 사용할 수 있습니다.

  • position = "identity"는 각 객체를 그래프 컨텍스트 내에서 떨어지는 위치에 정확하게 배치합니다. 이것은 막대가 겹치기 때문에 막대에는 별로 유용하지 않습니다. 그 겹침을 보려면 alpha를 작은 값으로 설정하여 막대를 약간 투명하게 만들거나 fill = NA를 설정하여 완전히 투명하게 만들어야 합니다.

    # 왼쪽
    ggplot(mpg, aes(x = drv, fill = class)) + 
      geom_bar(alpha = 1/5, position = "identity")
    
    # 오른쪽
    ggplot(mpg, aes(x = drv, color = class)) + 
      geom_bar(fill = NA, position = "identity")

    자동차의 구동 유형에 대한 분할된 막대 차트로, 각 막대는 자동차  클래스에 대한 색상으로 채워집니다.  색상 세그먼트의 높이는 주어진 구동 유형 수준 내에서  주어진 클래스 수준을 가진 자동차 수를 나타냅니다. 그러나 세그먼트가  겹칩니다. 첫 번째 플롯에서 막대는 투명한 색상으로 채워지고  두 번째 플롯에서는 색상으로 윤곽선만 그려집니다.

    자동차의 구동 유형에 대한 분할된 막대 차트로, 각 막대는 자동차  클래스에 대한 색상으로 채워집니다.  색상 세그먼트의 높이는 주어진 구동 유형 수준 내에서  주어진 클래스 수준을 가진 자동차 수를 나타냅니다. 그러나 세그먼트가  겹칩니다. 첫 번째 플롯에서 막대는 투명한 색상으로 채워지고  두 번째 플롯에서는 색상으로 윤곽선만 그려집니다.

    identity 위치 조정은 점과 같은 2D 지옴에 더 유용하며, 여기서는 기본값입니다.

  • position = "fill"은 스태킹처럼 작동하지만, 각 누적 막대 세트의 높이를 동일하게 만듭니다. 이렇게 하면 그룹 간의 비율을 비교하기가 더 쉽습니다.

  • position = "dodge"는 겹치는 객체를 서로 옆에 바로 배치합니다. 이렇게 하면 개별 값을 비교하기가 더 쉽습니다.

    # 왼쪽
    ggplot(mpg, aes(x = drv, fill = class)) + 
      geom_bar(position = "fill")
    
    # 오른쪽
    ggplot(mpg, aes(x = drv, fill = class)) + 
      geom_bar(position = "dodge")

    왼쪽에는 자동차의 구동 유형에 대한 분할된 막대 차트가 있으며,  각 막대는 클래스 수준에 대한 색상으로 채워집니다. 각 막대의 높이는  1이고 색상 세그먼트의 높이는 주어진 구동 유형 내에서 주어진 클래스  수준을 가진 자동차의 비율을 나타냅니다. 오른쪽에는 자동차의 구동 유형에 대한 다지(dodged) 막대 차트가  있습니다. 다지 막대는 구동 유형 수준별로 그룹화됩니다. 각 그룹 내  막대는 각 클래스 수준을 나타냅니다. 일부 클래스는 일부 구동 유형  내에서 표현되고 다른 구동 유형에서는 표현되지 않아 각 그룹 내 막대  수가 동일하지 않습니다. 이 막대의 높이는 주어진 구동 유형 및 클래스  수준을 가진 자동차 수를 나타냅니다.

    왼쪽에는 자동차의 구동 유형에 대한 분할된 막대 차트가 있으며,  각 막대는 클래스 수준에 대한 색상으로 채워집니다. 각 막대의 높이는  1이고 색상 세그먼트의 높이는 주어진 구동 유형 내에서 주어진 클래스  수준을 가진 자동차의 비율을 나타냅니다. 오른쪽에는 자동차의 구동 유형에 대한 다지(dodged) 막대 차트가  있습니다. 다지 막대는 구동 유형 수준별로 그룹화됩니다. 각 그룹 내  막대는 각 클래스 수준을 나타냅니다. 일부 클래스는 일부 구동 유형  내에서 표현되고 다른 구동 유형에서는 표현되지 않아 각 그룹 내 막대  수가 동일하지 않습니다. 이 막대의 높이는 주어진 구동 유형 및 클래스  수준을 가진 자동차 수를 나타냅니다.

막대 차트에는 유용하지 않지만 산점도에는 매우 유용할 수 있는 다른 유형의 조정이 하나 있습니다. 첫 번째 산점도를 상기해 보세요. 데이터셋에 234개의 관측값이 있는데 플롯에는 126개의 점만 표시된다는 것을 눈치챘나요?

자동차의 고속도로 연비 대 엔진 크기의 산점도로 음의 연관성을  보여줍니다.

hwydispl의 기본 값은 반올림되어 점이 그리드에 나타나고 많은 점이 서로 겹칩니다. 이 문제를 오버플로팅(overplotting) 이라고 합니다. 이러한 배열은 데이터의 분포를 보기 어렵게 만듭니다. 데이터 포인트가 그래프 전체에 균등하게 퍼져 있나요, 아니면 109개의 값을 포함하는 hwydispl의 특별한 조합이 하나 있나요?

위치 조정을 “jitter”로 설정하여 이 그리딩을 피할 수 있습니다. position = "jitter"는 각 점에 약간의 무작위 노이즈를 추가합니다. 두 점이 같은 양의 무작위 노이즈를 받을 가능성이 없기 때문에 점들이 퍼집니다.

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(position = "jitter")

자동차의 고속도로 연비 대 엔진 크기의 지터링된 산점도.  플롯은 음의 연관성을 보여줍니다.

무작위성을 추가하는 것은 플롯을 개선하는 이상한 방법처럼 보일 수 있지만, 그래프를 작은 규모에서는 덜 정확하게 만들지만 큰 규모에서는 그래프를 잘 드러나게 만듭니다. 이것은 매우 유용한 작업이기 때문에 ggplot2에는 geom_point(position = "jitter")의 단축형인 geom_jitter()가 함께 제공됩니다.

위치 조정에 대해 자세히 알아보려면 각 조정과 관련된 도움말 페이지를 찾아보세요: ?position_dodge, ?position_fill, ?position_identity, ?position_jitter, ?position_stack.

9.6.1 연습문제

  1. 다음 플롯의 문제점은 무엇입니까? 어떻게 개선할 수 있습니까?

    ggplot(mpg, aes(x = cty, y = hwy)) + 
      geom_point()
  2. 두 플롯의 차이점이 있다면 무엇입니까? 이유는 무엇입니까?

    ggplot(mpg, aes(x = displ, y = hwy)) +
      geom_point()
    ggplot(mpg, aes(x = displ, y = hwy)) +
      geom_point(position = "identity")
  3. geom_jitter()의 어떤 매개변수가 지터링의 양을 제어합니까?

  4. geom_jitter()geom_count()를 비교하고 대조하세요.

  5. geom_boxplot()의 기본 위치 조정은 무엇입니까? 그것을 보여주는 mpg 데이터셋의 시각화를 만드세요.

9.7 좌표계

좌표계는 아마도 ggplot2에서 가장 복잡한 부분일 것입니다. 기본 좌표계는 x와 y 위치가 독립적으로 작용하여 각 점의 위치를 결정하는 데카르트 좌표계(Cartesian coordinate system)입니다. 가끔 도움이 되는 두 가지 다른 좌표계가 있습니다.

  • coord_quickmap()은 지리적 지도의 가로세로 비율(aspect ratio)을 올바르게 설정합니다. 이것은 ggplot2로 공간 데이터를 플롯하는 경우 매우 중요합니다. 이 책에서는 지도를 다룰 공간이 없지만 ggplot2: Elegant graphics for data analysisMaps 장에서 자세히 알아볼 수 있습니다.

    nz <- map_data("nz")
    
    ggplot(nz, aes(x = long, y = lat, group = group)) +
      geom_polygon(fill = "white", color = "black")
    
    ggplot(nz, aes(x = long, y = lat, group = group)) +
      geom_polygon(fill = "white", color = "black") +
      coord_quickmap()

    뉴질랜드 경계의 두 지도. 첫 번째 플롯에서는 가로세로 비율이  올바르지 않고 두 번째 플롯에서는 올바릅니다.

    뉴질랜드 경계의 두 지도. 첫 번째 플롯에서는 가로세로 비율이  올바르지 않고 두 번째 플롯에서는 올바릅니다.

  • coord_polar()는 극좌표를 사용합니다. 극좌표는 막대 차트와 콕스콤(Coxcomb) 차트 사이의 흥미로운 연결을 보여줍니다.

    bar <- ggplot(data = diamonds) + 
      geom_bar(
        mapping = aes(x = clarity, fill = clarity), 
        show.legend = FALSE,
        width = 1
      ) + 
      theme(aspect.ratio = 1)
    
    bar + coord_flip()
    bar + coord_polar()

    두 개의 플롯이 있습니다. 왼쪽은 다이아몬드 투명도(clarity)의 막대  차트이고 오른쪽은 동일한 데이터의 콕스콤 차트입니다.

    두 개의 플롯이 있습니다. 왼쪽은 다이아몬드 투명도(clarity)의 막대  차트이고 오른쪽은 동일한 데이터의 콕스콤 차트입니다.

9.7.1 연습문제

  1. coord_polar()를 사용하여 누적 막대 차트를 파이 차트로 바꾸세요.

  2. coord_quickmap()coord_map()의 차이점은 무엇입니까?

  3. 다음 플롯은 도시 및 고속도로 mpg 간의 관계에 대해 무엇을 말해줍니까? coord_fixed()가 중요한 이유는 무엇입니까? geom_abline()은 무엇을 합니까?

    ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
      geom_point() + 
      geom_abline() +
      coord_fixed()

9.8 레이어드 그래픽 문법

Section 1.3 에서 배운 그래프 템플릿에 위치 조정, 스탯, 좌표계, 패싯을 추가하여 확장할 수 있습니다:

ggplot(data = <DATA>) + 
  <GEOM_FUNCTION>(
     mapping = aes(<MAPPINGS>),
     stat = <STAT>, 
     position = <POSITION>
  ) +
  <COORDINATE_FUNCTION> +
  <FACET_FUNCTION>

우리의 새 템플릿은 템플릿에 나타나는 대괄호로 묶인 단어인 7개의 매개변수를 취합니다. 실제로는 그래프를 만들기 위해 7개의 매개변수를 모두 제공할 필요가 거의 없습니다. ggplot2가 데이터, 매핑, 지옴 함수를 제외한 모든 것에 대해 유용한 기본값을 제공하기 때문입니다.

템플릿의 7개 매개변수는 플롯을 구축하기 위한 공식적인 시스템인 그래픽 문법을 구성합니다. 그래픽 문법은 데이터셋, 지옴, 매핑 세트, 스탯, 위치 조정, 좌표계, 패싯 방식, 테마의 조합으로 어떤 플롯이든 고유하게 설명할 수 있다는 통찰력에 기초합니다.

이것이 어떻게 작동하는지 보려면 처음부터 기본 플롯을 구축하는 방법을 고려해 보세요: 데이터셋으로 시작한 다음 표시하려는 정보로 변환할 수 있습니다(스탯으로). 다음으로 변환된 데이터의 각 관측값을 나타낼 기하학적 객체를 선택할 수 있습니다. 그런 다음 지옴의 심미적 속성을 사용하여 데이터의 변수를 나타낼 수 있습니다. 각 변수의 값을 심미성의 수준에 매핑합니다. 이 단계들은 Figure 9.3 에 설명되어 있습니다. 그런 다음 지옴을 배치할 좌표계를 선택하고 객체의 위치(그 자체로 심미적 속성임)를 사용하여 x 및 y 변수의 값을 표시합니다.

원시 데이터에서 각 행이 컷의 한 수준을 나타내고 개수 열이 해당 컷 수준에  얼마나 많은 다이아몬드가 있는지를 보여주는 빈도 테이블로 가는 단계를  보여주는 그림. 그런 다음 이 값들은 막대의 높이에 매핑됩니다.
Figure 9.3: 원시 데이터에서 빈도 테이블로, 그리고 막대의 높이가 빈도를 나타내는 막대 플롯으로 가는 단계.

이 시점에서 완전한 그래프를 갖게 되지만 좌표계 내에서 지옴의 위치를 추가로 조정하거나(위치 조정) 그래프를 하위 플롯으로 분할(패싯)할 수 있습니다. 또한 하나 이상의 추가 레이어를 추가하여 플롯을 확장할 수도 있습니다. 여기서 각 추가 레이어는 데이터셋, 지옴, 매핑 세트, 스탯, 위치 조정을 사용합니다.

이 방법을 사용하여 상상하는 어떤 플롯이든 만들 수 있습니다. 즉, 이 장에서 배운 코드 템플릿을 사용하여 수십만 개의 고유한 플롯을 만들 수 있습니다.

ggplot2의 이론적 토대에 대해 더 알고 싶다면 ggplot2의 이론을 자세히 설명하는 과학 논문인 “The Layered Grammar of Graphics”를 읽어보는 것을 추천합니다.

9.9 요약

이 장에서는 간단한 플롯을 만들기 위한 심미성과 기하학, 플롯을 부분집합으로 나누기 위한 패싯, 지옴이 계산되는 방식을 이해하기 위한 통계, 지옴이 겹칠 수 있는 경우 위치의 세부 사항을 제어하기 위한 위치 조정, xy가 의미하는 바를 근본적으로 변경할 수 있는 좌표계로 시작하여 레이어드 그래픽 문법에 대해 배웠습니다. 아직 다루지 않은 레이어 중 하나는 테마이며, Section 11.5 에서 소개할 것입니다.

전체 ggplot2 기능에 대한 개요를 얻을 수 있는 매우 유용한 두 가지 리소스는 ggplot2 치트시트(https://posit.co/resources/cheatsheets에서 찾을 수 있음)와 ggplot2 패키지 웹사이트(https://ggplot2.tidyverse.org)입니다.

이 장에서 얻어야 할 중요한 교훈은 ggplot2에서 제공하지 않는 지옴이 필요하다고 느낄 때, 다른 누군가가 해당 지옴을 제공하는 ggplot2 확장 패키지를 만들어 이미 문제를 해결했는지 확인해 보는 것이 항상 좋은 생각이라는 것입니다.