본문 바로가기
  • plotly로 바로쓰는 동적시각화 in R & 파이썬
Plotly in R - 그래프에 마우스를 올려봅시다

plotly 추세선 그리기 in R

by 아참형인간 2022. 5. 4.
trendline.knit

사용데이터 : https://2stndard.tistory.com/68

plotly에 추세선 넣기

추세선은 산점도나 시계열 그래프에서 데이터의 전반적 흐름을 설명해주는 직선 혹은 곡선을 말한다. 데이터의 전반적 상승 흐름이나 하락 흐름을 시각적으로 표현해주는 방법으로 추세선을 그리는 여러가지 방법이 있다. 시계열 데이터의 경우 가장 쉽게 추세선을 그리는 방법은 특정 구간의 시점과 종점을 이어주는 방식으로 그릴 수 도 있고 고점과 저점을 이어주어 그리는 방식도 있다. 하지만 산점도나 시계열 데이터 모두 선형 회귀를 사용하여 추세선을 그려주는 방법이 가장 많이 사용된다.

ggplot2에서는 geom_smooth()를 사용하여 간단히 추세선을 그릴 수 있다. 하지만 plotly에서는 geom_smooth()와 같이 추세선을 그려주는 기능을 지원하지 않는다. 따라서 plolty에서 추세선을 그리기 위한 방법 두 가지를 알아보고자 한다.

ggplotly() 사용

ggplot2에는 있지만 plolty에는 없는 기능을 구현하고자 할 때 가장 쉽게 사용할 수 있는 방법은 ggplotly()를 사용하는 방법이다. ggplolty()ggplot객체를 plolty객체로 변환하는 기능을 제공하는 함수이다. 따라서 geom_smooth()로 추세선을 그린 ggplot객체를 ggploltly()를 사용하여 plotly객체로 변환한다.

다음은 학과의 졸업자수 대비 취업률 산점도와 우리나라의 최근 200일간의 코로나 19 확진자에 대한 추세선을 geom_smooth()로 그려서 ggplotly()plotly객체로 변환하는 과정이다.

ggplot_trend_emp <- df_취업률_2000 |>
  ggplot(aes(x = 졸업자수, y = 취업자수)) + 
  geom_point() +
  geom_smooth(method = 'loess', aes(color="loess")) +
  geom_smooth(method = 'lm', aes(color="lm")) + 
  scale_color_manual(name="추세선", values=c("blue", "red"))

ggplotly(ggplot_trend_emp)
ggplot_trend_covid <- df_covid19 |>
  filter(iso_code == 'KOR', !is.na(new_cases)) |>
  filter(date >= max(date) - 200) |>
  ggplot(aes(x = date, y = new_cases)) +
  geom_line(aes(group = location)) +
  scale_x_date(date_breaks = "1 month", date_labels = "%Y %m") +
  scale_y_continuous(labels = scales::number) +
  labs(x = '년월', y = '신규확진자') +
  geom_smooth(method = 'loess', aes(color="loess")) +
  geom_smooth(method = 'lm', aes(color="lm")) + 
  scale_color_manual(name="추세선", values=c("blue", "red"))

ggplotly(ggplot_trend_covid)

plotly로 직접 그리기

이번에는 plotly 함수를 사용하여 직접 추세선을 그리는 과정을 알아보자. 앞서 설명한 바와 같이 추세선을 그리는데 가장 많이 사용하는 방법은 선형 회귀를 사용하는 방법이다. geom_smooth()에서도 ‘method’ 매개변수를 사용하여 선형회귀(lm)와 국소회귀(loess) 방법을 설정하여 추세선 그리는 방법을 변경할 수 있다.

이를 plotly에서 구현하기 위해서는 X축과 Y축에 설정되는 독립변수와 종속변수 간의 모델을 R base에서 제공하는 lm()loess()를 사용하여 만들어야 한다. 이렇게 만든 모델에 fitted()predict()를 사용하여 독립변수(X축)에 대응하는 종속변수(Y축)에 대한 추세선을 그려준다. 만약 신뢰구간(Confidence Interval, CI)의 표현이 필요하다면 add_ribbons()을 사용하여 그려줄 수 있다.

