HOWTO · R

R에서 그룹화 된 상자 그림 만들기

이 기사에서는 R에서 그룹화 된 상자 그림을 만드는 방법을 소개합니다.

이 페이지의 내용

ggplot2에서 그룹화된 상자 그림을 만드는 일은 결국 하나의 결정으로 귀결됩니다. 비교하고 싶은 그룹으로 데이터를 나눌 변수를 무엇으로 할 것인가입니다. 그 변수를 fill 미적 요소에 매핑하면 geom_boxplot()가 각 x 위치 안에 나란한 상자를 그려 주고, facet_wrap()로 데이터를 별도의 패널로 나눌 수도 있습니다. 아래 예제는 dplyr 패키지와 함께 gapminder 데이터 세트를 사용하며, 각 방법은 독자의 열에 맞게 바꿔 쓸 수 있는 그룹화된 상자 그림을 만들어 줍니다.

geom_boxplot()로 그룹화된 상자 그림 만들기

ggplot 함수와 geom_boxplot 함수를 함께 사용해 상자 그림 객체를 만드는 것이 일반적입니다. ggplot의 첫 번째 인수는 데이터 세트이고 두 번째 인수는 aes로 만든 미적 매핑 목록입니다. 아래 매핑에서 x와 y는 dplyr 함수로 세 개의 선택된 연도만 남긴 gapminder의 continent와 lifeExp 열을 가리킵니다.

이어지는 예제 코드와 그 안의 축 레이블은 영어로 유지되며, 이 코드는 대륙별 평균 기대 수명을 상자 그림으로 그립니다.

if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("gapminder", quietly = TRUE) &&
    requireNamespace("dplyr", quietly = TRUE)) {
  library(ggplot2)
  library(gapminder)
  library(dplyr)

  dat <- gapminder %>%
    filter(year %in% c(1972, 1992, 2007))

  print(ggplot(dat, aes(x = continent, y = lifeExp)) +
    geom_boxplot() +
    scale_y_continuous(name = "Average Life Expectancy") +
    scale_x_discrete(labels = abbreviate, name = "Continent"))
}

이 호출은 대륙마다 상자를 하나씩 그립니다. 이미 x 변수로 그룹화되어 있지만 각 대륙 안의 연도는 아직 하나로 합쳐져 있습니다. 다음 단계는 두 번째 그룹화 변수를 추가하는 것입니다. requireNamespace 가드는 플로팅 패키지가 설치되어 있지 않은 환경에서 스크립트가 깔끔하게 종료되도록 해 주며, 이 경우 그리기는 건너뜁니다. 따라서 코드는 문법 예시로 보고 렌더링된 결과는 이 기사 뒷부분의 그림을 참고하세요.

fill 미적 요소로 상자 그룹화하기

열을 fill에 매핑하면 geom_boxplot에게 각 x 위치 안에서 그룹마다 별도의 상자를 그리라고 지시하는 것입니다. 한 가지 주의할 점은 매핑된 변수가 이산형일 때만 fill 매핑이 뚜렷한 그룹을 만든다는 것입니다. gapminder의 year 열은 수치형이므로 fill = year 매핑은 연속적인 색상 그라디언트로 처리되어 플롯이 연도별 상자로 나뉘지 않습니다. factor로 감싸면 숫자가 범주형 수준으로 변환되어 의도한 나란한 상자가 만들어집니다. 순수 R에서 그 차이를 확인할 수 있습니다.

이어지는 예제 코드와 그 출력은 영어로 유지되며, 수치형 벡터와 범주형으로 변환된 벡터의 클래스 차이를 보여 줍니다.

year <- c(1972, 1992, 2007)

print(class(year))
print(class(factor(year)))
print(levels(factor(year)))
[1] "numeric"
[1] "factor"
[1] "1972" "1992" "2007"

수치형 year는 연속 값으로 남아 있지만 factor(year)는 이름이 있는 수준을 가지며, fill 매핑은 두 번째 형태에서만 별도의 상자로 펼쳐집니다. ggplot2에서도 같은 차이가 레이아웃을 결정합니다. 아래 비교 코드의 축 레이블도 영어로 유지됩니다.

if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("gridExtra", quietly = TRUE) &&
    requireNamespace("gapminder", quietly = TRUE) &&
    requireNamespace("dplyr", quietly = TRUE)) {
  library(ggplot2)
  library(gridExtra)
  library(gapminder)
  library(dplyr)

  dat <- gapminder %>%
    filter(year %in% c(1972, 1992, 2007))

  p1 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = year)) +
    geom_boxplot() +
    scale_y_continuous(name = "Average Life Expectancy") +
    scale_x_discrete(labels = abbreviate, name = "Continent")

  p2 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = factor(year))) +
    geom_boxplot() +
    scale_y_continuous(name = "Average Life Expectancy") +
    scale_x_discrete(labels = abbreviate, name = "Continent")

  grid.arrange(p1, p2, nrow = 2)
}

연속형 year의 fill 매핑과 factor(year)의 fill 매핑을 비교한 그룹화된 상자 그림으로, factor 버전만 별도의 상자를 그립니다

위쪽 패널은 year를 수치형으로 유지해 그룹화되지 않은 상태를 보여 주고, 아래쪽 패널은 factor(year)를 사용해 대륙마다 선택된 연도별로 상자 세 개를 보여 줍니다.

facet_wrap()로 그룹을 패널로 나누기

facet_wrap 함수는 선택한 변수로 그룹화된 상자 그림을 그리는 또 다른 방법입니다. 여기서는 연도마다 패널 하나를 만듭니다. facet_wrap 함수는 fill 매핑 없이도 동작하지만, fill = factor(year) 매핑을 유지하면 상자에 색이 입혀져 패널을 더 쉽게 구분할 수 있습니다.

이어지는 예제 코드와 그 안의 축 레이블은 영어로 유지됩니다.

if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("gapminder", quietly = TRUE) &&
    requireNamespace("dplyr", quietly = TRUE)) {
  library(ggplot2)
  library(gapminder)
  library(dplyr)

  dat <- gapminder %>%
    filter(year %in% c(1972, 1992, 2007))

  p3 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = factor(year))) +
    geom_boxplot() +
    facet_wrap(~year) +
    scale_y_continuous(name = "Average Life Expectancy") +
    scale_x_discrete(labels = abbreviate, name = "Continent")

  print(p3)
}

연도마다 패널 하나씩 있고 같은 x 및 y 눈금을 공유하는 패싯 상자 그림

기본적으로 facet_wrap가 만드는 모든 패널은 같은 눈금을 공유하므로 패널 간 값을 직접 비교할 수 있습니다. scales = "free"를 전달하면 각 패널이 포함된 데이터에 맞게 자체 축을 조정합니다. 좁은 패널의 세부 사항을 드러낼 수는 있지만, 같은 높이가 더 이상 같은 값을 의미하지 않으므로 패널 간 비교를 오도할 수 있습니다. 아래 코드의 축 레이블도 영어로 유지됩니다.

if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("gapminder", quietly = TRUE) &&
    requireNamespace("dplyr", quietly = TRUE)) {
  library(ggplot2)
  library(gapminder)
  library(dplyr)

  dat <- gapminder %>%
    filter(year %in% c(1972, 1992, 2007))

  p4 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = factor(year))) +
    geom_boxplot() +
    facet_wrap(~year, scales = "free") +
    scale_y_continuous(name = "Average Life Expectancy") +
    scale_x_discrete(labels = abbreviate, name = "Continent")

  print(p4)
}

연도별 각 패널이 자체 축 눈금을 조정하는 패싯 상자 그림

레이아웃 선택 및 결과 확인

그룹 수가 적고 각 x 범주 안에서 직접 비교하고 싶다면 fill 그룹화를 사용하고, 그룹이 많거나 각 부분집합이 자체 패널을 가질 만하다면 facet_wrap 패싯을 선택하세요. 어느 변수로 fill 그룹을 만들고 어느 변수로 패싯할지 바꿀 수도 있습니다. 아래 예제는 필터링하지 않은 gapminder 데이터 세트로 돌아가 continent를 fill에 매핑하고 facet_wrap 패싯이 사용 가능한 모든 연도를 받도록 합니다.

이어지는 예제 코드와 그 안의 축 레이블은 영어로 유지됩니다.

if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("gapminder", quietly = TRUE)) {
  library(ggplot2)
  library(gapminder)

  p5 <- ggplot(gapminder, aes(x = continent, y = lifeExp, fill = continent)) +
    facet_wrap(~year) +
    geom_boxplot() +
    scale_y_continuous(name = "Average Life Expectancy") +
    scale_x_discrete(labels = abbreviate, name = "Continent")

  print(p5)
}

연도별로 패싯되고 대륙이 fill 색상에 매핑된 전체 gapminder 데이터 세트의 상자 그림

어떤 레이아웃을 선택하든 렌더링된 플롯에서 그룹당 상자나 패널 수가 예상과 일치하는지 확인하세요. 수치형 열이 별도의 상자 대신 부드러운 색상 범례를 만들어 낸다면 먼저 factor로 변환하고, 패널 모양은 같아 보이는데 위치가 다르다면 차트에서 값을 읽기 전에 눈금이 공유되는지 확인하세요.