[TOC] 翻譯自《Demo Week: Tidy Time Series Analysis with tibbletime》 原文鏈接:www.business science.io/code tools/2017/10/26/demo_week_tibbletime.html 註意:由於軟體包的 ...
目錄
翻譯自《Demo Week: Tidy Time Series Analysis with tibbletime》
原文鏈接:www.business-science.io/code-tools/2017/10/26/demo_week_tibbletime.html
註意:由於軟體包的版本變化,部分代碼被修改,文字有刪減
時間序列分析工具箱——tibbletime
tibbletime
的用途
- tidy 時間序列分析的未來:基於
tbl
的新類——tbl_time
,為tibble
對象添加時間軸,賦予處理時間的能力。 - 時間序列函數:為
tbl_time
對象專門設計的一系列函數,例如:filter_time()
:根據日期簡便快捷地過濾一個tbl_time
對象。as_period()
:轉換時間周期(例如月度變為年度),讓用戶能將數據聚合到低粒度水平上。time_collapse()
:當使用time_collapse
時,tbl_time
對象中落入相同周期的索引將被修改成相同的日期。rollify()
:修改一個函數,使其能夠在特定時間區間上計算一個或一組值。可以用來計算滾動均值,或其他tidyverse
框架下的滾動計算。create_series()
:根據規則時間序列,用簡化標記快速初始化一個帶有date
列tbl_time
對象。
載入包
tibbletime
目前還在活躍開發階段,可以用常規方法安裝,也可以藉助 devtools
從 github 上安裝最新開發版。
# Get tibbletime version with latest features
devtools::install_github("business-science/tibbletime")
安裝完成後,載入下麵的包:
tibbletime
:創建帶時間軸的tibble
對象,可以使用tbl_time
函數。tidyquant
:載入tidyverse
框架,用tq_get()
獲取數據。
# Load libraries
library(tibbletime) # Version: 0.1.1, Future of tidy time series analysis
library(tidyquant) # Loads tidyverse, tq_get()
數據
用 tq_get()
下載 FANG(臉書、亞馬遜、網飛、谷歌)每天的股票價格。
# Stock Prices from Yahoo! Finance
FANG_symbols <- c("FB", "AMZN", "NFLX", "GOOG")
FANG_tbl_d <- FANG_symbols %>%
tq_get(
get = "stock.prices",
from = "2014-01-01",
to = "2016-12-31")
FANG_tbl_d <- FANG_tbl_d %>%
group_by(symbol)
FANG_tbl_d
## # A tibble: 3,024 x 8
## # Groups: symbol [4]
## symbol date open high low close volume adjusted
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 FB 2014-01-02 54.83 55.22 54.19 54.71 43195500 54.71
## 2 FB 2014-01-03 55.02 55.65 54.53 54.56 38246200 54.56
## 3 FB 2014-01-06 54.42 57.26 54.05 57.20 68852600 57.20
## 4 FB 2014-01-07 57.70 58.55 57.22 57.92 77207400 57.92
## 5 FB 2014-01-08 57.60 58.41 57.23 58.23 56682400 58.23
## 6 FB 2014-01-09 58.65 58.96 56.65 57.22 92253300 57.22
## 7 FB 2014-01-10 57.13 58.30 57.06 57.94 42449500 57.94
## 8 FB 2014-01-13 57.91 58.25 55.38 55.91 63010900 55.91
## 9 FB 2014-01-14 56.46 57.78 56.10 57.74 37503600 57.74
## 10 FB 2014-01-15 57.98 58.57 57.27 57.60 33663400 57.60
## # ... with 3,014 more rows
我們設計了一個函數來按股票代碼分塊繪圖,可以在本文中重覆使用。沒有必要深究這些代碼,只要認識到我們正在創建一個 ggplot2
對象,它通過指定數據框、x、y 和 group(如果存在)等要素來創建根據“symbol”分塊的信息圖。
# Setup plotting function that can be reused later
ggplot_facet_by_symbol <- function(data,
mapping)
{
if (is.null(mapping$group))
{
# No groups
g <- data %>%
ggplot(
mapping = mapping) +
labs(x = quo_name(mapping$x),
y = quo_name(mapping$y))
}
else
{
# Deal with groups
g <- data %>%
ggplot(
mapping = mapping) +
labs(x = quo_name(mapping$x),
y = quo_name(mapping$y),
group = quo_name(mapping$group))
}
# Add faceting and theme
g <- g +
geom_line() +
facet_wrap(
~ symbol, ncol = 2, scales = "free_y") +
scale_color_tq() +
theme_tq()
return(g)
}
我們可以使用繪圖函數 ggplot_facet_by_symbol
快速可視化我們的數據。讓我們看一下“除權調整的”股票價格。
# Plot adjusted vs date
FANG_tbl_d %>%
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
labs(
title = "FANG Stocks: Adjusted Prices 2014 through 2016")
上圖所顯示就是我們要處理的數據,下麵讓我們進入 tibbletime
的教程。
教程:tibbletime
本教程將介紹下列函數的用法:
filter_time
:對時間索引的過濾as_period
:改變數據的周期rollify
:將任意函數轉換成為滾動函數
初始化一個 tbl_time
對象
在我們使用這些新函數之前,我們需要創建一個 tbl_time
對象。新類的操作幾乎與普通的 tibble
對象相同。然而,它會在背後自動跟蹤時間信息。
使用 as_tbl_time()
函數初始化對象。指定 index = date
,這告訴 tbl_time
對象要跟蹤哪個索引。
# Convert to tbl_time
FANG_tbl_time_d <- FANG_tbl_d %>%
as_tbl_time(index = date)
我們可以列印 tbl_time
對象。看起來幾乎與分組的 tibble
相同。請註意,“Index: date”通知我們“time tibble”已正確初始化。
# Show the tbl_time object we created
FANG_tbl_time_d
## # A time tibble: 3,024 x 8
## # Index: date
## # Groups: symbol [4]
## symbol date open high low close volume adjusted
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 FB 2014-01-02 54.83 55.22 54.19 54.71 43195500 54.71
## 2 FB 2014-01-03 55.02 55.65 54.53 54.56 38246200 54.56
## 3 FB 2014-01-06 54.42 57.26 54.05 57.20 68852600 57.20
## 4 FB 2014-01-07 57.70 58.55 57.22 57.92 77207400 57.92
## 5 FB 2014-01-08 57.60 58.41 57.23 58.23 56682400 58.23
## 6 FB 2014-01-09 58.65 58.96 56.65 57.22 92253300 57.22
## 7 FB 2014-01-10 57.13 58.30 57.06 57.94 42449500 57.94
## 8 FB 2014-01-13 57.91 58.25 55.38 55.91 63010900 55.91
## 9 FB 2014-01-14 56.46 57.78 56.10 57.74 37503600 57.74
## 10 FB 2014-01-15 57.98 58.57 57.27 57.60 33663400 57.60
## # ... with 3,014 more rows
我們可以使用繪圖函數 ggplot_facet_by_symbol()
繪製它,我們看到 tbl_time
對象與 tbl
對象的反應相同。
# Plot the tbl_time object
FANG_tbl_time_d %>%
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
labs(
title = "Working with tbltime: Reacts same as tbl class")
時間序列函數
讓我們看看可以用新的 tbl_time
對象做些什麼。
filter_time
filter_time()
函數根據按日期簡便快捷地過濾 tbl_time
對象,它使用一個函數格式(例如 'date_operator_start' ~ 'date_operator_end'
)。我們使用標準日期格式 YYYY-MM-DD + HH:MM:SS
指定日期運算符,但也有強大的簡化標記來更有效地指定日期子集。
假設我們想要過濾出 2014-06-01
和 2014-06-15
之間的所有觀察結果。我們可以使用函數標記 filter_time('2014-06-01' ~ '2014-06-15')
來完成。
# filter_time by day
FANG_tbl_time_d %>%
filter_time('2014-06-01' ~ '2014-06-15') %>%
# Plotting
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
geom_point() +
labs(
title = "Time Filter: Use functional notation to quickly subset by time",
subtitle = "2014-06-01 ~ 2014-06-15")
我們可以按月完成同樣的工作。假設我們只想在 2014 年 3 月進行觀察。使用簡化函數標記 ~ '2014-03'
。
# filter_time by month
FANG_tbl_time_d %>%
filter_time(~ '2014-03') %>%
# Plotting
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
geom_point() +
labs(
title = "Time Filter: Use shorthand for even easier subsetting",
subtitle = "~ 2014-03")
tbl_time
對象也響應括弧符號運算符——[
。在這裡,我們提取 2014 年所有日期的數據。
# time filter bracket [] notation
FANG_tbl_time_d[~ '2014'] %>%
# Plotting
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
labs(
title = "Time Filter: Bracket Notation Works Too",
subtitle = "FANG_tbl_time_d[~ 2014]")
filter_time()
有許多功能和簡化標記,感興趣的讀者可以查看 filter_time vignette 和 filter_time function documentation。
as_period
函數 as_period()
可以改變 tbl_time
對象的周期。與傳統方法相比,使用此方法有兩個優點:
- 函數標記非常靈活:
yearly == y == 1 y
- 函數標記提供了無數周期轉換的可能,例如:
15 d
:以 15 天為一周期2 m
:以 2 月為一周期4 m
:以 4 月為一周期6 m
:以半年為一周期
首先,讓我們做一個簡單的月度周期性變化。
# Convert from daily to monthly periodicity
FANG_tbl_time_d %>%
as_period(period = "month") %>%
# Plotting
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
labs(
title = "Periodicity Change from Daily to Monthly") +
geom_point()
讓我們提升一個檔次。那麼每兩個月一次呢? 只需使用函數標記 2 m
即可。
# Convert from daily to bi-monthly periodicity
FANG_tbl_time_d %>%
as_period(period = '2 m') %>%
# Plotting
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
labs(
title = "Periodicity Change to Daily to Bi-Monthly",
subtitle = "2~m") +
geom_point()
讓我們繼續。那麼每半年一次呢? 只需使用 6 m
即可。
# Convert from daily to bi-annually periodicity
FANG_tbl_time_d %>%
as_period(period = '6 m') %>%
# Plotting
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
labs(
title = "Periodicity Change to Daily to Bi-Annually",
subtitle = "6~m") +
geom_point()
函數標記幾乎提供了無限可能,感興趣的話可以查看 vignette on periodicity change with tibbletime。
rollify
rollify()
函數是一個副詞(tidyverse
中的一種特殊類型的函數,用於修改另一個函數)。rollify()
的作用是將任何函數轉換為自身的滾動版本。
# Rolling 60-day mean
roll_mean_60 <- rollify(
mean, window = 60)
FANG_tbl_time_d %>%
mutate(
mean_60 = roll_mean_60(adjusted)) %>%
select(-c(open:volume)) %>%
# Plot
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = adjusted, color = symbol)) +
geom_line(
aes(y = mean_60),
color = palette_light()[[6]]) +
labs(
title = "Rolling 60-Day Mean with rollify")
我們甚至可以做出更複雜的滾動功能,例如相關性。我們在 rollify()
中使用函數形式 .f = ~fun(.x,.y,...)
。
# Rolling correlation
roll_corr_60 <- rollify(
~ cor(.x, .y, use = "pairwise.complete.obs"),
window = 60)
FANG_tbl_time_d %>%
mutate(
cor_60 = roll_corr_60(
open, close)) %>%
select(-c(open:adjusted)) %>%
# Plot
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = cor_60, color = symbol)) +
labs(
title = "Rollify: 60-Day Rolling Correlation Between Open and Close Prices")
我們甚至可以返回多個結果。例如,我們可以創建滾動分位數。
首先,創建一個返回分位數的函數。
# Quantile tbl function
quantile_tbl <- function(x)
{
q <- quantile(x)
tibble(
quantile_name = names(q),
quantile_value = q)
}
# Test the function
quantile_tbl(1:100)
## # A tibble: 5 x 2
## quantile_name quantile_value
## <chr> <dbl>
## 1 0% 1.00
## 2 25% 25.75
## 3 50% 50.50
## 4 75% 75.25
## 5 100% 100.00
很好,它可以工作。接下來,使用 rollify
創建滾動版本。我們設置 unlist = FALSE
來返回列表列。
# Rollified quantile function
roll_quantile_60 <- rollify(
quantile_tbl, window = 60, unlist = FALSE)
接下來,在 mutate()
中應用滾動分位數函數來獲得滾動分位數。確保你已經用 select()
、filter()
和 unnest()
刪除了不必要的列,過濾了 NA
值,並展開列表列。現在每個日期有五個分位數值。
# Apply rolling quantile
FANG_quantile_60 <- FANG_tbl_time_d %>%
mutate(
rolling_quantile = roll_quantile_60(adjusted)) %>%
select(-c(open:adjusted)) %>%
filter(!is.na(rolling_quantile)) %>%
unnest()
FANG_quantile_60
## # A time tibble: 13,940 x 4
## # Index: date
## # Groups: symbol [4]
## symbol date quantile_name quantile_value
## * <chr> <date> <chr> <dbl>
## 1 FB 2014-03-28 0% 53.5300
## 2 FB 2014-03-28 25% 57.8750
## 3 FB 2014-03-28 50% 64.2100
## 4 FB 2014-03-28 75% 68.6275
## 5 FB 2014-03-28 100% 72.0300
## 6 FB 2014-03-31 0% 53.5300
## 7 FB 2014-03-31 25% 57.9350
## 8 FB 2014-03-31 50% 64.2100
## 9 FB 2014-03-31 75% 68.6275
## 10 FB 2014-03-31 100% 72.0300
## # ... with 13,930 more rows
最後,畫出結果。
FANG_quantile_60 %>%
ggplot_facet_by_symbol(
mapping = aes(
x = date, y = quantile_value,
color = symbol, group = quantile_name)) +
labs(
title = "Rollify: Create Rolling Quantiles")
如果想繼續探索 rollify
的用法,可以查看 vignette on rolling functions with rollify。