PlayGround Article read.tableやread.csvで読み込まれるdataframeの列数は最初の5行で決まるらしい imaizume 2015年12月7日 Created with Sketch. 0 Created with Sketch. 155 概要 - 列数はどうやって決まっているのか --- 先日研究室でR言語を使っていて、3列のデータを持つCSVから`read.csv`関数でdataframeを作ろうとしたところ**なぜか2列のデータとして認識されてしまう事案が発生**しました。 このCSVの3列目は一部のレコードで存在し、それ以外の行はデータが入っていない(読み込むと`NA`になる)というものです。 例えばこんな感じで、**col3にはデータが入っている行といない行があります**。 ```text:test.csv col1,col2,col3 lorem,10 ipsum,18 dolor,30,true sit,40 amet,23,false ``` `read.csv("./test.csv", sep=",", header=F)`を実行した結果 |col1|col2|col3| |:--|:-:|:--| |lorem|10|NA| |ipsum|18|NA| |dolor|30|true| |sit|40|NA| |amet|23|false| ちなみに上記の例ではきちんと3列のデータとして読み込まれました。 また上記と同様のCSVを複数持っていたのですが、**あるCSVでは3列で認識され、あるCSVは2列で認識される**という現象が起きたため「そもそもRのdataframeってどうやって行数判断されてるんだ??」という疑問が生まれたのでした。 結論 - 最初の5行が判断材料 --- `read.csv`(`read.table`でも同様)の[公式リファレンス](https://stat.ethz.ch/R-manual/R-devel/library/utils/html/read.table.html)では以下のような説明がされています。 > The number of data columns is determined by looking at the first five lines of input (or the whole input if it has less than five lines), or from the length of `col.names` if it is specified and is longer. This could conceivably be wrong if `fill` or `blank.lines.skip` are true, so specify `col.names` if necessary (as in the ‘Examples’). 翻訳すると 『列数は**入力データの最初の5行(全体が5行未満ならば全ての行)を見て決定される。** もしくは**`col.names` が指定されており、かつそれが最初の5行で決められた列数よりも長ければ、そのcol.namesの長さから決定される。**ただし `fill` または `blank.lines.skip` オプションに`TRUE`が指定された場合はこの限りではないかもしれない。』 となります。 したがって要約すると * 「`col.names`が指定されていない」 OR 「5行未満」 : **「5行目までの列数」 = 「dataframe全体の列数」** * 「`col.names`が指定されている」 AND 「5行以上」 : **「`length(col.names)`行目までの列数」 = 「dataframe全体の列数」** になるそうです。 うーんこれは知らなかった。 つまり冒頭の現象は、**あるCSVでは最初に3列目が現れるのが6行目以降だったので2列と判定され、別のCSVでは5行目までに3列目のデータが現れていたため3列と認識されていた**ようでした。 ### 3列として認識される例 ```text:3列のデータとして認識される例 col1,col2,col3 lorem,10 ipsum,18 dolor,30,true sit,40 amet,23,true consectetur,7,NA ``` `read.table`した結果 |col1|col2|col3| |---|:-:|---| |lorem|10|NA| |ipsum|18|NA| |dolor|30|true| |sit|40|NA| |amet|23|true| |consectetur|7|NA| ### 2列のデータとして認識される例 (5行目までに3列目が現れない) ```text:2列と認識されてしまう例 lorem,10 ipsum,18 dolor,30 sit,40 amet,23 consectetur,7,true << 6行目以降のため無視される ``` `read.table`した結果 |col1|col2| |---|:-:| |lorem|10| |ipsum|18| |dolor|30| |sit|40| |amet|23| |consectetur|7| ここでもし**`col.names`に`c("col1", "col2", "col3")`を指定すれば3列のデータとして認識されます**。 一部データが空の列への対処法 - カンマをつけるか列名をベクトルで指定する --- また引用したリファレンスにもあったように、一部のデータ(特に最終列)が欠けたデータで正しく列数を認識させる方法は2つあると思います。 1. 最終列が存在しない行では最後にカンマを入れる 1. `col.names`を(列名をベクトルで)指定する 前者の方法を用いる場合は**データ生成元でログの吐き出し方を変えるなどの対処が必要**でしょう。 そのため既存の実装を変更する必要があります。 一方後者の方法はある種の列数指定ですので、冒頭に示したような最後にカンマのないデータに対しても列数を強制的に指定できるという点で有利ですが、**`col.names`の長さ分の行までしか検出されない**のでかなり後方のデータになって初めて現れる場合は前者の方法を使うしかありません。 参考 --- * [Data Input - The R manual DEVELOPMENT Versions (英語版公式リファレンス)](https://stat.ethz.ch/R-manual/R-devel/library/utils/html/read.table.html) * [非公式の日本語訳](http://www.is.titech.ac.jp/~mase/mase/html.jp/temp/read.table.jp.170.html) (ご指摘により翻訳が誤っていたことが判明しましたので本文中からは削除させていただきました)