はじめに
この実験では、pandas を使用してデータ分析をより大きなデータセットに拡張する方法に焦点を当てます。データの部分的な読み込み、効率的なデータ型の使用、チャンク分割、および Dask などの他のライブラリの活用などの手法をカバーしています。pandas はメモリ内分析に適しており、非常に大きなデータセットには必ずしも最適なツールではないことに注意することが重要です。
VM のヒント
VM の起動が完了したら、左上隅をクリックして Notebook タブに切り替え、Jupyter Notebook を開いて練習を行ってください。
時々、Jupyter Notebook の読み込みが完了するまで数秒待つ必要がある場合があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。
学習中に問題が発生した場合は、Labby に質問してください。セッション終了後にフィードバックを提供していただければ、迅速に問題を解決します。
データセットの生成
最初のステップは、テスト用の大規模なデータセットを生成することです。多数の列を持つデータセットを作成し、parquet ファイルに保存します。このステップでは pandas と numpy ライブラリが必要です。
import pandas as pd
import numpy as np
def make_timeseries(start="2000-01-01", end="2000-12-31", freq="1D", seed=None):
## Function to generate timeseries data
index = pd.date_range(start=start, end=end, freq=freq, name="timestamp")
n = len(index)
state = np.random.RandomState(seed)
columns = {
"name": state.choice(["Alice", "Bob", "Charlie"], size=n),
"id": state.poisson(1000, size=n),
"x": state.rand(n) * 2 - 1,
"y": state.rand(n) * 2 - 1,
}
df = pd.DataFrame(columns, index=index, columns=sorted(columns))
if df.index[-1] == end:
df = df.iloc[:-1]
return df
timeseries = [
make_timeseries(freq="1T", seed=i).rename(columns=lambda x: f"{x}_{i}")
for i in range(10)
]
ts_wide = pd.concat(timeseries, axis=1)
ts_wide.to_parquet("timeseries_wide.parquet")
必要なデータのみを読み込む
すべてのデータを読み込む代わりに、必要な列のみを読み込むことができます。ここでは、parquet ファイルから必要なデータのみを読み込む 2 つの方法を紹介します。
## Option 1: Load all data then filter
columns = ["id_0", "name_0", "x_0", "y_0"]
pd.read_parquet("timeseries_wide.parquet")[columns]
## Option 2: Load only the requested columns
pd.read_parquet("timeseries_wide.parquet", columns=columns)
効率的なデータ型を使用する
Pandas のデフォルトのデータ型は、メモリ使用効率が最適ではありません。このステップでは、より大きなデータセットをメモリに格納するために、より効率的なデータ型を使用する方法を示します。
ts = make_timeseries(freq="30S", seed=0)
ts.to_parquet("timeseries.parquet")
ts = pd.read_parquet("timeseries.parquet")
## Convert 'name' column to 'category' type for efficiency
ts2 = ts.copy()
ts2["name"] = ts2["name"].astype("category")
## Downcast numeric columns to their smallest types
ts2["id"] = pd.to_numeric(ts2["id"], downcast="unsigned")
ts2[["x", "y"]] = ts2[["x", "y"]].apply(pd.to_numeric, downcast="float")
チャンク分割を使用する
チャンク分割(Chunking)は、大きな問題を独立して解くことができる小さな問題に分割する方法です。各チャンクがメモリに収まる限り、メモリよりもはるかに大きいデータセットを扱うことができます。
files = pathlib.Path("data/timeseries/").glob("ts*.parquet")
counts = pd.Series(dtype=int)
for path in files:
df = pd.read_parquet(path)
counts = counts.add(df["name"].value_counts(), fill_value=0)
counts.astype(int)
他のライブラリを使用する
Dask のような他のライブラリは、メモリよりも大きいデータセットを扱うことができます。Dask は pandas に似た API を提供し、データを並列処理することができます。
import dask.dataframe as dd
ddf = dd.read_parquet("data/timeseries/ts*.parquet", engine="pyarrow")
## Compute value counts using Dask
ddf["name"].value_counts().compute()
まとめ
この実験では、pandas を使用してデータ分析をより大きなデータセットに拡張するためのさまざまな手法を紹介しました。大規模なデータセットを生成し、必要なデータのみを読み込む方法、効率的なデータ型を使用する方法、チャンク分割を行う方法を学びました。また、Dask のような他のライブラリを活用して、メモリよりも大きいデータセットを扱う方法についても調べました。この実験で学んだ手法と概念は、データ分析プロジェクトで大規模なデータセットを扱う際に役立つでしょう。