聰明不如鈍筆
총명불여둔필
assignment KindeR

R에서 이미 알고 있는 값으로 상자-수염 그래프 그리기(feat. stat='identity')

이 블로그와 아주 좋은 친구인 위키피디아는 상자-수염 그래프를 이렇게 설명합니다.

 

기술 통계학에서 '상자 수염 그림''box-and-whisker plot, box-and-whisker diagram) 또는 '상자 그림'(box plot, boxplot)은 수치적 자료를 표현하는 그래프이다.

 

이 그래프는 가공하지 않은 자료 그대로를 이용하여 그린 것이 아니라, 자료로부터 얻어낸 통계량인 5가지 요약 수치(다섯 숫자 요약, five-number summary)를 가지고 그린다.

 

이 때 5가지 요약 수치란 최솟값, 제 1사분위(Q1), 제 2사분위(Q2), 제 3사분위(Q3), 최댓값을 일컫는 말이다.

 

여기서 우리가 주목해야 하는 표현은 두 번째 문장에 나옵니다.

 

상자 수염 그래프는 가공 않은 자료 그러니까 전체 데이터(Raw Data)로 그리는 게 아니라 따로 계산한 통계량을 가지고 그립니다.

 

그런데 R에서 (ggplot2로) 상자 수염 그래프를 그릴 때는 전체 데이터를 활용하는 게 일반적입니다.

 

만약 미리 계산한 결과만 알고 있을 때는 어떻게 상자-수염 그래프를 그려야 할까요?

 

제목에 나온 것처럼 힌트는 stat='identity' 옵션입니다.

 

geom_col() 함수가 등장하기 전에는 막대 그래프를 그릴 때 geom_bar(stat='identity')라고 썼던 걸 기억하는 분이 계실 겁니다.

 

구글에 stat = 'idenity'라고 검색해 보면 막대 그래프 이미지가 주욱 뜰 정도입니다.

 

상자-수염 그래프도 똑같이 geom_boxplot(stat='identity')라고 쓰면 미리 계산한 결과를 가지고 상자-수엽 그래프를 그릴 수 있습니다.

 

stat='identity'라는 옵션 자체가 R에서 뭔가 따로 계산하지 말고 현재 있는 자료를 그대로 쓰라는 뜻이거든요.

 

그래서 R에 자료 집계를 맡길 때는 그냥 geom_bar()라고 쓰지만 따로 자료를 입력했을 때는 geom_bar(stat='identity')라고 썼던 겁니다.

 

그러면 실제로 상자-수염 그래프를 그리는 연습을 해보겠습니다.

 

제일 먼저 할 일은 늘 그렇듯 tidyverse 패키지 불러오기.

 

혹시 왜 ggplot2가 아니라 tidyvese를 불러오는지 궁금하신 분도 계실 겁니다.

 

tidyverse는 ggplot2를 비롯해 △dplyrforcatspurrrreadrstringrtibble △tidyr 등을 담고 있는 패키지 '묶음'입니다.

 

각 패키지가 서로 긴밀하게 엮어 있기 때문에 한번에 불러오는 편이 낫습니다.

 

아직 tidyvese 패키지를 설치하지 않으셨다면 이번 기회에 설치해 보시는 것도 좋습니다.

 

#install.packages('tidyverse')
library('tidyverse')
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.2     v purrr   0.3.4
## v tibble  3.0.3     v dplyr   1.0.2
## v tidyr   1.1.2     v stringr 1.4.0
## v readr   1.3.1     v forcats 0.5.0
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()

 

먼저 기존 방식대로 전체 데이터를 가지고 상자-수염 그래프를 그려보겠습니다.

 

표준 정규분포를 따르는 샘플 데이터를 만들어 상자-수염 그래프를 그리는 코드는 이렇게 쓸 수 있습니다.

 

tibble(
  y=rnorm(n=100, mean=0, sd=1)
) %>% 
  ggplot(aes(y=y)) +
  geom_boxplot()

 

혹시 이 코드가 전혀 이해가 가지 않으시는 분은 '최대한 친절하게 쓴 R로 그래프 그리기(feat. ggplot2)' 포스트가 도움이 될 수 있습니다.

 

이미 알고 있는 값으로 상자-수염 그래프를 그릴 때는 당연히 이미 알고 있는 값을 전부 알려줘야 합니다.

 

최솟값 0부터 각 사분위별로 25씩 늘어나서 최댓값이 100이 되는 자료를 일단 하나 만들어 놓겠습니다.

 

tribble(
  ~최솟값, ~x1분위, ~x2분위, ~x3분위, ~최댓값,
  0, 25, 50, 75, 100
) -> sample
sample
## # A tibble: 1 x 5
##   최솟값 x1분위 x2분위 x3분위 최댓값
##    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
## 1      0     25     50     75    100

 

그다음 위치별로 값을 지정합니다. 최솟값은 ymin, 1분위는 lower, 중간값(2분위)은 middle, 3분위는 upper, 최댓값은 ymax에 넣으면 됩니다.

 

이때 주의해야 할 건 x값을 따로 지정해주지 않으면 에러 메시지가 나온다는 것.

 

지금은 x에 어떤 값이 오든지 크게 관계가 없으니까 일단 0이라고 지정하겠습니다.

 

그러고 나서 stat='identity' 옵션으로 코드를 마무리하면 됩니다.

 

sample %>% 
  ggplot(aes(x=0,
             ymin=최솟값,
             lower=x1분위,
             middle=x2분위,
             upper=x3분위,
             ymax=최댓값)) +
  geom_boxplot(stat='identity')

 

ggplot2로 상자-수염 그래프를 그리면 최솟값·최댓값에 따로 표시를 해주지 않습니다.

 

이걸 표시하고 싶으실 때는 geom_errorbar() 함수를 적용하시면 됩니다.

 

이 함수를 나중에 쓰면 이 오차 막대가 그래프를 덮어 버립니다.

 

그러니 geom_boxplot()보다 앞에 이 함수를 쓰셔야 합니다.

 

sample %>% 
  ggplot(aes(x=0,
             ymin=최솟값,
             lower=x1분위,
             middle=x2분위,
             upper=x3분위,
             ymax=최댓값)) +
  geom_errorbar(width = .2) +
  geom_boxplot(stat='identity')

 

'나는 전체 데이터는 없지만 각 분위값은 전부 알고 있다. 그런데 R에서 상자-수염 그래프를 그리는 법을 몰라 답답하다.'

 

이렇게 생각하면서 골머리를 앓고 계신 분께 작은 도움이 되기를 바라는 마음으로 글을 마칩니다.

 

그럼 모두들 Happy Charting -_-)/

 

데이터 과학 입문서 '친절한 R with 스포츠 데이터'를 썼습니다

어쩌다 보니 '한국어 사용자에게 도움이 될지도 모르는 R 언어 기초 회화 교재'를 세상에 내놓게 됐습니다. 책 앞 부분은 '한국어 tidyverse 사투리' 번역, 뒷부분은 'tidymodels 억양 따라하기'에 초점

kuduz.tistory.com

 

댓글,

KindeR | 카테고리 다른 글 더 보기