Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

utils::read.csvとdata.table::fread、readr::read_csv

More than 5 years have passed since last update.

この記事について

ちょっと大きなcsvファイルを読み込むのに、data.table::freadがすごく速かったとつぶやいたら(data.table::freadが速い)、いくつかリツイートしてもらったので、その後の話を少し公開してみる。data.table::freadreadr::read_csvは確かに速いけど、utils::read.csvと同じ結果を求めるためには、ちょっと一手間いりますよという話です。

(追記1:日付忘れました)@r-de-rさまからコメントをいただき、Macでは同じようにならない旨、ご指摘いただきました。参考までにたけしょうがこの記事を書いたときの実行環境を記しておきます。

  • Windows 7 SP1
  • R 3.2.2
  • data.table 1.9.6
  • readr 0.2.2

(追記2:20151111)@yutannihilationさまがいろいろと調べて下さいました。この記事の内容はパッケージのバージョンによって結果が左右されるようです。すごく魅力的なパッケージですが、まだ開発も続いているパッケージですし、ある程度落ち着くまでは、積極的な利用は控えていた方がいいかもしれません(コードが後々使えなくなる可能性があるので)。

読み込みの検証

同じデータを読み込んで、同じ結果になるまでの手順を探ります。

読み込みデータについて

ファイルは適当に作ったcsvファイル(5KB程度)を利用します。

utils::read.csv

みんな大好きutils::read.csvです。最初、データの読み込みには、この関数を使えと教わる人が多いことでしょう(utils::read.table含む)。以下の例では、na.strings = ""として、空白をNAとして扱う指定をしています。

dat1 <- read.csv("http://plaza.umin.ac.jp/~takeshou/R/dat/survey.csv",
              na.strings = "")
str(dat1)

'data.frame': 100 obs. of 10 variables:
$ sample : int 1 2 3 4 5 6 7 8 9 10 ...
$ age : int 60 28 23 46 59 43 56 64 45 52 ...
$ height : num 185 155 171 163 163 ...
$ weight : num 86.7 57.8 66.1 62.4 60.4 ...
$ sex : Factor w/ 2 levels "f","m": 1 2 2 1 1 2 2 1 2 2 ...
$ village : Factor w/ 3 levels "A","B","C": 2 1 1 1 3 1 1 3 2 1 ...
$ income : num 8.72 13.61 9.2 6.9 11.18 ...
$ disease : int 1 0 0 0 1 0 0 0 1 0 ...
$ treatment: Factor w/ 2 levels "X","Y": 1 NA NA NA 2 NA NA NA 2 NA ...
$ outcome : int 1 NA NA NA 1 NA NA NA 1 NA ...

utils::read.csvのdefaultでは、文字列は因子になって付置されます。医学・保健系の解析を行う場合では、ほとんどの場合、この動作で問題はないと思いますし、この動作が最も便利だと思います。1

ですので、今回は、このdat1と同じモノをdata.table::freadreadr::read_csvを使って作成してみましょう。

data.table::fread

後述のreadr::read_csvもそうですが、defaultでは、文字列が文字列として読み込まれます。なので前提として、stringsAsFactors = TRUEというオプション指定が必要です。

library("data.table")
dat2 <- fread("http://plaza.umin.ac.jp/~takeshou/R/dat/survey.csv",
              stringsAsFactors = TRUE,
              na.strings = "")
str(dat2)

Classes ‘data.table’ and 'data.frame': 100 obs. of 10 variables:
$ sample : int 1 2 3 4 5 6 7 8 9 10 ...
$ age : int 60 28 23 46 59 43 56 64 45 52 ...
$ height : num 185 155 171 163 163 ...
$ weight : num 86.7 57.8 66.1 62.4 60.4 ...
$ sex : Factor w/ 3 levels NA,"f","m": 2 3 3 2 2 3 3 2 3 3 ...
$ village : Factor w/ 4 levels NA,"A","B","C": 3 2 2 2 4 2 2 4 3 2 ...
$ income : num 8.72 13.61 9.2 6.9 11.18 ...
$ disease : int 1 0 0 0 1 0 0 0 1 0 ...
$ treatment: Factor w/ 3 levels NA,"X","Y": 2 1 1 1 3 1 1 1 3 1 ...
$ outcome : int 1 NA NA NA 1 NA NA NA 1 NA ...
- attr(*, ".internal.selfref")=

このままでは、data.tableとしての属性も持ちますので、as.data.frameを使って、data.frameに変換しますが、実は、FactorのところでNAも水準の1つとしてカウントされています。これはfactorを使って、調整します。

dat2 <- as.data.frame(dat2)
for(loop in seq(along.with = dat2)){
  if(is.factor(dat2[, loop])){
    dat2[, loop] <- factor(dat2[, loop])
  }
}

ここまでやって、漸くdat1dat2で同じものになりました。

identical(dat1, dat2)

[1] TRUE

readr::read_csv

readr::read_csvもほぼ同様ですが、今度は問題が2つになります。1つめは、文字列を因子に変換してくれないことで、2つめは、文字コードの問題です。僕は基本的にWindows環境ですので、最初、SJISを指定せずに読み込んだとき、結構悲惨な状態になりました。

library(readr)
dat3 <- read_csv("http://plaza.umin.ac.jp/~takeshou/R/dat/survey.csv",
                 locale = locale(encoding = "SJIS"))
str(dat3)

Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 100 obs. of 10 variables:
$ sample : int 1 2 3 4 5 6 7 8 9 10 ...
$ age : int 60 28 23 46 59 43 56 64 45 52 ...
$ height : num 185 155 171 163 163 ...
$ weight : num 86.7 57.8 66.1 62.4 60.4 ...
$ sex : chr "f" "m" "m" "f" ...
$ village : chr "B" "A" "A" "A" ...
$ income : num 8.72 13.61 9.2 6.9 11.18 ...
$ disease : int 1 0 0 0 1 0 0 0 1 0 ...
$ treatment: chr "X" NA NA NA ...
$ outcome : int 1 NA NA NA 1 NA NA NA 1 NA ...

最初にdata.frameに変換し、次にcharacterからfactorへの変換を行います。

dat3 <- as.data.frame(dat3)
for(loop in seq(along.with = dat3)){
  if(is.character(dat3[, loop])){
    dat3[, loop] <- factor(dat3[, loop])
  }
}
identical(dat1, dat3)

[1] TRUE

これで漸くutils::read.csvと同等の結果が得られました。

以上でこのつぶやきの全貌の紹介を終わります。

読み込みスピード

今回は、小さなファイルの読み込みですので、スピードについては検証していません。同じ結果を得られるためのスピードも誰かが…

終わりに

初めてQiitaに書いてみました。こういう情報共有サービスというのはありがたいですね。なるべく間違いのないように記述したつもりですが、何かございましたら、なんなりとご指摘いただけますと助かります。


  1. この後、diseaseやoutcomeも因子に変更しますが、今回はそこまでは無視します。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away