본문 바로가기
  • plotly로 바로쓰는 동적시각화 in R & 파이썬
ggplot2

회귀방정식이 표기된 ggplot2 in R

by 아참형인간 2022. 2. 19.
lm_equation.knit

회귀 방정식을 ggplot에 넣기

회귀 모델을 사용하면 그 그래프를 직선으로 그리고 회귀 방정식을 그래프에 표현하는 것은 거의 당연한 시각화이다. 하지만 이렇게 당연한 시각화가 ggplot2에서는 너무도 당연하게 지원되지 않는다. 이를 위해서는 broom 패키지를 사용하여 회귀 방정식 표현에 사용할 회귀 계수를 알아내야 하고 방정식을 만들어 적절한 위치에 표기해 주어야 한다. 이 방법에 대해 알아본다.

먼저 데이터를 불러들이고 전처리하겠다. 사용하는 데이터는 교육통계 서비스 홈페이지에서 제공하는 2020년 취업통계 데이터 셋 을 사용하겠다. 2020년 취업통계 데이터 셋을 불러 들이는 코드는 다음과 같다.

library(readxl)
library(tidyverse)
library(patchwork)
library(showtext)
showtext_auto()

df_취업통계 <- read_excel('2020년 학과별 고등교육기관 취업통계.xlsx', 
                     ## '학과별' 시트의 데이터를 불러오는데,
                     sheet = '학과별',
                     ## 앞의 13행을 제외하고
                     skip = 13, 
                     ## 첫번째 행은 열 이름으로 설정
                     col_names = TRUE, 
                     ## 열의 타입을 설정, 처음 9개는 문자형으로 다음 79개는 수치형으로 설정
                     col_types = c(rep('text', 9), rep('numeric', 79)))

## df_취업통계에서 첫번째부터 9번째까지의 열과 '계'로 끝나는 열을 선택하여 다시 df_취업통계에 저장
df_취업통계 <- df_취업통계 |> select(1:9, ends_with('계'), '입대자')

이번 포스트에서는 전체 학과의 졸업자수 대비 취업자수 산점도를 기본으로 의약계열 졸업자와 취업자의 선형회귀 모델을 생성한다. 이 그룹에 대조 그룹으로 인문계열 졸업자와 취업자의 선형회귀 모델을 생성하여 붉은 색으로 표현한 후 각각의 범례 라벨에 선형회귀 방정식을 표현한다. 마지막으로 의약계열의 졸업자와 취업자의 밀집도를 확인하기 위해 러그 플롯을 가장자리에 붙이도록 하겠다.

먼저 의약계열과 인문계열의 선형회귀 모델 생성을 위해 데이터를 만들고 lm()으로 회귀모형을 만든다. 이 선형회귀 모델에서 필요한 회귀 계수를 산출하기 위해 broom 패키지의 glance()tidy() 패키지를 사용하였다.

## broom 패키지 설치
if(!require(broom)) {
  install.packages('broom')
  library(broom)
}

## 의약계열과 인문계열 데이터 생성 
df_의약 <- df_취업통계 |> filter(대계열 == '의약계열')
df_인문 <- df_취업통계 |> filter(대계열 == '인문계열')

## 의약계열과 인문계열의 선형회귀 모델 생성
model_lm_의약 <- lm(df_의약$취업자_합계_계 ~ df_의약$졸업자_계)
model_lm_인문 <- lm(df_인문$취업자_합계_계 ~ df_인문$졸업자_계)

## 각각의 선형회귀 모델의 요약 정보 생성
glance_의약 <- broom::glance(model_lm_의약)
glance_인문 <- broom::glance(model_lm_인문)

## 각각의 선형회귀 모델의 회귀 계수 생성
tidy_의약 <- broom::tidy(model_lm_의약)
tidy_인문 <- broom::tidy(model_lm_인문)

이제 그래프에 표현할 선형 회귀 방정식을 만든다. tidy()의 결과에서 회귀방정식을 생성하고 R 스퀘어 값을 뒤에 붙여준다.

## 의약계열의 회귀방정식과 R^2값에 대한 문자열 생성
equ_의약 <- paste0('의약계열 : y = ', round(tidy_의약$estimate[2], 2), 'x + ', round(tidy_의약$estimate[1], 2), ', R\u00B2', ' = ',round(glance_의약$r.squared, 3))

## 인문계열의 회귀방정식과 R^2값에 대한 문자열 생성
equ_인문 <- paste0('인문계열 : y = ', round(tidy_인문$estimate[2], 2), 'x + ', round(tidy_인문$estimate[1], 2), ', R\u00B2', ' = ',round(glance_인문$r.squared, 3))

이제 그래프를 그려본다. 그래프는 다음과 같은 순서로 그려진다.

  1. 전체 학과, 의약계열, 인문계열의 산점도
  2. 전체 학과, 의약계열, 인문계열의 추세선
  3. X, Y축의 눈금과 라벨, 범위를 설정
  4. 그래프 전체 제목, 부제목, 캡션 설정
  5. 의약계열과 인문계열의 색을 설정하는데 색 라벨을 회귀방정식으로 설정
  6. 적절한 테마 설정
  7. 러그 플롯과 의야계열 클러스터를 원으로 강조
library(grid)
library(ggalt)

df_취업통계 |> 
  ggplot() +
  ## 전체 계열의 산점도 생성
  geom_point(aes(x = 졸업자_계, y = 취업자_합계_계), color = 'grey75', alpha = 0.5) +
  ## 인문계열의 산점도 생성
  geom_point(data = df_인문,
             aes(x = 졸업자_계, y = 취업자_합계_계, color = '인문계열'), alpha = 0.5) + 
  ## 의약계열의 산점도 생성
  geom_point(data = df_의약,
             aes(x = 졸업자_계, y = 취업자_합계_계, color = '의약계열'), alpha = 0.5) + 
  ## 전체 계열의 회귀선 생성
  geom_smooth(aes(x = 졸업자_계, y = 취업자_합계_계), color = 'grey75', se = F, method = 'lm') + 
  ## 인문계열의 회귀선 생성
  geom_smooth(data = df_인문,
              aes(x = 졸업자_계, y = 취업자_합계_계, color = '인문계열'), se = F, method = 'lm') + 
  ## 의약계열의 회귀선 생성
  geom_smooth(data = df_의약,
             aes(x = 졸업자_계, y = 취업자_합계_계, color = '의약계열'), se = F, method = 'lm') + 
  ## X축 스케일의 눈금과 라벨을 100, 300, 500로 설정하고 0부터 500까지 범위 설정
  scale_x_continuous(breaks = c(100, 300, 500), labels = c(100, 300, 500), limits = c(0, 500)) +
  ## Y축 스케일의 눈금과 라벨을 100, 300, 500로 설정하고 0부터 500까지 범위 설정
  scale_y_continuous(breaks = c(100, 300, 500), labels = c(100, 300, 500), limits = c(0, 500)) + 
  labs(title =  expression(underline('의약계열 졸업현황')), x = '졸업자수', y = '취업자수', subtitle = "졸업자수 대비 취업자수", caption = '출처 : 실전에서 바로쓰는 데이터 시각화 in R') +
  scale_x_continuous(breaks = c(100, 300, 500), labels = c(100, 300, 500), limits = c(0, 500)) + 
  scale_y_continuous(breaks = c(100, 300, 500), labels = c(100, 300, 500), limits = c(0, 500)) + 
  scale_color_manual(name = NULL, values = c('의약계열' = '#4169E1', '인문계열' = '#FA8072'), labels = c(equ_의약, equ_인문)) +
  theme(text = element_text(size = 20), 
        strip.text.x = element_blank(),
        strip.background = element_rect(colour="white", fill="white"),
        legend.position=c(.25,.9), 
        legend.background = element_rect(fill = NA), 
        legend.key = element_rect(fill = NA), 
        plot.title = element_text(size = rel(2), family = 'NanumBarunGothicBold', hjust = 0.5),
        plot.subtitle = element_text(vjust = 0.5, family = 'NanumBarunGothic', color = 'grey30'),
        axis.line = element_blank(), 
        plot.background = element_rect(fill = '#FFFAFA'), 
        panel.background = element_rect(fill = '#FFFAFA'), 
        plot.margin = margin(0.025, 0.01, 0.01, 0.01, "npc"), 
        plot.caption = element_text(color = 'grey50', hjust = 1)
  ) +
  geom_encircle(data = df_의약, 
                aes(x = 졸업자_계, y = 취업자_합계_계, color='의약계열')) + 
  geom_rug(data = df_의약,
           aes(x = 졸업자_계, y = 취업자_합계_계), col= "steelblue", alpha=0.5)

댓글