zoo パッケージのインストール・読み込み
zoo パッケージは install.packages() を使って簡単にインストールできます。> install.packages('zoo')
--- このセッションで使うために、CRAN のミラーサイトを選んでください --- Secure CRAN mirrors 1: 0-Cloud [https] 2: Australia (Canberra) [https] 3: Australia (Melbourne 1) [https] 4: Australia (Melbourne 2) [https] 5: Australia (Perth) [https] 6: Austria [https] 7: Belgium (Ghent) [https] 8: Brazil (BA) [https] 9: Brazil (PR) [https] 10: Brazil (RJ) [https] 11: Brazil (SP 1) [https] 12: Brazil (SP 2) [https] 13: Bulgaria [https] 14: China (Hong Kong) [https] 15: China (Guangzhou) [https] 16: China (Lanzhou) [https] 17: China (Shanghai) [https] 18: Costa Rica [https] 19: Denmark [https] 20: East Asia [https] 21: Ecuador (Cuenca) [https] 22: Ecuador (Quito) [https] 23: France (Lyon 1) [https] 24: France (Lyon 2) [https] 25: France (Marseille) [https] 26: Germany (Erlangen) [https] 27: Germany (Münster) [https] 28: Germany (Regensburg) [https] 29: Greece [https] 30: Hungary [https] 31: Iceland [https] 32: Indonesia (Jakarta) [https] 33: Italy (Padua) [https] 34: Japan (Tokyo) [https] 35: Korea (Gyeongsan-si) [https] 36: Korea (Seoul 1) [https] 37: Korea (Ulsan) [https] 38: Mexico (Mexico City) [https] 39: Morocco [https] 40: Norway [https] 41: Philippines [https] 42: Russia [https] 43: Spain (A Coruña) [https] 44: Sweden [https] 45: Switzerland [https] 46: Taiwan (Taipei) [https] 47: Turkey (Mersin) [https] 48: UK (Bristol) [https] 49: UK (London 1) [https] 50: USA (IA) [https] 51: USA (KS) [https] 52: USA (MI 1) [https] 53: USA (MI 2) [https] 54: USA (OH) [https] 55: USA (OR) [https] 56: USA (TN) [https] 57: USA (TX 1) [https] 58: Uruguay [https] 59: (other mirrors) Selection: 34 URL 'https://cran.ism.ac.jp/src/contrib/zoo_1.8-7.tar.gz' を試しています Content type 'application/x-gzip' length 861309 bytes (841 KB) ================================================== downloaded 841 KB * installing *source* package ‘zoo’ ... ** パッケージ ‘zoo’ の解凍および MD5 サムの検証に成功しました ** using staged installation ** libs clang -I"/usr/local/Cellar/r/3.6.3_1/lib/R/include" -DNDEBUG -I../inst/include -I/usr/local/opt/gettext/include -I/usr/local/opt/readline/include -I/usr/local/include -fPIC -g -O2 -c coredata.c -o coredata.o clang -I"/usr/local/Cellar/r/3.6.3_1/lib/R/include" -DNDEBUG -I../inst/include -I/usr/local/opt/gettext/include -I/usr/local/opt/readline/include -I/usr/local/include -fPIC -g -O2 -c init.c -o init.o clang -I"/usr/local/Cellar/r/3.6.3_1/lib/R/include" -DNDEBUG -I../inst/include -I/usr/local/opt/gettext/include -I/usr/local/opt/readline/include -I/usr/local/include -fPIC -g -O2 -c lag.c -o lag.o clang -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/usr/local/Cellar/r/3.6.3_1/lib/R/lib -L/usr/local/opt/gettext/lib -L/usr/local/opt/readline/lib -L/usr/local/lib -o zoo.so coredata.o init.o lag.o -L/usr/local/Cellar/r/3.6.3_1/lib/R/lib -lR -lintl -Wl,-framework -Wl,CoreFoundation installing to /usr/local/Cellar/r/3.6.3_1/lib/R/library/00LOCK-zoo/00new/zoo/libs ** R ** demo ** inst ** byte-compile and prepare package for lazy loading ** help *** installing help indices ** building package indices ** installing vignettes ** testing if installed package can be loaded from temporary location ** checking absolute paths in shared objects and dynamic libraries ** testing if installed package can be loaded from final location ** testing if installed package keeps a record of temporary installation path * DONE (zoo) ダウンロードされたパッケージは、以下にあります ‘/private/var/folders/wn/cpm4w94s1474b7cvvj2rmd600000gn/T/RtmpgMaHkf/downloaded_packages’ '.Library' 中のパッケージの HTML 索引を更新します Making 'packages.html' ... 完了
インストールできたら、require() で読み込めば、使い始めることができます。
> require(zoo) 要求されたパッケージ zoo をロード中です 次のパッケージを付け加えます: ‘zoo’ 以下のオブジェクトは ‘package:base’ からマスクされています: as.Date, as.Date.numeric
zoo オブジェクトの作り方
zoo パッケージを使うには、データから zoo オブジェクトを生成する必要があります。生成関数 zoo() を用いて、ベクトル、行列、データフレームから生成する方法 (ts() と類似) と、read.zoo() を用いてファイルから読み込む方法 (read.table() と類似) があります。zoo クラスは不規則時系列を前提としていますが、ts クラスのような規則時系列 (等間隔の時系列) 向けに、zooreg クラスも用意されています。こちらは zooreg() で生成するか、reed.zoo() の regular パラメータを TRUE にして読み込みます。
CSV ファイルから zoo オブジェクトを作る
read.zoo() で CSV ファイルを読み込んで zoo オブジェクトを作る例を見てみましょう。以下のような CSV ファイル USDJPY60.csv を読み込んでみます。米ドル円の時間足の四本値データです。時刻は東京時間になっています。為替市場は東京の土曜日の朝で終わり、月曜日の朝から再開しますので、2013-01-19 06:00 から 2013-01-21 07:00 にデータが飛んでいます。このようなデータは、ts クラスでは取扱いが難しくなります。2013-01-17 23:00,89.40,89.45,89.24,89.39 2013-01-18 00:00,89.39,89.41,89.22,89.40 2013-01-18 01:00,89.40,89.54,89.39,89.41 2013-01-18 02:00,89.41,89.90,89.41,89.70 2013-01-18 03:00,89.70,89.89,89.70,89.83 2013-01-18 04:00,89.83,90.12,89.78,90.03 2013-01-18 05:00,90.03,90.05,89.80,89.85 2013-01-18 06:00,89.85,89.97,89.82,89.85 2013-01-18 07:00,89.87,89.97,89.80,89.95 2013-01-18 08:00,89.95,90.09,89.80,89.81 2013-01-18 09:00,89.81,90.01,89.80,89.84 2013-01-18 10:00,89.84,89.95,89.63,89.83 2013-01-18 11:00,89.83,89.90,89.71,89.82 2013-01-18 12:00,89.82,89.98,89.80,89.97 2013-01-18 13:00,89.97,90.20,89.82,89.97 2013-01-18 14:00,89.97,90.07,89.82,89.99 2013-01-18 15:00,89.99,90.15,89.97,90.14 2013-01-18 16:00,90.14,90.14,89.98,90.02 2013-01-18 17:00,90.02,90.09,89.90,89.95 2013-01-18 18:00,89.95,89.98,89.68,89.90 2013-01-18 19:00,89.90,89.91,89.73,89.85 2013-01-18 20:00,89.86,89.86,89.74,89.81 2013-01-18 21:00,89.81,90.05,89.77,89.88 2013-01-18 22:00,89.88,89.99,89.83,89.93 2013-01-18 23:00,89.93,90.01,89.88,89.96 2013-01-19 00:00,89.96,89.96,89.76,89.93 2013-01-19 01:00,89.93,89.96,89.85,89.89 2013-01-19 02:00,89.89,90.08,89.87,90.02 2013-01-19 03:00,90.02,90.06,89.95,90.00 2013-01-19 04:00,89.99,90.03,89.94,90.03 2013-01-19 05:00,90.03,90.10,90.00,90.04 2013-01-19 06:00,90.04,90.11,89.99,90.02 2013-01-21 07:00,90.09,90.24,90.08,90.15 2013-01-21 08:00,90.15,90.23,90.12,90.17 2013-01-21 09:00,90.18,90.18,89.75,89.83 2013-01-21 10:00,89.83,89.86,89.42,89.56 2013-01-21 11:00,89.56,89.71,89.56,89.70
read.zoo() での読み込みは、以下のように行います。
> usdjpy60 <- read.zoo("USDJPY60.csv", sep=",", format="%Y-%m-%d %H:%M", tz="", col.names=c(NA, "open", "high", "low", "close"))
read.zoo() は read.table() のラッパーなので、多くの引数はそのまま read.table() に渡り、同様の振舞いをします。sep, col.names はそれに該当します。
zoo クラスは、データの間隔が不均一であることを前提としていますので、ts のように start と frequency ではデータの示す時刻位置が表現できません。そのため zoo クラスは時刻のインデックスを持っています。インデックスには Date クラス、POSIXct クラス、あるいは単なる数値が用いられます。read.zoo() で生成する場合は、第1カラムがインデックスを定めるカラムになります (index.column パラメータで変更することもでき、0 にすれば row.names() を使わせることもできます)。インデックスカラムの書式は format パラメータに従います。format のみ指定されている場合は、それを使って Date に変換します。format と tz が指定されると POSIXct に変換します (今回の例はこれです)。そうでない場合は通番が用いられます。
今回の例についてまとめると、以下のようになります。
zoo クラスは、データの間隔が不均一であることを前提としていますので、ts のように start と frequency ではデータの示す時刻位置が表現できません。そのため zoo クラスは時刻のインデックスを持っています。インデックスには Date クラス、POSIXct クラス、あるいは単なる数値が用いられます。read.zoo() で生成する場合は、第1カラムがインデックスを定めるカラムになります (index.column パラメータで変更することもでき、0 にすれば row.names() を使わせることもできます)。インデックスカラムの書式は format パラメータに従います。format のみ指定されている場合は、それを使って Date に変換します。format と tz が指定されると POSIXct に変換します (今回の例はこれです)。そうでない場合は通番が用いられます。
今回の例についてまとめると、以下のようになります。
- USDJPY60.csv を読み込む
- カラムはカンマ区切りで認識する
- インデックスの形式は %Y-%m-%d %H:%M で、POSIXct で保持する
- カラム名は open, high, low, close
読み込まれたデータを表示すると次のようになります。
> usdjpy60 open high low close 2013-01-17 23:00:00 89.40 89.45 89.24 89.39 2013-01-18 00:00:00 89.39 89.41 89.22 89.40 2013-01-18 01:00:00 89.40 89.54 89.39 89.41 2013-01-18 02:00:00 89.41 89.90 89.41 89.70 2013-01-18 03:00:00 89.70 89.89 89.70 89.83 2013-01-18 04:00:00 89.83 90.12 89.78 90.03 2013-01-18 05:00:00 90.03 90.05 89.80 89.85 2013-01-18 06:00:00 89.85 89.97 89.82 89.85 2013-01-18 07:00:00 89.87 89.97 89.80 89.95 2013-01-18 08:00:00 89.95 90.09 89.80 89.81 2013-01-18 09:00:00 89.81 90.01 89.80 89.84 2013-01-18 10:00:00 89.84 89.95 89.63 89.83 2013-01-18 11:00:00 89.83 89.90 89.71 89.82 2013-01-18 12:00:00 89.82 89.98 89.80 89.97 2013-01-18 13:00:00 89.97 90.20 89.82 89.97 2013-01-18 14:00:00 89.97 90.07 89.82 89.99 2013-01-18 15:00:00 89.99 90.15 89.97 90.14 2013-01-18 16:00:00 90.14 90.14 89.98 90.02 2013-01-18 17:00:00 90.02 90.09 89.90 89.95 2013-01-18 18:00:00 89.95 89.98 89.68 89.90 2013-01-18 19:00:00 89.90 89.91 89.73 89.85 2013-01-18 20:00:00 89.86 89.86 89.74 89.81 2013-01-18 21:00:00 89.81 90.05 89.77 89.88 2013-01-18 22:00:00 89.88 89.99 89.83 89.93 2013-01-18 23:00:00 89.93 90.01 89.88 89.96 2013-01-19 00:00:00 89.96 89.96 89.76 89.93 2013-01-19 01:00:00 89.93 89.96 89.85 89.89 2013-01-19 02:00:00 89.89 90.08 89.87 90.02 2013-01-19 03:00:00 90.02 90.06 89.95 90.00 2013-01-19 04:00:00 89.99 90.03 89.94 90.03 2013-01-19 05:00:00 90.03 90.10 90.00 90.04 2013-01-19 06:00:00 90.04 90.11 89.99 90.02 2013-01-21 07:00:00 90.09 90.24 90.08 90.15 2013-01-21 08:00:00 90.15 90.23 90.12 90.17 2013-01-21 09:00:00 90.18 90.18 89.75 89.83 2013-01-21 10:00:00 89.83 89.86 89.42 89.56 2013-01-21 11:00:00 89.56 89.71 89.56 89.70
その他の作り方
メモリ上のデータフレーム等から zoo オブジェクトを構成するには zoo() を使います。order.by パラメータによりインデックスに用いる値を直接指定できるので、read.zoo() で対応できないようなインデックスを用いたい場合は、read.table() でデータフレームを構築した後、zoo() で zoo オブジェクト化すると良いでしょう。zoo オブジェクトの内部構造
R のオブジェクトは、内部構造を知っていた方が扱いやすいので、見ておきましょう。まず、unclass() してみます。> unclass(usdjpy60) open high low close [1,] 89.40 89.45 89.24 89.39 [2,] 89.39 89.41 89.22 89.40 [3,] 89.40 89.54 89.39 89.41 [4,] 89.41 89.90 89.41 89.70 [5,] 89.70 89.89 89.70 89.83 [6,] 89.83 90.12 89.78 90.03 [7,] 90.03 90.05 89.80 89.85 [8,] 89.85 89.97 89.82 89.85 [9,] 89.87 89.97 89.80 89.95 [10,] 89.95 90.09 89.80 89.81 [11,] 89.81 90.01 89.80 89.84 [12,] 89.84 89.95 89.63 89.83 [13,] 89.83 89.90 89.71 89.82 [14,] 89.82 89.98 89.80 89.97 [15,] 89.97 90.20 89.82 89.97 [16,] 89.97 90.07 89.82 89.99 [17,] 89.99 90.15 89.97 90.14 [18,] 90.14 90.14 89.98 90.02 [19,] 90.02 90.09 89.90 89.95 [20,] 89.95 89.98 89.68 89.90 [21,] 89.90 89.91 89.73 89.85 [22,] 89.86 89.86 89.74 89.81 [23,] 89.81 90.05 89.77 89.88 [24,] 89.88 89.99 89.83 89.93 [25,] 89.93 90.01 89.88 89.96 [26,] 89.96 89.96 89.76 89.93 [27,] 89.93 89.96 89.85 89.89 [28,] 89.89 90.08 89.87 90.02 [29,] 90.02 90.06 89.95 90.00 [30,] 89.99 90.03 89.94 90.03 [31,] 90.03 90.10 90.00 90.04 [32,] 90.04 90.11 89.99 90.02 [33,] 90.09 90.24 90.08 90.15 [34,] 90.15 90.23 90.12 90.17 [35,] 90.18 90.18 89.75 89.83 [36,] 89.83 89.86 89.42 89.56 [37,] 89.56 89.71 89.56 89.70 attr(,"index") [1] "2013-01-17 23:00:00 JST" "2013-01-18 00:00:00 JST" [3] "2013-01-18 01:00:00 JST" "2013-01-18 02:00:00 JST" [5] "2013-01-18 03:00:00 JST" "2013-01-18 04:00:00 JST" [7] "2013-01-18 05:00:00 JST" "2013-01-18 06:00:00 JST" [9] "2013-01-18 07:00:00 JST" "2013-01-18 08:00:00 JST" [11] "2013-01-18 09:00:00 JST" "2013-01-18 10:00:00 JST" [13] "2013-01-18 11:00:00 JST" "2013-01-18 12:00:00 JST" [15] "2013-01-18 13:00:00 JST" "2013-01-18 14:00:00 JST" [17] "2013-01-18 15:00:00 JST" "2013-01-18 16:00:00 JST" [19] "2013-01-18 17:00:00 JST" "2013-01-18 18:00:00 JST" [21] "2013-01-18 19:00:00 JST" "2013-01-18 20:00:00 JST" [23] "2013-01-18 21:00:00 JST" "2013-01-18 22:00:00 JST" [25] "2013-01-18 23:00:00 JST" "2013-01-19 00:00:00 JST" [27] "2013-01-19 01:00:00 JST" "2013-01-19 02:00:00 JST" [29] "2013-01-19 03:00:00 JST" "2013-01-19 04:00:00 JST" [31] "2013-01-19 05:00:00 JST" "2013-01-19 06:00:00 JST" [33] "2013-01-21 07:00:00 JST" "2013-01-21 08:00:00 JST" [35] "2013-01-21 09:00:00 JST" "2013-01-21 10:00:00 JST" [37] "2013-01-21 11:00:00 JST"
本体は、2次元の行列です。列名は dimnames[[2]] に入っています。時刻のインデックスは index というアトリビュートに格納されています。index() で取り出すことができます。index の中身は POSIXct のベクトルです。
> class(index(usdjpy60)) [1] "POSIXct" "POSIXt"
時刻情報へのアクセス
zoo クラスは ts クラスと同様の仕様の time(), start(), end(), cycle(), frequency() を持っています。time() は index() と同じです。cycle(), frequency() は、規則時系列で frequency 属性を持っている zooreg クラスについては ts クラス同様、frequency を基に挙動します。一般の zoo クラス (不規則時系列) の場合は、インデックスを数値化して階差をとり、その最大公約数を frequency とみなして処理してくれます。> frequency(usdjpy60) [1] 0.0002777778 > 1/frequency(usdjpy60) [1] 3600
例えば前述の usdjpy60 は、1時間周期のデータです。インデックスは POSIXct なので、秒単位を想定していますから、frequency は 1/3600=0.000277... となります。
データ操作
coredata() で、zoo オブジェクトからデータ部分 (ベクトルまたは行列) を取り出すことができます。2つの zoo オブジェクトの結合、共通部分を求めるには merge() を用います。merge(..., all = FALSE) は ts.intersect() 相当、merge(..., all = TRUE) は ts.union() 相当です (all の既定値は TRUE なので ts.union() 相当の動作になります)。
c(), cbind(), rbind() も zoo 用のオーバーライドが提供されているため、ベクトルや行列のように取り扱うことができます。
時系列の切り出しは、ts と同様 window() を使うことができます。
> window(usdjpy60, start=as.POSIXct("2013-01-19 01:00:00"), end=as.POSIXct("2013-01-19 05:00:00")) open high low close 2013-01-19 01:00:00 89.93 89.96 89.85 89.89 2013-01-19 02:00:00 89.89 90.08 89.87 90.02 2013-01-19 03:00:00 90.02 90.06 89.95 90.00 2013-01-19 04:00:00 89.99 90.03 89.94 90.03 2013-01-19 05:00:00 90.03 90.10 90.00 90.04
また、zoo では演算子 [、[<- のオーバーライドが行われており、インデックス値による行の取り出しが可能になっています。
> usdjpy60[c(as.POSIXct("2013-01-19 03:00:00"), as.POSIXct("2013-01-19 05:00:00"))] open high low close 2013-01-19 03:00:00 90.02 90.06 89.95 90.00 2013-01-19 05:00:00 90.03 90.10 90.00 90.04
集計
rollmean(x, k) は時系列 x に対して k 個の移動平均をとる関数です。タイムスタンプは中央値 (端数切り捨て) が使われます。タイムスタンプを最大値にするには rollmeanr() を用いるか、rollmean() にパラメータ align="right" をつけます。align="left" で最小値を採用することもできます。rollmean() に類似の関数として、rollmax, rollmedian, rollsum と各々の *r も用意されています。
汎用のローリング集計関数として、rollapply(), rollapplyr() もあり、任意の関数での集計が行えます。
ts, data.frame と同様、aggregate(), by() を用いた集計も可能です。
グラフィックス
zoo クラスの plot() はオーバーライドされています。列ごとの折れ線グラフが描画されます。> plot(usdjpy60)
plot.type="single" とすることで、各列を重ねて描画することもできます。col パラメータで色を指定できます。
> plot(usdjpy60, plot.type="single", col = c("red", "blue", "green", "black"))
欠損値の処理
時系列データの取扱いで重要なのが、欠損値の処理です。zoo オブジェクトに対する欠損値の処理方法を見てみます。欠損値のある新しいサンプルデータ USDJPYtick.csv を用意しました。米ドル円のティックデータです。ティックデータは bid (買値) と ask (売値) があり、更新のあった方のデータだけが含まれていることが一般的です。そのため、bid と ask のうち更新の無かった方が欠損値になっています。2013-01-08 00:00:00.174000,92.034,92.037 2013-01-08 00:00:00.427000,,92.038 2013-01-08 00:00:00.678000,92.035, 2013-01-08 00:00:00.931000,92.034, 2013-01-08 00:00:01.435000,92.033,92.036
次のように読み込みます。最初に実行している options() は、秒を小数点以下3桁 (ミリ秒) まで表示するという設定です。欠損値の箇所は NA として読み込まれました。
> options(digits.secs=3) > tick <- ask="" bid="" col.names="c(NA," format="%Y-%m-%d %H:%M:%OS" read.zoo="" sep="," tick.csv="" tz=""> tick bid ask 2013-01-08 00:00:00.174 92.034 92.037 2013-01-08 00:00:00.427 NA 92.038 2013-01-08 00:00:00.677 92.035 NA 2013-01-08 00:00:00.930 92.034 NA 2013-01-08 00:00:01.434 92.033 92.036 ->
ティックデータの場合は NA の箇所は値が変化していないことを意味しています。したがって、直近の値で補間するのが妥当です。このような場合は na.locf() を用います。locf は last observation carried forward のことで、最後の観測値を前へ持ち越す、という意味です。
> na.locf(tick) bid ask 2013-01-08 00:00:00.174 92.034 92.037 2013-01-08 00:00:00.427 92.034 92.038 2013-01-08 00:00:00.677 92.035 92.038 2013-01-08 00:00:00.930 92.034 92.038 2013-01-08 00:00:01.434 92.033 92.036
ティックデータ向きではありませんが、他の処理方法も見てみます。
na.fill() は、先頭、中間、終端の3箇所について異なる値を補間する関数です。na.fill(x, fill) の fill パラメータに3要素のリストを渡すことで補間方法を指示します。fill の第1要素が先頭、第2要素が中間、第3要素が終端の補間値を意味します。NA は補完しない、NULL はその行を抹消、"extend" は先頭、終端であれば、NA ではない値をそのまま延長、中間であれば線形補間を行います。それ以外の値を指定すると、その値をそのまま入れます。
> na.fill(tick, "extend") bid ask 2013-01-08 00:00:00.174 92.0340 92.03700 2013-01-08 00:00:00.427 92.0345 92.03800 2013-01-08 00:00:00.677 92.0350 92.03733 2013-01-08 00:00:00.930 92.0340 92.03667 2013-01-08 00:00:01.434 92.0330 92.03600
na.aggregate() は、集計値に基づく補間を行います。既定であれば、全体の平均値を使って補間します。by パラメータに各観測値のグループを指定するベクトルを渡せば、同じグループ内での集計値で補間します。by には関数も渡すことができ、time() の値を関数に渡したときの戻り値でグループ化を行います。FUN パラメータには集計を行う関数を指定できます。既定値では mean になっているため、全体の平均値での補間が行われます。
> na.aggregate(tick) bid ask 2013-01-08 00:00:00.174 92.034 92.037 2013-01-08 00:00:00.427 92.034 92.038 2013-01-08 00:00:00.677 92.035 92.037 2013-01-08 00:00:00.930 92.034 92.037 2013-01-08 00:00:01.434 92.033 92.036
線形に補間するには、na.approx() を用います。同様に na.spline() はスプライン補間を行います。
> na.approx(tick) bid ask 2013-01-08 00:00:00.174 92.0340 92.0370 2013-01-08 00:00:00.427 92.0345 92.0380 2013-01-08 00:00:00.677 92.0350 92.0375 2013-01-08 00:00:00.930 92.0340 92.0370 2013-01-08 00:00:01.434 92.0330 92.0360 > na.spline(tick) bid ask 2013-01-08 00:00:00.174 92.03400 92.0370 2013-01-08 00:00:00.427 92.03527 92.0380 2013-01-08 00:00:00.677 92.03500 92.0384 2013-01-08 00:00:00.930 92.03400 92.0382 2013-01-08 00:00:01.434 92.03300 92.0360