data.table

[追記] 別の選択肢としてHadley Wickhamの readr もお薦めです。現時点では data.table のほうが少し速いようです。

data.tableとは?

data.table は従来の data.frame に代わるデータ型を提供するパッケージです。効率が良く,巨大なCSVファイルの読み込みが桁違いに速くなります。

インストールとライブラリの読み込みは想定通りです:

install.packages("data.table")
library(data.table)

データの読み込み

data.frame の読み込みは read.csv() などのいくつかの関数で行いましたが,data.table の読み込みは fread() だけです。

data = fread("ファイル名またはURL")

CSVかTSVか,ヘッダがあるかないかは,たいてい自動判断してくれます。もしうまくいかなかったら,オプションで指定します。

data = fread("ファイル名またはURL", sep=",", header=TRUE, na.strings=c("NA",""))

ただし,文字コードだけは設定できないようです。Mac上ではUTF-8しか扱ってくれませんでした。また,na.strings=c("","欠測値") のようなUTF-8文字列を与えても無視されるようです。

Sys.setlocale(category="LC_ALL", locale="ja_JP.SJIS") してみましたが,読み込み方は変わったものの,文字化けして表示されるだけのようです。

また,開発途上のためか高速化のためか,CSVはRFC 4180準拠ではなく,ダブルクォートが入り子になっているとうまくいきません。

おもしろい使い方として,data = fread(" まで打ってから,データをRコンソールにコピペし,") を打ち込むという方法も使えます。例えば

data = fread("魔,方,陣
2,9,4
7,5,3
6,1,8")

または

data = fread("
魔,方,陣
2,9,4
7,5,3
6,1,8
")

のような感じです。これで data と打ち込むと

   魔 方 陣
1:  2  9  4
2:  7  5  3
3:  6  1  8

と表示されます。

現実的な例でやってみましょう。RgoogleMapsを使った放射線地図で使った福島県の放射線データ fukushima.csv は,422656地点の緯度(lat),経度(lon),放射線(radiation,μSv/h単位),日時(datetime)を収めたものです。これをローカルにダウンロードして,読み込んで,それぞれの欄の平均値を表示し,時間を計測してみましょう。

> # 従来のdata.frame版
> system.time({df = read.csv("~/public_html/stat/data/fukushima.csv", as.is=TRUE)})
   ユーザ   システム       経過  
     7.129      0.120      7.686 
> system.time(print(mean(df$lat)))
[1] 37.59176
   ユーザ   システム       経過  
     0.004      0.000      0.004 
> system.time(print(mean(df$lon)))
[1] 140.4282
   ユーザ   システム       経過  
     0.005      0.000      0.004 
> system.time(print(mean(as.POSIXct(df$datetime))))
[1] "2011-07-18 01:52:49 JST"
   ユーザ   システム       経過  
    62.599      6.351     69.457 
> 
> # 新しいdata.table版
> system.time({dt = fread("~/public_html/stat/data/fukushima.csv")})
   ユーザ   システム       経過  
     0.479      0.018      1.119 
> system.time(print(mean(dt$lat)))
[1] 37.59176
   ユーザ   システム       経過  
     0.004      0.000      0.005 
> system.time(print(mean(dt$lon)))
[1] 140.4282
   ユーザ   システム       経過  
     0.004      0.000      0.005 
> system.time(print(mean(as.POSIXct(dt$datetime))))
[1] "2011-07-18 01:52:49 JST"
   ユーザ   システム       経過  
    62.892      6.842     71.122 

読み込みは劇的に早くなりました。他の計算はあまり変わりません。ただ,この場合は,日時を表す文字列を内部形式に変換する as.POSIXct() が遅すぎてどうにもなりません。

これを改善するには fasttime パッケージを使います。これはまだCRANに入っていないので,次のようにしてRForge.netからインストールします。

install.packages("fasttime", repos="http://rforge.net")

これが失敗するならソースを取得してビルドします:

install.packages("fasttime", repos="http://rforge.net", type="source")

試してみましょう。

> library(fasttime)
> 
> system.time(print(mean(fastPOSIXct(df$datetime))))
[1] "2011-07-18 10:52:49 JST"
   ユーザ   システム       経過  
     0.044      0.000      0.045 
> system.time(print(mean(fastPOSIXct(dt$datetime))))
[1] "2011-07-18 10:52:49 JST"
   ユーザ   システム       経過  
     0.045      0.001      0.046 

3桁高速化できました! すごいですね! でも答えが違ってますね。実は fasttime は変換元の文字列はGMTにしか対応していないので,JSTなら 9*3600 を引く必要があります。

> mean(fastPOSIXct(dt$datetime)) - 9*3600
[1] "2011-07-18 01:52:49 JST"

data.table の fread() と fasttime の fastPOSIXct() で劇的に高速化できることがおわかりいただけたでしょうか。

まだまだ未完なんですが,とりあえず data.table を使った例:


[追記] lubridateパッケージにも高速な変換関数があるそうです:R で文字列を POSIX time に変換するには lubridate::parse_date_time2() がちょっぱや #rstatsj - Qiita

[追記] Hadley Wickham が fread() に相当する readr というもの(旧 fastread)を作っています:hadley/readr · GitHub

[追記] readr がCRANに入りました(readr 0.1.0 | RStudio Blog)。SPSS,Stata,SASファイルを読む haven も。Excelファイルを読む readxl(RでExcelのデータを読む方法参照)も合わせて,Hadley Wickham だらけになりました。


Last modified: