Pandas & NumPy Academy · レッスン

Parquet:高速な列指向ストレージ

to_parquet()でPandas DataFrameをParquetに書き込み、CSVより高速に読み戻し、列プルーニングで必要なフィールドだけを読み込みます。

レッスン 4/413 ステップ

「Parquet:高速な列指向ストレージ」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

Parquetとは

Apache Parquetは、分析ワークロード向けに設計された列指向バイナリファイル形式です。データをテキストとして行単位で保存するCSVとは異なり、Parquetは各列を連続したブロックに保存し、効率的に圧縮するとともにメタデータを記録します。そのため、幅の広いテーブルから一部の列だけを読み込むクエリが大幅に高速化されます。Parquetはデータレイク(AWS S3、Google Cloud Storage)で事実上の標準形式となっており、Pandas、Dask、Spark、BigQueryでネイティブにサポートされています。

to_parquet()でParquetを書き込む

Pandas DataFrameをParquetに変換するには、df.to_parquet('output.parquet')という1回のメソッド呼び出しで済みます。デフォルトのエンジンはpyarrowです(pip install pyarrowでインストールします)。Parquetは列のデータ型を正確に保持するため、日付列が読み込み時に文字列になることはありません。また、compressionパラメーターによる圧縮にも標準で対応しています。'snappy'は適度な圧縮率で読み書きが高速であり、'gzip'は速度を犠牲にして、より高い圧縮率を実現します。

import pandas as pd
import numpy as np

# Create a sample DataFrame
np.random.seed(0)
df = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=100000, freq='T'),
    'value': np.random.randn(100000),
    'category': np.random.choice(['A', 'B', 'C'], 100000)
})

# Write to Parquet
df.to_parquet('data.parquet', index=False, compression='snappy')
print('Written to data.parquet')

read_parquet()でParquetを読み込む

pd.read_parquet('output.parquet')を使うと、ファイルをDataFrameに読み戻せます。同等のCSVを読み込む場合と比べ、Parquetの読み込みは、多数の列を持つ幅の広いテーブルで通常5~10倍高速です。データ型は正確に保持されます。日付はdatetime64のまま、カテゴリはcategoryのまま、整数は保存時のint32またはint64のままです。メタデータがファイルに埋め込まれているため、データ型の推測も必要ありません。

import pandas as pd
import time

# Read Parquet
start = time.time()
df = pd.read_parquet('data.parquet')
print(f'Read Parquet: {time.time()-start:.3f}s')
print(df.dtypes)
print(df.shape)

列プルーニング:必要な列だけを読み込む

列指向ストレージの最大の利点は列プルーニングです。ファイルの残りの部分を走査せずに、特定の列だけを読み込めます。columnsパラメーターに列名のリストを渡してください。100列のテーブルで1列あたり100 MBあり、そのうち3列だけが必要な場合、Parquetは10 GBではなく3 MBを読み込みます。CSVでは、目的の列を取り出すためにすべての文字を走査する必要があります。そのためParquetは、分析パイプラインで扱う幅の広いテーブルに最適です。

import pandas as pd

# Only load the 2 columns needed for this analysis
df = pd.read_parquet('large_table.parquet',
                     columns=['date', 'revenue'])
print(df.columns.tolist())
print(df.shape)
print(df.memory_usage(deep=True).sum() / 1e6, 'MB loaded')

行グループフィルタリング(述語プッシュダウン)

Parquetは、ファイルフッターに各行グループ(行のブロック)の統計情報(最小値・最大値)を保存します。filtersパラメーターでフィルターを適用すると、読み込み対象と一致する可能性がない行グループ全体をスキップします。これを述語プッシュダウンと呼びます。たとえば、時系列順に並んだParquetファイルで日付をフィルタリングすると、範囲外の月のブロック全体をスキップし、関連する部分だけを読み込みます。pyarrowエンジンはこの機能をネイティブにサポートしています。

import pandas as pd

# Filter using predicate pushdown — row groups outside range are skipped
df = pd.read_parquet(
    'time_series.parquet',
    columns=['date', 'value'],
    filters=[('date', '>=', '2024-06-01'),
              ('date', '<', '2024-07-01')]
)
print(f'Loaded {len(df):,} rows (June only)')
print(df.head())

ParquetとCSVの比較

以下は、1000万行・20列のデータセットにおけるParquetとCSVの実用的な比較です:

  • ファイルサイズ:CSV 約2 GB、Parquet(snappy)約400 MB
  • 読み込み時間(全列):CSV 約15秒、Parquet 約2秒
  • 読み込み時間(3列):CSV 約15秒(すべてを走査する必要あり)、Parquet 約0.3秒
  • データ型の保持:CSVはデータ型を失う、Parquetは保持する
  • 人間による可読性:CSVはあり、Parquetはなし(バイナリ)

データを一度書き込み、何度も読み込む本番パイプラインでは、ほとんどの場合Parquetの方が適しています。

パーティション化されたParquetデータセット

非常に大規模なデータセットでは、Parquetのパーティション化されたデータセットを利用できます。データを複数のファイルに分割し、列の値に基づくディレクトリ階層で整理する方法です。たとえば年と月でパーティション化すると、data/year=2024/month=01/part.parquetのようになります。パーティション化されたデータセットを読み込むと、クエリに一致するディレクトリが自動的にフィルタリングされます。これはデータレイクの標準的なレイアウトであり、数十億行に対する効率的な範囲クエリを可能にします。

