ff packageの使い方
仕事でffを使用する機会があったので忘れる前にメモしとく。
使い方は以下を参考にさせて頂いた。
一時ディレクトリの指定
RのffとbigmemoryとRevoScaleRとを比較してみたに
実体はテンポラリファイル内に大量に生成される
とあるようにデフォルトだと/tmp/Rtmp******とかいうディレクトリが都度作成される。
/配下に十分な空き領域がない場合は以下のコマンドでtmpディレクトリを変更する。
> options(fftempdir="/data/fftmp")
ファイルの読み込み
CSVファイルからffdfオブジェクトにデータを読み込むには次のようにする。
> air.ff <- read.csv.ffdf(file="2008.csv", header=TRUE)
factor型にしたい列は読み込みの段階でfactor化しちゃうこと
とあるのでFactor型の変数がある場合は注意する。
ffオブジェクトの保存と読み込み
RのffとbigmemoryとRevoScaleRとを比較してみたにはffsaveとffloadが紹介されているがsave.ffdfとload.ffdfもある。save.ffdfだと指定したディレクトリに列毎の*.ffファイルが作成される。
> save.ffdf(air.ff, dir="/data/ffdat/air2008")
読込むときは次のようにする。
> ls() [1] "air.ff" > rm(air.ff) > ls() character(0) > load.ffdf("/data/ffdat/air2008") > ls() [1] "air.ff"
save.ffdf/load.ffdfしか使っていないけど不安定なのでffsave/ffloadの方が良いかもしれない。
インデックスの取得と値の設定
欠損値を0埋めするような場合、通常のdata.frameだと
> air.df$ActualElapsedTime[is.na(air.df$ActualElapsedTime)] <- 0
のように書けば済むけどffdfだと次のようなエラーが発生する。
> air.ff$ActualElapsedTime[is.na(air.ff$ActualElapsedTime)] <- 0 Error: vmode(value) == v is not TRUE
これを避けるには条件を満たす行の数と同じ長さのffvectorを作成して代入する必要がある。(もっとスマートな方法があったらご教示ください)
> idx <- ffwhich(air.ff, is.na(ActualElapsedTime)) > air.ff$ActualElapsedTime[idx] <- ff(0, length=length(idx), vmode=vmode(air.ff$ActualElapsedTime))
オブジェクトのコピー
以下のようにload.ffdfで読込んだffdfオブジェクトから列を指定し別のオブジェクトを作成して保存すると、指定した列の*.ffファイルが元のディレクトリから消えてしまう。
> load.ffdf("/data/ffdat/air2008") > air.ff.glm <- ffdf( + Year=air.ff$Year, + Month=air.ff$Month, + DayOfWeek=air.ff$DayOfWeek, + UniqueCarrier=air.ff$UniqueCarrier, + CRSElapsedTime=air.ff$CRSElapsedTime, + Origin=air.ff$Origin, + Dest=air.ff$Dest, + Distance=air.ff$Distance, + Cancelled=air.ff$Cancelled) > save.ffdf(air.ff.glm, dir="/data/ffdat/air_glm2008")
これを避けるにはclone()を使用する。
> load.ffdf("/data/ffdat/air2008") > air.ff.glm <- ffdf( + Year=clone(air.ff$Year), + Month=clone(air.ff$Month), + DayOfWeek=clone(air.ff$DayOfWeek), + UniqueCarrier=clone(air.ff$UniqueCarrier), + CRSElapsedTime=clone(air.ff$CRSElapsedTime), + Origin=clone(air.ff$Origin), + Dest=clone(air.ff$Dest), + Distance=clone(air.ff$Distance), + Cancelled=clone(air.ff$Cancelled)) > save.ffdf(air.ff.glm, dir="/data/ffdat/air_glm2008")
変数の指定の仕方
dio.ffdf$xはff型で返ってくるから大丈夫
dio.ffdf[, 1]はオンメモリ(通常のvector)で返ってくるから爆死
とあるように同じ変数でも指定の仕方によって動作が異なる。hist()で痛い目みたのでメモしとく。
ff型でhist()
> air.hist <- hist(air.ff$ActualElapsedTime[!is.na(air.ff$ActualElapsedTime)]) > air.hist$breaks [1] 12.00 25.67 39.34 53.01 66.68 80.35 94.02 107.69 121.36 135.03 148.70 162.37 [13] 176.04 189.71 203.38 217.05 230.72 244.39 258.06 271.73 285.40 299.07 312.74 326.41 [25] 340.08 353.75 367.42 381.09 394.76 408.43 422.10 435.77 449.44 463.11 476.78 490.45 [37] 504.12 517.79 531.46 545.13 558.80 572.47 586.14 599.81 613.48 627.15 640.82 654.49 [49] 668.16 681.83 695.50 709.17 722.84 736.51 750.18 763.85 777.52 791.19 804.86 818.53 [61] 832.20 845.87 859.54 873.21 886.88 900.55 914.22 927.89 941.56 955.23 968.90 982.57 [73] 996.24 1009.91 1023.58 1037.25 1050.92 1064.59 1078.26 1091.93 1105.60 1119.27 1132.94 1146.61 [85] 1160.28 1173.95 1187.62 1201.29 1214.96 1228.63 1242.30 1255.97 1269.64 1283.31 1296.98 1310.65 [97] 1324.32 1337.99 1351.66 1365.33 1379.00
区間配列が細かく小数になってる。かつ欠損があるとエラーになる。
vectorでhist()
> which(names(air.ff)=="ActualElapsedTime") [1] 12 > air.hist <- hist(air.ff[, 12]) > air.hist$breaks [1] 0 50 100 150 200 250 300 350 400 450 500 550 600 650 700 750 800 850 900 950 [21] 1000 1050 1100 1150 1200 1250 1300 1350 1400
こちらはdata.frameで実行するのと変わらない。欠損があってもエラーにならない。