선형회귀(lm) 추세선

선형회귀 추세선을 plotly로 그리는 방법은 앞서 설명한 바와 같이 lm()을 사용하여 선형회귀 모델을 만들고 이를 fitted()를 사용하여 해당 모델에 대한 적합치를 Y축에 매핑함으로써 그려줄 수 있다.

lm_trend_emp <- lm(data = df_취업률_2000, 취업자수 ~ 졸업자수)

df_취업률_2000 |>
  plot_ly(type = 'scatter', mode = 'markers') |>
  add_trace(x = ~졸업자수, y = ~취업자수, name = 'data') |>
  add_trace(mode = 'lines', x = ~졸업자수, y = ~fitted(lm_trend_emp), name = '선형 추세선')
df_covid19_trend_kor <- 
  df_covid19 |>
  filter(iso_code == 'KOR', !is.na(new_cases)) |>
  filter(date >= max(date) - 200) |>
  mutate(date_int = as.integer(date))

trend_linear <- lm(data = df_covid19_trend_kor, new_cases ~ date)

df_covid19_trend_kor |>
  plot_ly() |>
  add_trace(type = 'scatter', mode = 'lines', x = ~date, y = ~new_cases, name = 'Data') |>
  add_trace(type = 'scatter', mode = 'lines', x = ~date, y = fitted(trend_linear), name = '선형 추세선')

국소회귀(loess) 추세선

국소회귀 추세선을 plotly로 그리는 방법은 앞서 설명한 바와 같이 loess()을 사용하여 선형회귀 모델을 만들고 이를 fitted()를 사용하여 해당 모델에 대한 적합치를 Y축에 매핑함으로써 그려줄 수 있다. 다만 이 과정에서 X축 변량의 순서대로 fitted()값을 그려야 정상적인 추세선이 나타나기 때문에 이 데이터를 정렬하기 위해 임시 데이터프레임을 생성하여 사용하였다.

loess_trend_emp <- loess(data = df_취업률_2000, 취업자수 ~ 졸업자수)

df_loess_trend_emp <- data.frame(X = df_취업률_2000$졸업자수, Y = fitted(loess_trend_emp)) |>
  arrange(X)

df_취업률_2000 |>
  plot_ly(type = 'scatter', mode = 'markers') |>
  add_trace(x = ~졸업자수, y = ~취업자수, name = 'data') |>
  add_trace(data = df_loess_trend_emp, mode = 'lines', x = ~X, y = ~Y, name = 'loess')

이번에는 95% 신뢰구간을 표시하는 방법을 알아보자. 95% 신뢰구간을 표현하기 위해서는 predict()를 사용하여 표준오차(Standard Error, se)를 산출하고 이 수치의 1.96을 곱한 값의 상한과 하한을 설정하고 이를 add_ribbons()를 사용하여 그려준다.

df_covid19_trend_kor <- 
  df_covid19 |>
  filter(iso_code == 'KOR', !is.na(new_cases)) |>
  filter(date >= max(date) - 200) |>
  mutate(date_int = as.integer(date))

trend_linear_loess <- loess(data = df_covid19_trend_kor, new_cases ~ date_int, span = 0.75)

trend_linear_loess_pred = predict(trend_linear_loess, se = TRUE)

df_covid19_trend_kor |>
  plot_ly(type="scatter", mode="lines") |>
  add_trace(x = ~date, y = ~new_cases, name = 'Data') |>
  add_trace(x = ~date, y = fitted(trend_linear_loess), name = 'loess') |>
  add_ribbons(x=~date, 
              ymin=(trend_linear_loess_pred$fit - (1.96 * trend_linear_loess_pred$se)), 
              ymax=(trend_linear_loess_pred$fit + (1.96 * trend_linear_loess_pred$se)), 
              name="95% CI", line=list(opacity=0.4, width=0))

댓글