列数の異なるCSVへの対処
CSVは綺麗なデータばかりでなく、時に規定と異なる列数のレコードが紛れ込んでいたりすることもある。
ここでは、pandas.read_csv()
にて、「正しいフォーマットでの列数は定まっているが、
列数の異なるレコードが入ってしまっているようなデータを読み込んだ」ときの挙動をメモしておく。
最初から可変列数のCSVは、、、まぁ普通にopen()
などで読み込んで
二次元リストに整形した上で DataFrame()
に与えればいいと思う。
全体として pandas.read_csv()
は、正しいデータであることを前提とした仕様が多くて、
読み込みながら異常検知を同時にやってくれることにはあまり期待しない方がよい。
全列読み込む
列数が多すぎる
そのままだとエラーになり、例外処理なしではPythonの処理自体がそこで止まる。
read_csv()
の引数に「on_bad_lines=“error” / “warn” / “skip”
」を指定することで、
エラーにするか、標準エラー出力に警告を出してスキップするか、何も言わずスキップするか指定できる。
無理矢理パースする
ver.1.4 以降限定。
「余った列は捨てていいからスキップしないでほしい」など、列数が多い事態に対処法が決まっている場合、
engine=“python”
限定となるため処理速度は落ちるが、
on_bad_lines
に「1行がカンマで分割された文字列リスト List[str]
を引数にして、
適切な長さにした List[str]
を返す関数」を渡すと、
返ってきた値でパースを再開してくれる。
その上で返値が長すぎる場合、警告を出しつつあまりは捨てられて処理される。
Noneを返すとスキップする。
列数が少なすぎる
足りない分は NaN になる。
カンマの数が足りない場合は異常なのでスキップしてほしい場合でも、そういうオプションは無いっぽい。
一応、以下で議論はされている。
「正常なレコードならば最後の列には必ず値が入る」場合はラッキー。
読み込んだ後、最後の列がNaNのレコードを捨てればよい。
列を指定して読み込む
read_csv(csv_path, usecols=[0,1,3])
などとして、読み込む列を指定できる。
列数が多すぎる
普通に、該当する列のレコードが読み込まれる。
エラーを出す機能はない?
列数が少なすぎる
足りない列が指定された場合は NaN になる。
エラーを出す機能はない?
それでもスキップしたい
普通に open()
などで1行ずつ読みつつカンマの数をチェックして、
二次元リストに整形する、またはCSV文字列として連結しなおすなどしてから
pandas に与えるのが現状の手段となる、のかなあ。
まぁ、異常レコードが紛れるようなCSV、 カンマの数が偶然あっていてもそれだけで正しいと言うには足りないし、 じゃあどういうデータならば正しいのか、なんて汎用的に自動判別できるはずもないのはわかる。
NaNありきで読み込んでから、「もし正常レコードならこの列にはこういう値が入っている」というバリデーションをちゃんとする、結局それしかないんだろうね。