zoo是時間序列的基礎庫,是面向通用的設計。 xts 是對時間序列庫(zoo) 的一種擴展實現。xts 類型繼承了zoo 類型,豐富了時間序列數據處理的函數。
一、xts對象的結構和定義
1、xts對象是一個具有時間索引的觀測值矩陣,結構如下:
? xts = matrix + times
2、創建xts對象,函數如下:
xts?(x= , ?order.by= , ?…? )
參數?? x :?數據,必須是一個向量或者矩陣;
order.by: 索引(index),是一個與x行數相同的升序排列的時間對象。
創建示例:
data <- rnorm(5)
dates <- seq(as.Date("2016-01-01"), length = 5, by = "days")
smith <- xts(x = data, order.by = dates)
3、屬性(Attr)
xts允許數據綁定任意鍵值屬性,可用來保存對象的元數據。創建xts對象時添加屬性,只需要將name=value參數傳送給xts()函數。
#使用 POSIXct日期類對象創建bday
bday <- as.POSIXct("1899-05-08")
# 創建xts對象,并新增born屬性
hayek <- xts(x = data, order.by = dates, born = bday)
4、分解xts對象
xts?和?zoo的核心是一個簡單的R矩陣和一些附加屬性,最重要的屬性是索引(?index)。索引包含了將數據作為時間序列的所有信息。
coredata()? ?獲取xts對象中的矩陣部分。
index()??? ??獲取xts對象的index部分。
5、轉換成xts對象
??as.xts()
6、xts與其他時間序列的主要區別
xts與R大部分其他時間序列對象的主要區別是:?xts可以使用表示時間的任何類,不管是POSIXct,?Date 還是其他類,xts將它們轉換成一種內部格式,使用戶盡可能自然地選取子集。
a <- xts(x = 1:2, as.Date("2012-01-01") + 0:1)
a[index(a)]
7、索引的屬性
查看索引的類別?indexClass()?
查看索引的時區?indexTZ()?
顯示或修改索引時間格式? ?indexFormat()?
# 修改時間表示格式
indexFormat(temps) <- "%m/%d/%Y"
tzone(), 用于提取或設置時區。
tzone(x) <- "Time_Zone"
?
Xts對象的索引的原始向量是自UNIX紀元(1970-01-01)以來的累計秒數的向量
.index()可獲取索引的原始向量。
以下函數用于提取類似于POSIXlt?類型的時間組件:
.indexday()
.indexmon()
.indexyear()
#創建一個周末日期索引
index <- which(.indexwday(temps) == 0 | .indexwday(temps) == 6)
?
二、輸入和輸出xts數據
1、實際應用中從硬盤或者網絡中讀取數據。
例如,硬盤中的tmp_file文件的內容如下:
a,b
1/02/2015, 1, 3
2/03/2015, 2, 4
輸入示例1:
# 讀取tmp_file文件
dat<-read.csv(tmp_file)
#將dat轉換成xts格式
xts(dat, order.by = as.Date(rownames(dat), "%m/%d/%Y"))
輸入示例2:
#使用read.zoo讀取tmp_file文件
dat_zoo <- read.zoo(tmp_file, index.column = 0, sep = ",", format = "%m/%d/%Y")
#將dat_zoo轉換成xts
dat_xts <- xts(dat_zoo)
輸入示例3:
# FUN = as.yearmon將時間字符串轉換成更合適的時間類。
sun <- read.zoo(tmp_file, sep = ",", FUN = as.yearmon)
# 轉換成xts對象
sun_xts<-xts(sun)
2、?輸出xts 對象
主要有兩種方式:
1、使用saveRDS() 和readRDS()?將單個R對象序列化。
2、使用?zoo中的函數?write.zoo()
#獲取臨時文件名
tmp <- tempfile()
#使用zoo將xts對象寫入tmp文件
write.zoo(data_xts, sep = ",", file = tmp)
?
三、查詢時間范圍
1、查詢日期范圍
Xts可快速有效地確定日期和時點范圍的子集,并提取相應的觀測值。
使用特殊字符和日期搭配就可提取xts對象的日期范圍。
A["20090825"]?????? ## 20090825
A["201203/201212"]????? ?## 201203至201212
A["/201601"]???????## 自 201601開始
2、提取每日時間間隔
# 選取所有日期9:30-16:00之間的觀測值
NYSE["T09:30/T16:00"]
3、觀測值的更新或替換
# 將dates向量中對應的觀測值設置為NA
x[dates] <- NA
# 自2016-06-09至今的觀測值修改為0
x["2016-06-09/"] <- 0
4、定位時間周期的開始和結束
last(temps, "1 week")
last(lastweek, 2)
first(lastweek, "-2 days")
?可以將first()和last()組合起來使用
#第1周的后3天
last(first(Temps, '1 week'), '3 days')
5、查看時間周期性和次數
periodicity()? 查看時間序列的周期
?ndays()?,?nmonths(),?nquarters() ?查看周期的次數
?
四、xts對象的合并運算
?xts?objects在做數學計算時,會遵循時間并且只返回有時間交集的數據。?
1、用merge按列合并xts
merge()將一個或多個序列按列合并。適用于按固定日期來規范觀測值。
merge(a, b, join = "right", fill = 9999)
3個關鍵參數:
?... :用于合并的任意個的對象
Join :規定如何合并序列,例如inner或left方式。
?Fill : 規定如何設置序列合并后出現的缺失值
2、用rbind按行合并xts
合并結果按時間升序排列
?
五、觀測值的NA值處理
1、前一個或下個觀測值結轉法
取缺失值的前一個觀測值來填補缺失值。可防止先窺偏差(look-ahead bias)
# 使用上個觀測值
na.locf(x)???????????????
#設置fromLast = TRUE,可使用下個觀測值填補空缺
na.locf(x, fromLast = TRUE)
2、使用 na.approx()插補缺值
na.approx()基于兩點之間的簡單線性插值,數據點使用索引值之間的距離來估算,估算值在時間上是線性的。
?
六、時間序列操作
1、偏移函數lag()
k是偏移的步長。在xts中,k為正,序列的觀測值將向下(時間后方)偏移;k為負,觀測值將向上偏移。Zoo與xts相反。
> a
?????????? [,1]
2016-01-01??? 1
2016-01-02??? 2
2016-01-03??? 3
> lag(a)
?????????? [,1]
2016-01-01?? NA
2016-01-02??? 1
2016-01-03??? 2
> lag(a,k=-1)
?????????? [,1]
2016-01-01??? 2
2016-01-02??? 3
2016-01-03??? NA
2、差分函數diff()
一個簡單的差分例如: ?x(t) - x(t-k)? 其中k是序列偏移的步長。高階差分是對每個之前的差分計算結果的重復應用。
diff(xtsdata, ?lag = , differences = )
參數說明:
?Lag:偏移數;
differences:差分的次序(例如:調用多少次?diff?)。
# 下面兩條指令的效果相同
diff(x, differences = 2)
diff(diff(x))
3、endpoints()函數,按時間間隔分割數據
endpoints(data,on=, k= )
該函數接收一個時間序列并返回每個時間區間的最后一個觀測值的位置向量。返回值以0開始,以數據長度(總行數)結束。
參數on?支持各種時間周期, 包括"years",?"quarters",?"months","hours"和?"minutes"等。
參數K用于找到第k個周期。例如,設置on = "weeks", k = 2, 可取每兩周的最后一天。注意最后一個返回值總是數據的長度,即便是與間隔周期不一致。
例如,下列代碼顯示某數據每年的最后一個觀測值
endpoints(Air, on = "years")
[1] 0 12 24 36 48 60 72 84 96 108 120 132 144
4、用period.apply按時間分割數據,并運算
period.apply(x, INDEX, FUN, ...)
使用舉例:
# 計算每周的端點
ep <- endpoints(temps, on = "weeks")
# 計算每周均值并顯示結果
period.apply(temps, INDEX = ep, FUN = mean)
5、用 split-lapply-rbind分割數據并運算
#按周來劃分數據,f參數是一個字符串,用于描述劃分的間隔(例如:"months",?"years")
data_weekly <- split(data, f = "weeks")
#創建一個每周均值的列表
temps_avg <- lapply(X = data_weekly, FUN = mean)
x_list_rbind <- do.call(rbind, temps_avg)
do.call(rbind, ...)
向rbind傳送一個list,而不是一次傳送一個對象。
6、單變量序列轉換成OHLC數據(Open-High-Low-Close data)
基于常規窗口整合不同頻次的序列可以使分析更容易。
to.period()函數格式如下,參數包括序列x, 表示周期的字符k等
to.period(x,
????????? period = "months",
????????? k = 1,
????????? indexAt,
????????? name=NULL,
????????? OHLC = TRUE,
????????? ...)
使用舉例:
usd_eur_weekly <- to.period(usd_eur, period = "weeks")
usd_eur_yearly <- to.period(usd_eur, period = "years", OHLC = FALSE)
7、轉換成低頻序列
?to.period()也可將序列轉換成低調整頻次的數據,類似于二次抽樣。
# 轉換成季度OHLC格式
mkt_quarterly <- to.period(eq_mkt, period = "quarters")
#使用快捷功能轉換成季度OHLC格式
mkt_quarterly2 <- to.quarterly(eq_mkt, name = "edhec_equity", indexAt = "firstof")
indexAt參數設置為firstof?,選取區間時間的起點。設置參數name可以改變每一列的基礎名。
8、計算時間序列的滾動標準差
時間序列數據的另一個常用需求是在數據的滾動窗口應用函數。
?xts?對象可使用zoo函數rollapply()來實行。
該函數參數有時間序列對象x,窗口大小width,應用于每個滾動周期的函數FUN。
Width參數規定了窗口中的觀測值數量。例如,選取一個序列的10天滾動。
rollapply(x, width = 10, FUN = max, na.rm = TRUE)
注意:如果是日觀測值的序列是選取10天,如果是月觀測值的序列會選取10個月。
?
七、修改時間戳
1、在高頻次數據中發現具有相同時間戳的觀測值時,一般有效的做法是強制時間唯一,增加毫秒隨機數。
make.index.unique(data,eps= ,? drop=? ,…)?
參數說明:
eps:epsilon or small change的縮寫,控制相同的時間被擾亂的程度。
drop = TRUE:移除全部重復觀測值。
舉例
make.index.unique(x, eps = 1e-4)? # ?增加隨機數
make.index.unique(x, drop = TRUE) # 去除重復項
?
2、?某些情形時間戳過于精確,最好是近似到一些固定的間隔點。例如觀測值可能在一小時內的任何時點發生,但只需記錄最近的下個整點。
以下一個時間對齊數據,秒,分鐘,小時。
align.time(data,n= )?? 參數n,表示要近似到的秒數
align.time(x, n = 60) # 近似到分鐘
?