일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 26 |
27 | 28 | 29 | 30 |
- 데이터 핸들링
- R 연습문제
- dplyr
- R
- 강화학습 #추천서적 #강화학습인액션
- 주식데이터시각화
- R ggplot2
- 카플란마이어
- 교차타당성
- R select
- 생존그래프
- CrossValidation
- 확률실험
- 이산형 확률분포
- 미국 선거데이터
- ggsurvplot
- geom_errorbar
- ggplot()
- R dplyr
- 생존분석
- ISLR
- R mutate
- 의사결정나무
- ggplot2
- R filter
- Bias-Variance Tradeoff
- 데이터핸들링
- 콕스비례모형
- R문법
- R 결측치
- Today
- Total
Must Learning With Statistics
[R ggplot2] 테슬라 주가 데이터를 활용한 시계열 자료 시각화 본문
시계열 데이터는 매우 중요한 데이터 타입 중 하나입니다. 하지만, 시간의 흐름에 따라 값이 입력되는 데이터이기 때문에, 일반인 독립(Independent)데이터와 같은 방식으로 처리하면 잘못된 분석을 진행하게 됩니다. 이번 포스팅은 시계열 데이터를 다루는 방법 및 시각화를 하는 방법에 다루어보도록 하겠습니다.
데이터 다운로드 링크 : https://www.kaggle.com/timoboz/tesla-stock-data-from-2010-to-2020
0. 데이터 및 패키지 로드
library(ggplot2)
library(dplyr)
library(reshape)
library(tseries)
library(cowplot)
library(forecast)
TSLA = read.csv("D:\\Dropbox\\DATA SET(Dropbox)\\tesla-stock-data-from-2010-to-2020\\TSLA.csv")
TSLA$Date = as.Date(TSLA$Date)
Date | Open | High | Low | Close | Adj.Close | Volume |
---|---|---|---|---|---|---|
2010-06-29 | 19.00 | 25.00 | 17.54 | 23.89 | 23.89 | 18766300 |
2010-06-30 | 25.79 | 30.42 | 23.30 | 23.83 | 23.83 | 17187100 |
2010-07-01 | 25.00 | 25.92 | 20.27 | 21.96 | 21.96 | 8218800 |
2010-07-02 | 23.00 | 23.10 | 18.71 | 19.20 | 19.20 | 5139800 |
2010-07-06 | 20.00 | 20.00 | 15.83 | 16.11 | 16.11 | 6866900 |
2010-07-07 | 16.40 | 16.63 | 14.98 | 15.80 | 15.80 | 6921700 |
데이터는 다음과 같습니다. 일별에 따라, 시작가, 종가 등이 기록이 되어 있습니다. 그럼 이제 이 데이터를 통해 시계열 데이터를 다루는 방법에 대해 다루어보도록 하겠습니다. 먼저 시계열 데이터를 다룰 때 가장 중요한 패키지는 tseries입니다. 그 다음으로는 forecast패키지입니다. 그리고 데이터를 불러왔을 때, 가장 먼저 해야할 작업은 Date변수의 strings를 ‘Date’ 타입으로 변경시켜주는 것입니다.
1. Raw Data 시각화
TSLA %>%
select(-Volume) %>%
melt(id.vars = c("Date")) %>%
ggplot() +
geom_point(aes(x = Date, y = value, col = variable),
alpha = 0.5) +
geom_line(aes(x = Date, y = value, col = variable, group = variable),
alpha = 0.8) +
xlab("Date") + ylab("Stock Price") +
labs(col = "Types of Price") +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
legend.position = c(0.2,0.8))
Volume은 거래량을 의미하는데, 단위가 다르기 때문에 빼고 시각화를 하였습니다.
TSLA %>%
select(Date,Volume) %>%
ggplot() +
geom_point(aes(x = Date, y = Volume),
alpha = 0.5) +
geom_line(aes(x = Date, y = Volume),
alpha = 0.8) +
xlab("Date") + ylab("Volume") +
labs(col = "Types of Price") +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"))
Volume은 따로 그려주었습니다. 만약 위 두그래프를 같이 그리고 싶으시다면 우리는 cowplot패키지를 활용하면 두 그래프를 함께 그릴 수가 있습니다.
A = TSLA %>%
select(-Volume) %>%
melt(id.vars = c("Date")) %>%
ggplot() +
geom_point(aes(x = Date, y = value, col = variable),
alpha = 0.5) +
geom_line(aes(x = Date, y = value, col = variable, group = variable),
alpha = 0.8) +
labs(col = "Types of Price") + ylab("SalePrice") +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
axis.title.x = element_blank(),
axis.text.x = element_blank(),
legend.position = c(0.2,0.5))
B = TSLA %>%
select(Date,Volume) %>%
ggplot() +
geom_point(aes(x = Date, y = Volume),
alpha = 0.5) +
geom_line(aes(x = Date, y = Volume),
alpha = 0.8) +
xlab("Date") + ylab("Volume") +
labs(col = "Types of Price") +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"))
cowplot::plot_grid(A,B,ncol = 1,labels = c("A","B"))
이렇게 간단하게 시계열 데이터를 시각화할 수 있습니다. 가장 중요한 것은 날짜변수에 대해서는 꼭 as.Date() 혹은 as.POSIXct()를 활용해서 strings를 변환시켜주어야 한다는 점입니다.
2. 지수평활법(Moving Average) 시각화
위 raw Data를 그대로 사용했을 경우에는 데이터가 너무 많아 조금 복잡한 느낌이 들기도 합니다. 그래서 시계열 데이터에서는 Smoothing(평활법)이 자주 사용이 됩니다. 가장 많이 사용되는 지수평활법을 활용해보도록 하겠습니다.
Smoothing = function(x,interval){
ts_x = ts(x) # TimeSeries Strings
Sm = stats::filter(ts_x, filter = rep(1/interval,interval)) # To avoid packages collision
return(Sm)
}
stats::filter()은 dplyr::filter()과 명령어가 충돌하는 것을 방지하기 위해서 주는 대비책입니다. 그냥 filter만 사용해도 지수평활법이 바로 적용이 되나, 여러변수에 대해 한번에 처리하도록 하기위해 function을 간단하게 만들어보았습니다. filter 명령어에서 filter 옵션은 몇일을 단위로 평활을 적용할 것인지 설정해주는 부분입니다. 값이 크면 클수록 여러 일에 해당되는 데이터를 가지고 계산합니다. 즉, 단위를 크게 줄수록 시계열 선은 완만해지게 됩니다.
# Open (1 Week Smoothing)
Open_Week = Smoothing(x = TSLA$Open,
interval = 7)
DATE = TSLA$Date
ggplot(NULL) +
geom_point(aes(x = DATE, y = Open_Week)) +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
axis.title.x = element_blank(),
axis.text.x = element_blank(),
legend.position = c(0.2,0.5))
제가 만든 Smoothing function과 함께 1주일 단위의 평활 데이터를 그렸습니다. 그럼 이제 여러 변수에 대해 한번에 처리해보도록 하겠습니다.
# 30 days Smoothing
L_Smoothing = lapply(TSLA[,-grep("Date",colnames(TSLA))],
function(x, interval) Smoothing(x, 30))
L_Smoothing = as.data.frame(L_Smoothing)
head(L_Smoothing,n = 30)
Open High Low Close Adj.Close Volume
1 NA NA NA NA NA NA
2 NA NA NA NA NA NA
3 NA NA NA NA NA NA
4 NA NA NA NA NA NA
5 NA NA NA NA NA NA
6 NA NA NA NA NA NA
7 NA NA NA NA NA NA
8 NA NA NA NA NA NA
9 NA NA NA NA NA NA
10 NA NA NA NA NA NA
11 NA NA NA NA NA NA
12 NA NA NA NA NA NA
13 NA NA NA NA NA NA
14 NA NA NA NA NA NA
15 20.36567 21.17667 19.19400 20.04133 20.04133 3567430
16 20.35533 20.97267 19.20433 19.84167 19.84167 2968473
[ reached 'max' / getOption("max.print") -- omitted 14 rows ]
Open | High | Low | Close | Adj.Close | Volume |
---|---|---|---|---|---|
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
NA | NA | NA | NA | NA | NA |
20.36567 | 21.17667 | 19.19400 | 20.04133 | 20.04133 | 3567430.0 |
20.35533 | 20.97267 | 19.20433 | 19.84167 | 19.84167 | 2968473.3 |
20.08900 | 20.55533 | 19.00733 | 19.63400 | 19.63400 | 2418603.3 |
19.86167 | 20.30633 | 18.92033 | 19.51267 | 19.51267 | 2165776.7 |
19.71000 | 20.16300 | 18.90533 | 19.49867 | 19.49867 | 2010643.3 |
19.67533 | 20.14300 | 19.00367 | 19.60000 | 19.60000 | 1796676.7 |
19.78167 | 20.24167 | 19.12433 | 19.69900 | 19.69900 | 1585996.7 |
19.86167 | 20.29933 | 19.21633 | 19.74333 | 19.74333 | 1348253.3 |
19.89733 | 20.33967 | 19.28167 | 19.80000 | 19.80000 | 1223100.0 |
19.93533 | 20.41700 | 19.34833 | 19.90267 | 19.90267 | 1185953.3 |
19.99733 | 20.45267 | 19.41667 | 19.93800 | 19.93800 | 1119053.3 |
20.03800 | 20.44700 | 19.44333 | 19.94000 | 19.94000 | 995990.0 |
20.03633 | 20.40600 | 19.46333 | 19.93533 | 19.93533 | 885790.0 |
20.00467 | 20.35833 | 19.44500 | 19.90400 | 19.90400 | 811066.7 |
19.94900 | 20.28967 | 19.40133 | 19.83600 | 19.83600 | 752610.0 |
19.87600 | 20.22100 | 19.37733 | 19.80867 | 19.80867 | 698470.0 |
lapply를 활용하면 여러 변수에 대해서도 한번에 함수를 적용할 수가 있습니다. 혹시 apply계열의 함수에 이해가 잘 안되시는 분들은 https://mustlearning.tistory.com/9?category=859137 포스팅을 참고해주시길 바랍니다.
L_Smoothing$Date = DATE
L_Smoothing %>%
na.omit() %>%
select(-Volume) %>%
melt(id.vars = c("Date")) %>%
ggplot() +
geom_point(aes(x = Date, y = value, col = variable),
alpha = 0.5) +
geom_line(aes(x = Date, y = value, col = variable, group = variable),
alpha = 0.8) +
xlab("Date") + ylab("Stock Price") +
ggtitle("30 days Smoothing (Moving Average)") +
labs(col = "Types of Price") +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
legend.position = c(0.25,0.7))
이번에는 평활주기를 여러 값으로 설정하여 진행하도록하겠습니다. 이번에는 column이 아니라, 조건 값을 여러번 바꿔주면서 실행마다 데이터를 저장해주어야 하기때문에 assign을 활용해야 합니다.
INTERVAL = c(30,60,90,120,365)
for(i in INTERVAL){
DF = lapply(TSLA[,-grep("Date",colnames(TSLA))],
function(x, interval) Smoothing(x, i))
DF = as.data.frame(DF)
assign(paste0("L_Smoothing_",i),DF)
}
Open | High | Low | Close | Adj.Close | Volume | |
---|---|---|---|---|---|---|
500 | 30.80000 | 31.48733 | 30.07967 | 30.76133 | 30.76133 | 1165997 |
501 | 30.89667 | 31.62433 | 30.21567 | 30.91967 | 30.91967 | 1172200 |
502 | 31.08967 | 31.85233 | 30.42033 | 31.18000 | 31.18000 | 1200807 |
503 | 31.32200 | 32.07900 | 30.59600 | 31.36233 | 31.36233 | 1252087 |
504 | 31.44133 | 32.25500 | 30.71267 | 31.50367 | 31.50367 | 1327120 |
505 | 31.59200 | 32.37833 | 30.84267 | 31.60533 | 31.60533 | 1344653 |
506 | 31.66733 | 32.45767 | 30.92267 | 31.70067 | 31.70067 | 1380533 |
507 | 31.74033 | 32.49467 | 31.00500 | 31.72000 | 31.72000 | 1397390 |
508 | 31.75200 | 32.49600 | 31.02700 | 31.74400 | 31.74400 | 1426200 |
509 | 31.77500 | 32.50067 | 31.02500 | 31.72033 | 31.72033 | 1501973 |
510 | 31.78667 | 32.47933 | 30.96400 | 31.66567 | 31.66567 | 1549247 |
Open | High | Low | Close | Adj.Close | Volume | |
---|---|---|---|---|---|---|
500 | 30.67583 | 31.35683 | 29.83317 | 30.49450 | 30.49450 | 1470882 |
501 | 30.61917 | 31.30317 | 29.78283 | 30.44800 | 30.44800 | 1458575 |
502 | 30.52883 | 31.20350 | 29.70200 | 30.36983 | 30.36983 | 1391440 |
503 | 30.46683 | 31.16117 | 29.64100 | 30.33650 | 30.33650 | 1410872 |
504 | 30.43317 | 31.12567 | 29.61667 | 30.32033 | 30.32033 | 1409672 |
505 | 30.42083 | 31.10967 | 29.61517 | 30.32000 | 30.32000 | 1394453 |
506 | 30.41633 | 31.10567 | 29.62233 | 30.33267 | 30.33267 | 1385292 |
507 | 30.42283 | 31.13083 | 29.63667 | 30.37600 | 30.37600 | 1380643 |
508 | 30.46250 | 31.17600 | 29.67717 | 30.40700 | 30.40700 | 1366925 |
509 | 30.49267 | 31.18333 | 29.70533 | 30.41750 | 30.41750 | 1351095 |
510 | 30.48317 | 31.16750 | 29.69700 | 30.40917 | 30.40917 | 1322808 |
이렇게 하면 30일, 60일, 90일, 120일, 365일 등의 주기로 데이터셋이 따로 만들어진 것을 확인할 수가 있습니다.
TSLA2 = data.frame(
DATE = TSLA$Date,
Open = TSLA$Open,
Open_30 = L_Smoothing_30$Open,
Open_60 = L_Smoothing_60$Open,
Open_90 = L_Smoothing_90$Open,
Open_120 = L_Smoothing_120$Open,
Open_365 = L_Smoothing_365$Open
)
TSLA2 %>%
melt(id.vars = c("DATE")) %>%
ggplot() +
geom_line(aes(x = DATE, y = value, col = variable, group = variable),size = 1.2) +
theme_bw() +
xlab("Date") + ylab("Stock Price") +
ggtitle("Smoothing (Moving Average)") +
labs(col = "Smoothing Days") +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
legend.position = c(0.2,0.6))
TSLA2 %>%
melt(id.vars = c("DATE")) %>%
ggplot() +
geom_line(aes(x = DATE, y = value, col = variable, group = variable),size = 1.2) +
theme_bw() +
xlab("Date") + ylab("Stock Price") +
ggtitle("Smoothing (Moving Average)") +
labs(col = "Smoothing Days") +
guides(col = FALSE) +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
axis.text.x = element_text(angle = 90)) +
facet_wrap(~variable)
facet_wrap을 활용하면 따로따로 그릴 수도 있습니다. 확실히 평활을 적용한게 더 보기가 좋습니다.
3. 시계열 분해
시계열 데이터는 분해라는 것을 할 수 있습니다. 이에 대해서는 다른 포스팅에서 자세하게 다루도록 하겠습니다. 시계열분해는 2가지 방법이 있습니다.
- Additive
- Multiplicative
Decomposition = function(x){
TS_X = ts(x, frequency = 365)
Add = decompose(TS_X,type = "additive")
Multi = decompose(TS_X, type = "multiplicative")
Result = list()
Result$Add = Add
Result$Multi = Multi
return(Result)
}
decompse만 써도 시계열 분해가 바로 진행이 되지만, 저는 이번에도 간단하게 함수를 만들어주도록 하겠습니다. R의 작업속도를 빠르게 하기 위해서는 이러한 습관을 만드시는게 매우 중요하기 때문입니다.
분해된 시계열 데이터는 autoplot을 활용하면 간편하게 그릴 수가 있습니다. theme 옵션은 취향에 따라 주시면 됩니다.
4. Waterfall Chart
비즈니스 영역에서는 Waterfall Chart를 자주 그리고는 합니다. Waterfall Chart를 그리기 위해서 우리는 변화량을 계산해야합니다.
Difference = function(x){
Diff_Vector = c()
Diff_Vector[1] = 0
for(k in 2:length(x)){
Diff = x[k] - x[k-1]
Diff_Vector[k] = Diff
}
return(Diff_Vector)
}
이번에도 굳이 function을 만들어 주었습니다. 귀찮지만 이렇게 미리 작업을 해두면 나중에 코드가 길어졌을 때를 대비해서 코드를 간결하게 할 수가 있습니다.
Open_Diff = Difference(x = TSLA$Open)
WATER = data.frame(
DATE = TSLA$Date,
Open = Open_Diff
)
WATER$Increase = ifelse(WATER$Open >= 0 , "Plus", "Minus")
DATE | Open | Increase |
---|---|---|
2010-06-29 | 0.000000 | Plus |
2010-06-30 | 0.790001 | Plus |
2010-07-01 | 2.000000 | Plus |
2010-07-02 | 3.000000 | Plus |
2010-07-06 | 3.600000 | Plus |
2010-07-07 | 0.260001 | Plus |
WATER %>%
mutate(Increase = factor(Increase, levels = c("Plus","Minus"))) %>%
ggplot() +
geom_bar(aes(x = DATE, y = Open, fill = Increase), stat = 'identity') +
scale_fill_manual(values = c("red","royalblue")) +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
legend.position = "bottom")
WATER[(nrow(WATER)-100):nrow(WATER),] %>%
mutate(Increase = factor(Increase, levels = c("Plus","Minus"))) %>%
ggplot() +
geom_bar(aes(x = DATE, y = Open, fill = Increase), stat = 'identity') +
scale_fill_manual(values = c("red","royalblue")) +
theme_bw() +
theme(text = element_text(size = 15, face = "bold"),
legend.position = "bottom")
geom_bar()을 이용해서 간단하게 그래프를 그릴 수가 있습니다. 시계열은 참 하기 싫은 데이터 중 하나입니다. 고려할게 너무 많습니다. 하지만 꼭 숙지해야되는 데이터이기도 합니다. 다음에는 시계열 분석방법에 대해 다루어보도록 하겠습니다.

'R Code' 카테고리의 다른 글
[R] 중고 자동차 데이터를 활용한 탐색적 자료분석 실전 예시 (1) | 2020.03.01 |
---|---|
관광데이터를 이용한 R 연관규칙 분석 (2) | 2020.02.27 |
[R ggplot2 시각화] 대한민국 코로나 데이터 시각화 (0) | 2020.02.22 |
[R 대시보드] Flexdashboard 패지키를 활용한 R 대시보드 만들기 2편 (0) | 2020.02.09 |
[R 대시보드] Flexdashboard 패지키를 활용한 R 대시보드 만들기 1편 (0) | 2020.02.09 |