概要 - 列数はどうやって決まっているのか
先日研究室でR言語を使っていて、3列のデータを持つCSVからread.csv
関数でdataframeを作ろうとしたところなぜか2列のデータとして認識されてしまう事案が発生しました。
このCSVの3列目は一部のレコードで存在し、それ以外の行はデータが入っていない(読み込むとNA
になる)というものです。
例えばこんな感じで、col3にはデータが入っている行といない行があります。
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
でも同様)の公式リファレンスでは以下のような説明がされています。
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 iffill
orblank.lines.skip
are true, so specifycol.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列として認識される例
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列目が現れない)
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つあると思います。
- 最終列が存在しない行では最後にカンマを入れる
-
col.names
を(列名をベクトルで)指定する
前者の方法を用いる場合はデータ生成元でログの吐き出し方を変えるなどの対処が必要でしょう。
そのため既存の実装を変更する必要があります。
一方後者の方法はある種の列数指定ですので、冒頭に示したような最後にカンマのないデータに対しても列数を強制的に指定できるという点で有利ですが、col.names
の長さ分の行までしか検出されないのでかなり後方のデータになって初めて現れる場合は前者の方法を使うしかありません。
参考
- Data Input - The R manual DEVELOPMENT Versions (英語版公式リファレンス)
- 非公式の日本語訳 (ご指摘により翻訳が誤っていたことが判明しましたので本文中からは削除させていただきました)