Courses
私と同じように日常的にPythonでデータ分析をしていると、CSVファイルの読み込みが最もよくある作業のひとつだと気づくはずです。ただし、データセットが大きくなるにつれて、この方法は遅くなったりメモリを多く消費したりすることがあります。
Polarsは、Pandasに代わる高性能な選択肢として設計された、高速でモダンなPython向けDataFrameライブラリです。速度と低メモリ使用に重点を置いて構築されているため、従来のツールよりもはるかにスムーズに大規模データセットを扱えます。
Polars のコア関数 pl.read_csv() は、CSVファイルをDataFrameに読み込むためのシンプルな解決策を提供し、パース、データ型、メモリ使用を制御するためのオプションが組み込まれています。
このガイドでは、Polars の pl.read_csv() 関数を使ってCSVファイルを読み込み、パースを制御し、大規模データセットを扱う方法を紹介します。これから始める方は、まず Introduction to Polars コースで、Polarsを使ったデータ操作とインサイト抽出の基本を学んでください。
pl.read_csv() の基本
その前に、環境設定の方法は Python Polars チュートリアルをご確認ください。
では、pl.read_csv() 関数がどのように動作するか見ていきましょう。
# import the module
import polars as pl
# Load CSV into a Polars DataFrame
fuel_data = pl.read_csv("Fuel_Consumption_2000-2022.csv")
# Preview first few rows
print(fuel_data.head())
上の例では、Polarsがファイルを読み取り、DataFrameにロードしています。関数はPolarsのDataFrame(表形式のデータ構造)を返し、これはpandasで得られるものと似ています。
デフォルトでは、pl.read_csv() は次のように動作します。
-
最初の行が列名であると仮定する(
has_header=True) -
列のデータ型を自動で推論する
-
区切り文字としてカンマ(
,)を使用する -
ファイル全体をメモリに読み込む
pl.read_csv() の主なパラメータ
pl.read_csv() がデータを読み込む方法が分かったところで、以下のパラメータを使ってPolarsのパース方法をどのように調整できるかを見ていきます。
ファイルパスとソース
Polarsはさまざまなソースからデータを読み込めます。ローカルの文字列パス、Pathlib オブジェクト、URLも渡せます。例えば、次のコードは、各国のGDPをさまざまな年で含む大きなCSVをウェブから読み込みます。
# Reading from a URL
url = "https://raw.githubusercontent.com/datasets/gdp/master/data/gdp.csv"
gdp_data = pl.read_csv(url)
区切り文字とセパレーター
すべてのCSVがカンマを使うわけではありません。separator 引数を使えば、タブ、セミコロン、パイプなどの文字に対応できます。以下の例は、ファイル読み込み時に区切り文字を指定する方法です。
# Reading a Semicolon-separated file
sales_data = pl.read_csv("2024_sales.csv", separator=";")
# Reading a Tab-separated file (TSV)
orders_data = pl.read_csv("all_orders.tsv", separator="\t")
ヘッダーの扱い
前述のとおり、Polarsは最初の行に列名があると仮定します。もしファイルにヘッダー行がない場合は、以下のように has_header=False を指定してください。Polarsは column_1、column_2、column_3 のように自動で列名を割り当てます。
# Load file without a header
orders_data = pl.read_csv("all_orders.csv", has_header=False)
特定の列名を指定してリネームすることもできます。例えば次のとおりです。
# Providing specific column names
sales_data = pl.read_csv("sales_April.csv", new_columns=[
"OrderDate", "OrderNumber", "ProductKey", "SalespersonKey", "Salesperson"])
エンコーディング
CSVファイルによって文字エンコーディングが異なる場合があります。文字化けやエラーが出る場合は、エンコーディングを指定してください。
# Load CSV into a Polars DataFrame
fuel_data = pl.read_csv("Fuel_Consumption_2000-2022.csv", encoding="utf8")
他にも一般的なオプションとして、無効な文字を適切に処理する ”latin1” や ”utf8-lossy” があります。
PolarsでCSV読み込み時に列を選択する方法
大きなCSVを扱う際、すべての列が必要とは限りません。Polarsでは、columns パラメータで必要な列だけを読み込めます。
# Load only specific columns
fuel_data = pl.read_csv("Fuel_Consumption_2000-2022.csv",
columns=["YEAR", "MAKE", "MODEL"]
)
読み込み時に必要な列を選ぶと、不要なデータを読み込まないためメモリ使用量を削減できます。この方法は読み込みの高速化や、パイプライン全体のパフォーマンス向上にもつながります。
PolarsのCSVでデータ型(スキーマ)を扱う方法
Polarsは強い型付けのライブラリで、各列は整数、文字列など一貫したデータ型でなければなりません。
自動型推論
デフォルトでは、Polarsがデータを検査して自動的に列型を決定します。多くの場合はうまく機能しますが、IDを整数ではなく文字列として扱うべき列を誤って解釈するなど、誤推論が起きることもあります。
スキーマを手動で指定
DataFrameの一貫性を保ちたい場合は、データスキーマを手動で指定するべきです。これにより複数ファイル間での整合性が保たれ、後段の処理で型に起因するエラーを避けられます。
多くのケースでは、schema_overrides を使って特定の列だけデータ型を指定し、残りはPolarsに推論させるのが良いでしょう。
import polars as pl
# Manually overriding specific data types
empl_data = pl.read_csv(
"all_employees.csv",
schema_overrides={
"id": pl.Int64,
"name": pl.String,
"age": pl.Int64,
"salary": pl.Float64
}
)
または schema を使って、DataFrameの構造全体を定義します。
# Manually define the full schema
empl_data = pl.read_csv(
"all_employees.csv",
schema={
"id": pl.Int64,
"name": pl.String,
"age": pl.Int64,
"salary": pl.Float64
}
)
PolarsのCSVで欠損値を扱う方法
デフォルトで、Polarsは欠損値を自動検出し、null として表現します。欠損が ”NA”、”N/A”、”missing” のような特定の文字列で表されることもあります。これらは null_values で定義して、null として扱えます。
# Treating "N/A" and "EMPTY" as nulls
survey_data = pl.read_csv(
"survey_results.csv",
null_values=["N/A", "EMPTY", "null"]
)
欠損値を正しく処理することで、データ型の一貫性を保ち、誤った計算を防げるため、分析やモデリング時のエラーを減らせます。
Polarsで大きなCSVファイルを読み込む
手元のRAMを超える大規模データセットを扱う場合、Polarsはファイル全体を一度に読み込まずに処理できる点で真価を発揮します。
scan_csv() による遅延読み込み
read_csv() のように即座にメモリへ読み込む代わりに、Polarsは遅延実行の代替である scan_csv() を提供しており、最適化されたクエリプランを構築して必要な処理だけを実行します。
以下の例では、pl.scan_csv がCSVファイルを読み込まずにスキャンし、車種が“ACURA”の行に対して “YEAR”、“MAKE”、“MODEL” の列だけを取得するクエリを構築し、それを実行します。この操作により、ファイル全体ではなく、フィルタ後のデータだけがメモリに読み込まれます。
# Lazily reference the file (no data loaded yet)
fuel_consumption = pl.scan_csv("Fuel_Consumption_2000-2022.csv")
fuel_consumption_filtered = fuel_consumption.select(
["YEAR", "MAKE", "MODEL"]).filter(pl.col("MAKE") == "ACURA")
# Execute the query and load only the required data
fuel_consumption_acura = fuel_consumption_filtered.collect()
scan_csv() の使用をおすすめするケース:
- メモリに余裕なく収まらない大きなファイルを扱うとき
- フィルタ、列選択、集約など複数の変換を適用するとき
- 実行前にクエリ最適化を行いたいとき
ストリーミングとメモリ効率
Polarsはデータをチャンクに分けてストリーミング処理でき、ファイルサイズに関わらずピークメモリを一定に保てます。
大規模CSVには、まず scan_csv() で遅延クエリを作成するのが有効です。scan_csv() 呼び出し時点ではファイルは完全には読み込まれません。
# Read data in chunks
fuel_consumption = pl.scan_csv("Fuel_Consumption_2000-2022.csv",
low_memory=True)
上記の方法は依然として read_csv を使うため、最良のアプローチは遅延実行とストリーミングを組み合わせることです。
次の例では、Polarsがパイプラインでファイルをバッチ単位(行ごと)に処理し、任意の時点でメモリにはフィルタ済みの行(“CYLINDERS” > 3)のみを保持します。
# Lazily reference the file (no data loaded yet)
fuel_consumption = pl.scan_csv("Fuel_Consumption_2000-2022.csv")
result = fuel_consumption.filter(pl.col("CYLINDERS") > 3)
# Stream execution instead of loading everything at once
fuel_consumption_high = result.collect(engine="streaming")
Pandasに対するパフォーマンス上の優位性
pandasと比べて、CSVの読み込みや処理においてPolarsは優れた性能を示すことが多く、次のセクションで確認します。
Polars read_csv と Pandas read_csv の比較
以下の表は、PythonでCSVを読む際のPolarsとPandasの違いをまとめたものです。
|
Aspect |
Polars |
Pandas |
|
Speed |
マルチスレッドと最適化されたパースにより高速 |
大規模ファイルでは遅くなりがち(主にシングルスレッド) |
|
Memory Usage |
フットプリントが小さい;遅延+ストリーミングをサポート |
データセット全体を即時にメモリへ読み込む |
|
Syntax |
|
|
|
Execution Model |
遅延実行( |
即時(イager)実行のみ |
|
Optimization |
組み込みのクエリ最適化(射影、フィルタリング) |
自動最適化は限定的 |
|
Best Use Case |
大規模データセット、性能重視のワークフロー |
小規模データセット、素早い分析 |
分析ニーズに最適なツールを見極めるために、Pandas と Polars の違いを解説した記事をご覧ください。
さまざまなソースからCSVを読み込む
前述のとおり、Polarsを使えばさまざまなソースからCSVを読み込めます。ここまでの例では、ローカルファイルとURLからの読み込み方法を示しました。
さらに、Polarsは圧縮されたCSVファイルも自動で処理できます。例えば、次のコードは .gzip ファイルからデータを読み込みます。
# Read gzip-compressed CSV
census_data = pl.read_csv("2018_census.csv.gz")
よくあるエラーとトラブルシューティング
高性能なエンジンであるPolarsでも、特にCSV読み込み時には問題に遭遇することがあります。ここでは、私がよく遭遇する問題とその対処法を紹介します。
-
エンコーディングエラー:
UnicodeDecodeErrorのようなエラーが出る場合、ファイルがUTF-8でない可能性があります。これは古いファイルや特定のExcelバージョンで書き出したCSVでよく起きます。適切なエンコーディングを設定するか、文字化けや不正な文字が混在する場合は“utf8-lossy”を使用してください。 -
区切り文字の問題:DataFrameは読み込めたのに、データが1列に詰め込まれてしまう場合、Polarsが区切り文字を認識できていません。
separator引数で適切な区切り文字(セミコロン;、タブ\t、パイプ|など)を明示的に設定してください。 -
不適切なデータ型:Polarsが列型を誤って推論することがあります。たとえば数値IDを文字列として読んでしまう、またはパースエラーが起きるなどです。こうした場合は、特定の列に対して
schema_overridesで型を指定してください。すべての列の型を定義したい場合はschemaを使います。infer_schema_lengthを増やして、推論前により多くの行を検査させることもできます。 -
大規模ファイルによるメモリ問題: 大きなファイルを読み込んだ際にPythonプロセスがクラッシュする場合、RAMを使い切っています。
read_csv()からscan_csv()に切り替えて遅延読み込みを行い、メモリ使用を抑えつつ性能を改善してください。データセットの列数を減らして読み込む、またはストリーミング実行でチャンク処理することも有効です。
まとめ
Polarsの read_csv() はシンプルながら実務に十分対応できる強力な関数です。私見では、データセットが大きくなるにつれてPolarsの優位性は明らかになります。
次のステップとして、 Polars GPU エンジン のブログをご覧になり、その多様な活用方法を学んでください。実践に進む準備ができたら、Super Bowl Analytics with Polars のコードアロングで、現実の分析課題に取り組み、計算を適用し、スポーツアナリティクスの課題に基本的な機械学習手法を適用してみましょう。
FAQs
Polarsにおける read_csv() と scan_csv() の違いは何ですか?
read_csv() はデータを即時にメモリへ読み込みますが、scan_csv() は遅延実行で、.collect() を呼び出したときにのみ処理を行います。
read_csv() の代わりに scan_csv() を使うべきなのはいつですか?
大規模データセットや変換を連鎖させる場合は scan_csv() を使用してください。実行を最適化し、メモリ使用量を抑えられます。
PolarsはCSVファイルから特定の列だけを読み込めますか?
はい。read_csv() の columns=[...] を使うか、scan_csv() の遅延クエリで列を選択できます。
Polars のCSVで欠損値はどのように扱えばよいですか?
Polarsは空の値をデフォルトで null として扱い、null_values= でカスタムのヌル表記を指定できます。
Polarsは圧縮されたCSVファイルをサポートしていますか?
はい。.gz や .zip などの圧縮形式を手動展開せずに読み込めます。