2020/03/30

R - 研究編 4 zoo パッケージ - 時系列のための拡張パッケージ

zoo パッケージは、時系列を扱うためのクラス zoo および zooreg とその操作のための関数群を提供するパッケージです。特に、不規則時系列 (観測値の間隔が一定ではない時系列) を取り扱うことを目的として設計されています。各種の仕様は、ts クラスや base パッケージにおける振舞いの自然な拡張となるよう配慮されており、それらに慣れている方はスムースに使い始めることができます。

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 に変換します (今回の例はこれです)。そうでない場合は通番が用いられます。
今回の例についてまとめると、以下のようになります。

  • 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