zoo/xts
R에서 시계열 데이터를 처리하기 위한 전용 자료구조로 zoo
, Z’s Ordered Observations와 xts
, eXtensible Time Series가 많이 활용되었지만, tidyverse
등장이후 시계열 자료구조도 lubridate
팩키지의 등장 이후 시계열이 아닌 많이 사용되는 데이터프레임에서 표준으로 자리를 잡아가고 있으며 tsibble
이 두가지 큰 흐름의 간극을 매워가면서 새로운 지평을 열어가고 있다.
xts
기본xts
팩키지는 시계열 데이터를 기본 행렬자료구조에 시계열 정보를 인덱스로 붙여 표현한다.
xts
데이터 생성 및 분해xts
자료구조는 zoo
를 기반으로 확장한 시계열 자료구조로 행렬을 데이터에 담고 있고, 시계열 정보를 인덱스를 표현한다. 따라서 두가지 데이터와 시계열 인덱스가 있는 경우 xts()
함수에 넣어 order.by=
인자를 넣어 xts
자료구조를 생성시킨다.
library(xts)
time_data <- matrix(1:6, ncol = 2, nrow = 3)
time_index <- Sys.Date() + 1:3
time_xts <- xts(time_data, order.by = time_index)
class(time_xts)
[1] "xts" "zoo"
time_xts
[,1] [,2]
2019-02-20 1 4
2019-02-21 2 5
2019-02-22 3 6
xts
자료구조에서 시계열 정보를 날려버리고 데이터만 취할 경우 coredata()
함수를 사용하고, 시계열 인덱스 색인 정보만 추출할 경우 index()
함수를 사용해서 추출한다.
coredata(time_xts)
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
index(time_xts)
[1] "2019-02-20" "2019-02-21" "2019-02-22"
xts
데이터 가져오기AirPassengers
시계열 데이터는 ts
자료구조를 갖고 있어 이를 xts
자료구조로 변환시킬 경우 as.xts()
함수를 사용한다. 마찬가지로 read_._csv()
, read.zoo()
으로 데이터프레임으로 불러온 후에 xts()
함수에 벡터 혹은 행렬로 데이터를 넣고 시계열(POSIXlt) 벡터를 order.by=
에 지정하여 xts
객체를 생성한다.
## ts 객체변환
library(tidyverse)
as.xts(AirPassengers) %>% head
[,1]
Jan 1949 112
Feb 1949 118
Mar 1949 132
Apr 1949 129
May 1949 121
Jun 1949 135
## 데이터프레임 --> xts
sunspot_df <- read_csv("https://raw.githubusercontent.com/statsmodels/statsmodels/master/statsmodels/datasets/sunspots/sunspots.csv", col_types = cols(
YEAR = col_integer(),
SUNACTIVITY = col_double()
))
sunspot_df <- sunspot_df %>%
mutate(YEAR = lubridate::ymd(YEAR, truncated = 2L))
sunspot_xts <- xts(sunspot_df[,-1], order.by=sunspot_df$YEAR)
sunspot_xts %>% head
SUNACTIVITY
1700-01-01 5
1701-01-01 11
1702-01-01 16
1703-01-01 23
1704-01-01 36
1705-01-01 58
xts
데이터 쿼리xts
시계열 데이터가 준비되면, 원하는 정보를 xts
자료구조에서 쿼리를 작성해서 던지게 되면 뽑아낼 수 있다. PerformanceAnalytics
팩키지 edhec
데이터셋은 이미 xts
자료구조로 되어 있어 쿼리 연습을 하기 적합하다. EDHEC
- Risk Hedge Fund Style Indices는 헷지펀드 인덱스 수익률에 대한 시계열 정보가 담겨있다.
library(PerformanceAnalytics)
data("edhec")
edhec["2009-01", 1:3]
Convertible Arbitrage CTA Global Distressed Securities
2009-01-31 0.0491 -0.0016 0.0082
edhec["2009-01/2009-05", 1:3]
Convertible Arbitrage CTA Global Distressed Securities
2009-01-31 0.0491 -0.0016 0.0082
2009-02-28 0.0164 -0.0031 -0.0122
2009-03-31 0.0235 -0.0180 0.0022
2009-04-30 0.0500 -0.0140 0.0387
2009-05-31 0.0578 0.0213 0.0504
index()
함수를 시계열 인덱스를 빼서 부울 연산자와 조합하여 해당기간 정보를 뽑아내거나 시계열 데이터를 별도 벡터로 정리한 후에 이를 색인으로 활용하여 데이터를 추출하는 것도 가능하다.
edhec[index(edhec) > "2009-01-01" & index(edhec) <= "2009-02-28"]
Convertible Arbitrage CTA Global Distressed Securities
2009-01-31 0.0491 -0.0016 0.0082
2009-02-28 0.0164 -0.0031 -0.0122
Emerging Markets Equity Market Neutral Event Driven
2009-01-31 -0.0112 0.0079 0.0132
2009-02-28 -0.0133 -0.0046 -0.0091
Fixed Income Arbitrage Global Macro Long/Short Equity
2009-01-31 0.0112 0.0029 -0.0017
2009-02-28 0.0065 -0.0055 -0.0161
Merger Arbitrage Relative Value Short Selling Funds of Funds
2009-01-31 0.0056 0.0100 0.0282 0.0060
2009-02-28 0.0006 -0.0016 0.0328 -0.0037
q_dates <- lubridate::ymd(c("2009-01-31", "2009-02-28"))
edhec[q_dates]
Convertible Arbitrage CTA Global Distressed Securities
2009-01-31 0.0491 -0.0016 0.0082
2009-02-28 0.0164 -0.0031 -0.0122
Emerging Markets Equity Market Neutral Event Driven
2009-01-31 -0.0112 0.0079 0.0132
2009-02-28 -0.0133 -0.0046 -0.0091
Fixed Income Arbitrage Global Macro Long/Short Equity
2009-01-31 0.0112 0.0029 -0.0017
2009-02-28 0.0065 -0.0055 -0.0161
Merger Arbitrage Relative Value Short Selling Funds of Funds
2009-01-31 0.0056 0.0100 0.0282 0.0060
2009-02-28 0.0006 -0.0016 0.0328 -0.0037
최근 3개월, 마지막 1년 등을 first()
, last()
함수로 구현할 수 있다. xts::last()
와 xts::first()
를 조합시켜 중간, 예를 들어 최근 1년 첫 3개월을 추출할 수도 있다.
xts::first(edhec[, c("Funds of Funds", "Short Selling")], "3 months")
Funds of Funds Short Selling
1997-01-31 0.0317 -0.0166
1997-02-28 0.0106 0.0426
1997-03-31 -0.0077 0.0778
xts::last(edhec[, c("Funds of Funds", "Short Selling")], "7 months")
Funds of Funds Short Selling
2009-02-28 -0.0037 0.0328
2009-03-31 0.0008 -0.0462
2009-04-30 0.0092 -0.0820
2009-05-31 0.0312 0.0008
2009-06-30 0.0024 -0.0094
2009-07-31 0.0153 -0.0596
2009-08-31 0.0113 -0.0165
xts::last(edhec[, c("Funds of Funds", "Short Selling")], "1 year") %>% xts::first(., "3 months")
Funds of Funds Short Selling
2009-01-31 0.0060 0.0282
2009-02-28 -0.0037 0.0328
2009-03-31 0.0008 -0.0462
xts
데이터 결합x_df
, y_df
데이터프레임을 x_xts
, y_xts
객체로 변환을 한 후에 merge()
함수에 index=
인자를 넘겨 두 xts
객체를 결합시킬 수 있다. 그리고 이를 +
, -
, *
, /
등 사칙연산도 수행시킬 수 있다.
library(lubridate)
## 두 xts 객체 생성
x_df <- tribble(~"날짜", ~"값",
"2019-02-09", 0,
"2019-02-10", 0,
"2019-02-11", 0)
y_df <- tribble(~"날짜", ~"값",
"2019-02-09", 1,
"2019-02-10", 2,
"2019-02-12", 3)
x_xts <- xts(x_df$`값`, order.by = ymd(x_df$`날짜`))
y_xts <- xts(y_df$`값`, order.by = ymd(y_df$`날짜`))
## 날짜가 다른 두 xts 객체 결합
x_xts + y_xts
e1
2019-02-09 1
2019-02-10 2
## 날짜가 다른 두 xts 객체 기준 잡고 결합
(x_join <- merge(x_xts, index(y_xts), fill=0))
x_xts
2019-02-09 0
2019-02-10 0
2019-02-11 0
2019-02-12 0
(y_join <- merge(y_xts, index(x_xts), fill=0))
y_xts
2019-02-09 1
2019-02-10 2
2019-02-11 0
2019-02-12 3
## 연산
x_join / y_join
x_xts
2019-02-09 0
2019-02-10 0
2019-02-11 NaN
2019-02-12 0
xts
데이터 병합(merge)merge()
함수를 활용하여 서로 다른 변수를 갖는 xts
객체를 병합(merge) 할 수 있다. 이를 위해서 join=
인자를 사용하고 더 나아가 결측값도 fill = na.locf
을 사용해서 채워넣는 것이 가능하다.
## 두 xts 객체 생성
x_df <- tribble(~"날짜", ~"삼성전자",
"2019-02-09", 0,
"2019-02-10", 0,
"2019-02-11", 0)
y_df <- tribble(~"날짜", ~"KPMG",
"2019-02-09", 1,
"2019-02-10", 2,
"2019-02-12", 3)
x_xts <- xts(x_df$`삼성전자`, order.by = ymd(x_df$`날짜`))
y_xts <- xts(y_df$KPMG, order.by = ymd(y_df$`날짜`))
merge(x_xts, y_xts)
x_xts y_xts
2019-02-09 0 1
2019-02-10 0 2
2019-02-11 0 NA
2019-02-12 NA 3
merge(x_xts, y_xts, join="inner")
x_xts y_xts
2019-02-09 0 1
2019-02-10 0 2
merge(x_xts, y_xts, join="left", fill = na.locf)
x_xts y_xts
2019-02-09 0 1
2019-02-10 0 2
2019-02-11 0 2
횡으로 xts
객체를 결합하는 것과는 별개로 종으로 rbind
함수를 사용해서 결합시킬 수도 있다.
## 두 xts 객체 결합
rbind(x_xts, y_xts)
[,1]
2019-02-09 0
2019-02-09 1
2019-02-10 0
2019-02-10 2
2019-02-11 0
2019-02-12 3
xts
결측값 처리na.locf()
함수를 사용해서 결측값을 채워넣을 수 있다. 물로 na.fill()
함수에 fill=
인자를 지정해서 결측값을 넣는 것도 가능하다. 그외에도 na.trim()
, na.omit()
함수를 이용해서 결측값을 제거할 수도 있고ㅡ, na.approx()
함수로 결측값에 대한 보정도 가능하다.
## NA 결측값을 갖는 `xts` 객체 생성
na_df <- tribble(~"날짜", ~"KPMG",
"2019-02-07", NA,
"2019-02-09", 1,
"2019-02-10", 2,
"2019-02-11", NA,
"2019-02-12", NA,
"2019-02-13", 3,
"2019-02-17", NA)
na_xts <- xts(na_df$KPMG, order.by = ymd(na_df$`날짜`))
cbind(na_xts, na.locf(na_xts), na.locf(na_xts, fromLast = TRUE))
na_xts na.locf.na_xts. na.locf.na_xts..fromLast...TRUE.
2019-02-07 NA NA 1
2019-02-09 1 1 1
2019-02-10 2 2 2
2019-02-11 NA 2 3
2019-02-12 NA 2 3
2019-02-13 3 3 3
2019-02-17 NA 3 NA
na.fill(na_xts, fill=999)
[,1]
2019-02-07 999
2019-02-09 1
2019-02-10 2
2019-02-11 999
2019-02-12 999
2019-02-13 3
2019-02-17 999
na.trim(na_xts)
[,1]
2019-02-09 1
2019-02-10 2
2019-02-11 NA
2019-02-12 NA
2019-02-13 3
na.omit(na_xts)
[,1]
2019-02-09 1
2019-02-10 2
2019-02-13 3
na.approx(na_xts)
[,1]
2019-02-09 1.000000
2019-02-10 2.000000
2019-02-11 2.333333
2019-02-12 2.666667
2019-02-13 3.000000
na.spline(na_xts)
[,1]
2019-02-07 -2.0000000
2019-02-09 1.0000000
2019-02-10 2.0000000
2019-02-11 2.6666667
2019-02-12 3.0000000
2019-02-13 3.0000000
2019-02-17 -0.3333333
xts
지연시차(lag), 선행시차(lead)lag()
함수의 k=
인수값을 달리하여 지연시차(lag) 및 선행시차(lead)를 담아낼 수 있다.
lead_xts <- lag(na_xts, k = -1)
lag_xts <- lag(na_xts, k = 1)
merge(lead_xts, na_xts, lag_xts)
lead_xts na_xts lag_xts
2019-02-07 NA NA NA
2019-02-09 NA 1 NA
2019-02-10 1 2 1
2019-02-11 2 NA 2
2019-02-12 NA NA NA
2019-02-13 NA 3 NA
2019-02-17 3 NA 3
시계열 데이터의 정상성(stationarity)을 확보화기 위해서 차분을 사용하고 이를 계절성(seasonality)을 함께 반영하는 경우 diff()
함수에 differences=
를 인자로 함께 넣어 구현한다.
air_xts <- as.xts(AirPassengers) %>% head(., n=24)
air_diff <- diff(air_xts, lag=12, differences = 1)
merge(air_xts, air_diff)
air_xts air_diff
Jan 1949 112 NA
Feb 1949 118 NA
Mar 1949 132 NA
Apr 1949 129 NA
May 1949 121 NA
Jun 1949 135 NA
Jul 1949 148 NA
Aug 1949 148 NA
Sep 1949 136 NA
Oct 1949 119 NA
Nov 1949 104 NA
Dec 1949 118 NA
Jan 1950 115 3
Feb 1950 126 8
Mar 1950 141 9
Apr 1950 135 6
May 1950 125 4
Jun 1950 149 14
Jul 1950 170 22
Aug 1950 170 22
Sep 1950 158 22
Oct 1950 133 14
Nov 1950 114 10
Dec 1950 140 22
apply()
와 rollapply()
함수apply()
함수split-apply-combine
패턴을 동일하게 xts
시계열에도 적용시킬 수 있다. 이를 통해서 일별, 주별, 월별, 분기별, 년도별로 다양한 통계량을 산출할 수 있게 된다. endpoints()
함수로 시계열 끝점을 두어 시계열을 쪼개고(split) 함수를 적용(apply)시킨 후에 period.apply()
함수로 결합(combine)하는 과정을 거친다.
자주 사용되는 apply.weekly()
, apply.monthly()
, apply.yearly()
, apply.quarterly()
등 함수를 바로 사용하는 것도 가능하다.
ep <- endpoints(edhec, on="years")
period.apply(edhec[ ,"Funds of Funds"], INDEX=ep, FUN=mean) %>% head
Funds of Funds
1997-12-31 0.013591667
1998-12-31 0.003725000
1999-12-31 0.021300000
2000-12-31 0.006616667
2001-12-31 0.002933333
2002-12-31 0.001066667
apply.quarterly(edhec[ ,"Funds of Funds"], mean) %>% head
Funds of Funds
1997-03-31 0.011533333
1997-06-30 0.016966667
1997-09-30 0.027333333
1997-12-31 -0.001466667
1998-03-31 0.019766667
1998-06-30 0.002466667
rollapply()
함수apply()
함수는 split
으로 쪼개진 각 부분 시계열에 대해 함수연산을 적용시켜 결과를 취합하는 이산연산 과정인 반면, rollapply()
함수는 이동평균이나 합계(sum()
) 함수처럼 연속연산과 대비된다.
bimonthly <- rollapply(edhec["200701/12", "Funds of Funds"], 2, mean)
edhec_sum <- rollapply(edhec["200701/12", "Funds of Funds"], 3, sum)
merge(edhec["200701/12", "Funds of Funds"], bimonthly, edhec_sum)
Funds.of.Funds Funds.of.Funds.1 Funds.of.Funds.2
2007-01-31 0.0121 NA NA
2007-02-28 0.0096 0.01085 NA
2007-03-31 0.0096 0.00960 0.0313
2007-04-30 0.0163 0.01295 0.0355
2007-05-31 0.0204 0.01835 0.0463
2007-06-30 0.0082 0.01430 0.0449
2007-07-31 0.0041 0.00615 0.0327
2007-08-31 -0.0222 -0.00905 -0.0099
2007-09-30 0.0199 -0.00115 0.0018
2007-10-31 0.0303 0.02510 0.0280
2007-11-30 -0.0148 0.00775 0.0354
2007-12-31 0.0040 -0.00540 0.0195