pandas の pipe でメソッドチェーンを見やすくする

pandas のメソッドチェーンが長くなると、途中の処理が読みにくくなることがあります。pipe メソッドを使えば、独自の関数をチェーンの中に組み込めるため、処理の意図が明確になり、再利用性も高まります。

pipe の基本

pipe は DataFrame を第一引数として受け取る関数を、メソッドチェーンの中で呼び出すための仕組みです。

import pandas as pd

def remove_outliers(df, column, threshold=3):
    mean = df[column].mean()
    std = df[column].std()
    return df[(df[column] - mean).abs() <= threshold * std]

df = pd.DataFrame({
    "name": ["A", "B", "C", "D", "E"],
    "score": [80, 85, 90, 200, 75]
})

result = df.pipe(remove_outliers, "score")
print(result)

pipe を使わない場合は remove_outliers(df, “score”) と書くことになりますが、pipe を使えばチェーンの流れを崩さずに関数を適用できます。

チェーンの中に組み込む

pipe の真価はメソッドチェーンの中で発揮されます。

def add_rank(df, column):
    return df.assign(rank=df[column].rank(ascending=False).astype(int))

def filter_top_n(df, n=3):
    return df.nsmallest(n, "rank")

result = (
    df
    .pipe(remove_outliers, "score")
    .pipe(add_rank, "score")
    .pipe(filter_top_n, n=3)
)

各関数が「DataFrame を受け取って DataFrame を返す」というルールに従っていれば、pipe で自由につなげられます。処理の順番が上から下に読めるため、何をしているかが一目でわかるのが利点です。

pipe を使わない場合

filter_top_n(add_rank(remove_outliers(df, “score”), “score”), n=3) のようにネストが深くなる

pipe を使う場合

df.pipe(f1).pipe(f2).pipe(f3) と左から右へ読める

ラムダ式と組み合わせる

わざわざ関数を定義するほどでもない簡単な処理は、ラムダ式で書くこともできます。

result = (
    df
    .pipe(lambda d: d[d["score"] >= 50])
    .pipe(lambda d: d.assign(grade=d["score"].apply(
        lambda s: "A" if s >= 90 else "B" if s >= 80 else "C"
    )))
)

ただしラムダ式が複雑になると可読性が落ちるので、ある程度の処理量がある場合は名前付き関数に切り出すほうが望ましいでしょう。

実務での活用パターン

pipe はデータ前処理のパイプラインを構築するときに特に役立ちます。

生データの読み込み

クレンジング関数を pipe で適用

加工・集計関数を pipe で適用

分析や可視化に渡す

各ステップを独立した関数として定義しておけば、テストも容易になり、別のプロジェクトで再利用することもできます。assign で列を追加し、pipe で複雑な処理を組み込むという組み合わせが、pandas における読みやすいコードの定番パターンです。