見出し画像

Polarsのread_csv()で、AhrefsのCSVが読み込みエラーになるときの対策

Polarsは高速かつ使いやすくておすすめのライブラリですが、read_csvやscan_csvでエラーが出てしまうことがあります。

特に「Pandasでは普通に読み込まれるのに、なんでPolarsだとエラーになるんだ??」というケースが非常に多く、私がPolarsを使い始めたときにはかなり頭を悩まされました。

今思い返すと単純な理由なのですが、解決策をなかなか見つけられなかったので、同じエラーに遭遇している方に向けて簡潔にまとめておこうと思います。


「Original error: ```invalid utf-8 sequence```」が表示される

このエラーは、読み込もうとしているCSVファイルのエンコードがUTF-8以外のときに表示されます。

Polarsのread_csv()は、デフォルトの設定ではCSVファイルをUTF-8として読み込もうとするので、ファイルがUTF-8以外のエンコーディングになっているとエラーになってしまいます

このエラーは、pl.read_csvの引数にencodingとseparatorを指定してあげることで解決します。

以下はUTF-16のCSVを読み込むときのコードの例です。

import polars as pl

# エラーになるコード
df = pl.read_csv("./csv/organic_keywords_utf16.csv")

# エラーにならないコード
df = pl.read_csv("./csv/organic_keywords_utf16.csv", encoding="utf-16", separator="\t")

また、pandasでCSVファイルを読み込んだあとで、pl.from_pandas()を使ってPolarsのDataFrameに変換する方法もあります。ただしこちらの方法では、PandasとPolarsのデータタイプの扱いが違うからなのか、各カラムのデータタイプが変わってしまうケースがあるため注意が必要です。

# PandasでCSVを読み込んでから、PolarsのDataFrameに変換する
# データタイプが変わってしまうことがあるので要注意
pandas_df = pd.read_csv("./csv/organic_keywords_utf16.csv", encoding="utf-16", delimiter="\t")
df = pl.from_pandas(pandas_df)


「Original error: ```remaining bytes non-empty```」が表示される

AhrefsからダウンロードしてきたCSVで、このエラーが表示されるときはデータタイプの推論が正しくない出来ていないときでした。

Polarsのread_csvでは、デフォルトではCSVのファイルの上位100行のデータから、各カラムのデータタイプを推論するようです。
そのため100行目まで数値ばかりだったデータで、101行目以降に文字列が入っていた場合には、データタイプが一致しないのでエラーが起こってしまいます。

このエラーが起こっていた場合には、read_csvの引数dtypesにdictを渡して、エラーの原因になっているカラムに対してデータタイプを指定します。

# dtypesにdictを渡す
# dictのvalueにはPolars.Datatypeを渡す
df = pl.read_csv("./csv/organic_keywords_compare.csv", dtypes={"Position change": pl.Utf8})

エラーが起こっているカラムを突き止める方法

エラー原因を突き止める方法はいくつかありますが、個人的にわかりやすいのread_csv()の引数にinfer_schema_length=10000を指定する方法です

infer_schema_lengthはデータタイプの推論に使う行数を指定する引数。デフォルトでは100行ですが、これを10,000行まで増やすことでCSVが読み込まれるかをチェックします(infer_schema_length=0を指定すると全データを読み込むようです)

これで無事にCSVが読み込まれた場合は、作成されたDataFrameのデータタイプをチェックして、想定と違うデータタイプになってしまっているカラムがないかを確認します

例えばAhrefsのOrganic Keywordsからダウンロードしてきたデータでは、本来は数値(Int64)になっていそうな「Position change」というカラムのデータタイプが文字列(str)になっていることが分かります。

そこで「Position change」に含まれているユニークな値を表示すると、このカラムには"New"や"Lost"など、文字列も含まれていることが発見できます。

# Position change内のユニークな値を表示する
df.select("Position change").unique()

このような文字列があるカラムは数値型(Int64)としてDataFrameを作成することはできないため、CSVファイルの読み込み時にデータタイプを指定してあげる必要があります。

このCSV読み込み時にデータタイプを指定する方法が、先ほどコードを記載していたread_csvの引数のdtypesです。

今回は「Position change」というカラムを、文字列(pl.Utf8)で読み込みたいので、以下のコードを使ってCSVを読み込みます。

df = pl.read_csv("./csv/organic_keywords_compare.csv", dtypes={"Position change": pl.Utf8})

まとめ

このnoteで紹介したのは2つのケースだけですが、Pandasから移行しているときに悩まされることが多いエラーかと思います。

特にdtypesのほうは、私自身はPandasでは意識していなかったので、最初はどう対処すれば良いのか全然わかりませんでした。

同じエラーで苦しんでいる方の助けになれば幸いです。


いいなと思ったら応援しよう!