dplyrを拡張してデータフレームっぽい俺俺クラスを動かす

みんな大好きデータフレームのハンドリング用ライブラリdplyrを拡張して、時系列データのxts型も同じように操作できるtplyrパッケージを作ろうと思ったんだが、よくよく考えるとdplyrままでいいんじゃないかなって思って辞めた。
その際に試行錯誤した残骸を忘れないようにここにまとめる。

ここでは、dplyrのfilter関数に対してxts型が動作するように拡張することを考えよう。
そのために、以下のように3つの関数を用意する。
内容はコメントにあるとおりxtsとdata.frameの変換関数とxtsに対する実際のfilter処理だ。

# xtsをdata.frameへと変換する関数
xts_to_df <- function(x)
{
  data.frame(index=zoo::index(x), zoo::coredata(x))
}
# data.frameをxtsへと変換する関数
df_to_xts <- function(df)
{
  xts(dplyr::select(df, -index), order.by=df$index)
}
# xts型に対するfilter処理を記述(S3クラスのメソッドとする)
filter_.xts <- function(.data, ..., .dots) {
  dots <- lazyeval::all_dots(.dots, ...)
  df <- xts_to_df(.data)
  df_to_xts(dplyr::filter_(df, .dots = dots))
}

そして、ここがミソだが、ここで作成したfilter_.xts関数を無理やりdplyrのnamespaceに突っ込む。
こうすることで、dplyrパッケージの中の処理において、xts型のfilter処理に対してこの関数を呼んでくれるようになる*1

environment(filter_.xts) <- asNamespace("dplyr")

さて、実際に動くかxtsパッケージにあるサンプルデータで確かめてみよう。

> library(xts)
> data(sample_matrix)
> # 適当なxtsデータへと変換
> samplexts <- as.xts(sample_matrix)
> # 内容の確認
> head(samplexts)
               Open     High      Low    Close
2007-01-02 50.03978 50.11778 49.95041 50.11778
2007-01-03 50.23050 50.42188 50.23050 50.39767
2007-01-04 50.42096 50.42096 50.26414 50.33236
2007-01-05 50.37347 50.37347 50.22103 50.33459
2007-01-06 50.24433 50.24433 50.11121 50.18112
2007-01-07 50.13211 50.21561 49.99185 49.99185
> # ちゃんと動いてるか確認
> dplyr::filter(samplexts, Close > 51)
               Open     High      Low    Close
2007-02-14 50.95283 51.04699 50.80317 51.04699
2007-02-15 51.06330 51.11401 50.94681 51.05185
2007-02-16 51.12879 51.12879 51.00613 51.02164
2007-02-17 50.97722 51.13653 50.95260 51.13653
2007-02-18 51.18414 51.32090 51.13713 51.15151
2007-02-19 51.29502 51.32342 51.13524 51.17899

・・・ちゃんとfilter処理できてる!やったぜ、親分!

*1:と思ったが、グローバル環境に定義してる分にはこれは不要で、パッケージ化してこれをやろうとすると必要になるんだった、失敬失敬。