今週も特にありません

進捗どうですか?

tidy時系列データに対する差分計算

以下の記事の通りで、差分計算することが多い方はすでにdplyr::lagを使っていると思います。ここでは、差分計算と変化率、対数収益率を計算する場合についてと、最近少し調べていたtsibbleの中に含まれる関数に関するメモになります。 notchained.hatenablog.com

変化率

tibbletimeパッケージに含まれているFacebookの株価データを利用します。

> library(tidyverse)
> library(tibbletime)
> 
> data(FB)
> FB
# A tibble: 1,008 x 8
   symbol date        open  high   low close    volume adjusted
   <chr>  <date>     <dbl> <dbl> <dbl> <dbl>     <dbl>    <dbl>
 1 FB     2013-01-02  27.4  28.2  27.4  28    69846400     28  
 2 FB     2013-01-03  27.9  28.5  27.6  27.8  63140600     27.8
 3 FB     2013-01-04  28.0  28.9  27.8  28.8  72715400     28.8
 4 FB     2013-01-07  28.7  29.8  28.6  29.4  83781800     29.4
 5 FB     2013-01-08  29.5  29.6  28.9  29.1  45871300     29.1
 6 FB     2013-01-09  29.7  30.6  29.5  30.6 104787700     30.6
 7 FB     2013-01-10  30.6  31.5  30.3  31.3  95316400     31.3
 8 FB     2013-01-11  31.3  32.0  31.1  31.7  89598000     31.7
 9 FB     2013-01-14  32.1  32.2  30.6  31.0  98892800     31.0
10 FB     2013-01-15  30.6  31.7  29.9  30.1 173242600     30.1
# … with 998 more rows

diffは差分計算できない最初の値を除いた値を返すため、mutateで追加しようとしてもエラーが出ます。

> FB %>%
+   select(symbol, date, adjusted) %>%
+   mutate(d = diff(adjusted))
 エラー: Column `d` must be length 1008 (the number of rows) or one, not 1007

dplyr::lagを用いることで差分と変化率は以下のように計算できます。

> FB %>%
+   select(symbol, date, adjusted) %>%
+   mutate(d = adjusted - lag(adjusted), 
+          cr = d / lag(adjusted) * 100)
# A tibble: 1,008 x 5
   symbol date       adjusted       d      cr
   <chr>  <date>        <dbl>   <dbl>   <dbl>
 1 FB     2013-01-02     28    NA      NA    
 2 FB     2013-01-03     27.8  -0.23   -0.821
 3 FB     2013-01-04     28.8   0.99    3.56 
 4 FB     2013-01-07     29.4   0.66    2.29 
 5 FB     2013-01-08     29.1  -0.360  -1.22 
 6 FB     2013-01-09     30.6   1.53    5.26 
 7 FB     2013-01-10     31.3   0.710   2.32 
 8 FB     2013-01-11     31.7   0.42    1.34 
 9 FB     2013-01-14     31.0  -0.770  -2.43 
10 FB     2013-01-15     30.1  -0.850  -2.75 
# … with 998 more rows

対数収益率

対数収益率については、diff(log(FB$adjusted))という感じで計算できるということが巷でよく書かれていますが、こちらも上記と同じ理由でmutateした場合にはエラーになります。

> FB %>%
+   select(symbol, date, adjusted) %>%
+   mutate(ld = diff(log(adjusted)))
 エラー: Column `ld` must be length 1008 (the number of rows) or one, not 1007

dplyr::lagを用いた場合には、多少冗長の感じもしますが、それぞれ対数をとった値の差分を計算することになります。

> FB %>%
+   select(symbol, date, adjusted) %>%
+   mutate(ld = log(adjusted) - log(lag(adjusted)))
# A tibble: 1,008 x 4
   symbol date       adjusted        ld
   <chr>  <date>        <dbl>     <dbl>
 1 FB     2013-01-02     28    NA      
 2 FB     2013-01-03     27.8  -0.00825
 3 FB     2013-01-04     28.8   0.0350 
 4 FB     2013-01-07     29.4   0.0227 
 5 FB     2013-01-08     29.1  -0.0123 
 6 FB     2013-01-09     30.6   0.0513 
 7 FB     2013-01-10     31.3   0.0229 
 8 FB     2013-01-11     31.7   0.0133 
 9 FB     2013-01-14     31.0  -0.0246 
10 FB     2013-01-15     30.1  -0.0278 
# … with 998 more rows

並び替え付きの差分計算

tsibbleパッケージにはdplyr::with_orderを利用したdifferenceという関数が定義されており、時系列で順序が並び替えられていないデータでも並び替えた上で差分計算ができます。

> library(tsibble)
>
> set.seed(12345)
> FB %<>%
+   select(symbol, date, adjusted) %>%
+   slice(sample(nrow(FB)))
> FB %>% 
+   mutate(d = difference(adjusted, order_by = date))
# A tibble: 1,008 x 4
   symbol date       adjusted       d
   <chr>  <date>        <dbl>   <dbl>
 1 FB     2015-11-18    108.   2.64  
 2 FB     2016-07-01    114.  -0.0900
 3 FB     2016-01-15     95.0 -3.40  
 4 FB     2016-07-15    117.  -0.43  
 5 FB     2014-10-27     80.3 -0.390 
 6 FB     2013-08-29     41.3  0.730 
 7 FB     2014-04-17     58.9 -0.780 
 8 FB     2015-01-09     77.7 -0.440 
 9 FB     2015-11-19    106.  -1.51  
10 FB     2016-12-02    115.   0.300 
# … with 998 more rows

結局、この後arrangeを使って並び替えて確認したりすることが多そうなので、あまり使う場面は限られるかもしれません。