import pandas as pd

# Write a partitioned dataset (requires pyarrow)
df = pd.read_parquet('all_data.parquet')
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month

df.to_parquet(
    'partitioned_data/',
    partition_cols=['year', 'month'],
    index=False
)
# Creates: partitioned_data/year=2024/month=1/part-0.parquet etc.

パーティション化されたデータセットを読み込む

パーティション化されたParquetディレクトリの読み込み方法は、単一ファイルの読み込みと同じです。Pandas(pyarrow経由)がすべてのパーティションファイルを自動的に検出します。パーティション列の値は、結果のDataFrameの列として含まれます。また、filtersを使ってパーティションプルーニングを利用することもできます。パーティション列の値に基づいて、ディレクトリのサブツリー全体をスキップする機能です。これにより、1 TBのパーティション化されたデータセットに対するクエリでも、数MBのデータを読み込むような感覚で実行できます。

import pandas as pd

# Read the entire partitioned dataset
df_all = pd.read_parquet('partitioned_data/')
print('All years:', df_all['year'].unique())

# Read only 2024 data using partition pruning
df_2024 = pd.read_parquet(
    'partitioned_data/',
    filters=[('year', '==', 2024)]
)
print('2024 rows:', len(df_2024))

DaskでParquetを扱う

Daskはdd.read_parquet()とddf.to_parquet()によって、Parquetの読み書きをネイティブにサポートしています。パーティション化されたParquetディレクトリ内の各ファイルが1つのDaskパーティションになるため、完全に並列な読み込みが可能です。Daskは、フィルターが指定されている場合、述語プッシュダウンも利用します。大規模なDaskの処理結果をパーティション化されたParquetデータセットに書き出す方法は、現代のデータエンジニアリングパイプラインで標準的に使われています。

import dask.dataframe as dd

# Read partitioned Parquet with Dask (each file = one partition)
ddf = dd.read_parquet('partitioned_data/',
                      columns=['date', 'revenue', 'region'],
                      filters=[('year', '==', 2024)])

# Compute aggregation in parallel
result = ddf.groupby('region')['revenue'].sum().compute()
print(result.sort_values(ascending=False))

圧縮とエンコーディングのオプション

Parquet は複数の圧縮アルゴリズムと内部エンコーディング方式に対応しています。Snappy(デフォルト)は、中程度の圧縮率で速度を優先します。Gzip はファイルサイズを約 30% 小さくできますが、読み書きは遅くなります。Zstd は、速度と圧縮率のバランスにおいて、これら 2 つより優れています。整数列の場合、Parquet は追加設定なしでデルタエンコーディングや辞書エンコーディングを自動的に適用し、さらにサイズを削減します。

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({'id': range(500000), 'val': np.random.randn(500000)})

for comp in ['snappy', 'gzip', 'zstd']:
    fname = f'data_{comp}.parquet'
    df.to_parquet(fname, compression=comp, index=False)
    import os
    size_mb = os.path.getsize(fname) / 1e6
    print(f'{comp}: {size_mb:.2f} MB')

パイプラインで CSV を置き換える

Parquet を導入する最も簡単な方法は、プロジェクトの開始時に一度だけ変換するステップを追加することです。CSV を一度読み込み、データ型を整理して適切な型に変換し、Parquet として保存します。その後の実行ではすべて、CSV の代わりに Parquet ファイルを読み込みます。コードの変更を最小限に抑えながら、速度とストレージ使用量のメリットをすぐに得られます。新しいデータが CSV(夜間のエクスポートなど)として届く場合は、分析を始める前に Parquet として書き出す変換ステップをパイプラインに追加してください。

import pandas as pd

# One-time conversion
df = pd.read_csv('raw_data.csv',
                 parse_dates=['date'],
                 dtype={'category': 'category',
                        'amount': 'float32'})
df.to_parquet('clean_data.parquet', index=False)

# All future reads use Parquet
df_fast = pd.read_parquet('clean_data.parquet')
print('Loaded from Parquet:', df_fast.dtypes.to_dict())

理解度チェック

このレッスンで学んだデータ分析の概念について、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、CSV と比較してto_parquet() と read_parquet() がより高速で、ファイルサイズが小さく、データ型を保持したファイル入出力を提供すること、columns パラメーターによる列のプルーニングで必要な列だけを読み込み、ファイル全体のスキャンを避けられること、そして列の値ごとに整理されたパーティション分割 Parquet データセットによってパーティションプルーニングが可能になり、大規模なデータレイクで範囲検索を効率化できることを学びました。次は SQLAlchemy を使用して Pandas をリレーショナルデータベースに接続します。

無料で開始

AI チューターと学ぶ Python — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
30
レッスン
120

よくある質問

「Parquet:高速な列指向ストレージ」レッスンは無料ですか?

はい。「Parquet:高速な列指向ストレージ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

「Parquet:高速な列指向ストレージ」で何を学びますか?

to_parquet()でPandas DataFrameをParquetに書き込み、CSVより高速に読み戻し、列プルーニングで必要なフィールドだけを読み込みます。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Pandas & NumPy Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「Parquet:高速な列指向ストレージ」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPandas & NumPy Academyレッスンでコードを書いて実行できますか?

はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. chunksizeによるCSVのストリーミング
  2. チャンク間の逐次集計
  3. Dask DataFrame入門
  4. Parquet:高速な列指向ストレージ
← Pandas & NumPy Academyに戻る