プログラミング実践

【Python】pandas の .pipe() によるデータの連鎖処理

記事内に商品プロモーションを含む場合があります

どうも、こんにちは。
コンです。

また最近はPythonコードを書いているのが増えてきました。

業務の中でpandas でデータを 「絞り込んで→欠損行を落として→並べ替える」 という地味なコードを書いてました。そのコードは毎回中間変数に1行ずつ代入していくスタイルでした。動くには動くんですが、ふと 「これって本当にベストプラクティスなのかな?」 と思って調べてみました。

その過程で出会ったのが、pandas の .pipe() というメソッド。これを使うとコードが「上から下にデータが流れる」形に書けて、一気に読みやすくなったので、簡単にメモを残しておきます。

いつもの書き方:中間変数に1行ずつ代入する

たとえば、商品データから 「book カテゴリだけ抽出 → 価格が欠損している行を落とす → 価格で昇順にソートする」 という処理を書きたいとします。素直に書くとこんな感じになります。

import pandas as pd
df = pd.DataFrame({
    "name": ["A", "B", "C", "D", "E"],
    "category": ["book", "toy", "book", "food", "book"],
    "price": [1200, 800, None, 500, 2000],
})
def filter_category(df, category):
    return df[df["category"] == category]
filtered = filter_category(df, "book")
cleaned = filtered.dropna(subset=["price"])
result = cleaned.sort_values("price")

動作上は問題ありません。ただ、中間変数の filteredcleaned「次の行に渡すためだけに作った」一時変数で、命名にも地味に気を使います。あとから読み返したときに「cleaned って何が cleaned されてるんだっけ」と少し止まってしまうことも。

処理が3ステップ程度ならまだしも、5〜6ステップ重なってくると tmp1 tmp2 tmp3 みたいな名前が増えてきて、コードがゴチャっとしてきます。

.pipe() で書き直すと「上から下に流れる」

同じ処理を .pipe() を使って書き直すと、こうなります。

import pandas as pd
df = pd.DataFrame({
    "name": ["A", "B", "C", "D", "E"],
    "category": ["book", "toy", "book", "food", "book"],
    "price": [1200, 800, None, 500, 2000],
})
def filter_category(df, category):
    return df[df["category"] == category]
result = (
    df
    .pipe(filter_category, "book")
    .dropna(subset=["price"])
    .sort_values("price")
)

中間変数が消えて、「df を起点に、上から下へ何をやっているか」が一目でわかるようになりました。括弧で囲んでメソッド呼び出しを縦に並べているので、データが文字どおり上から下へ流れている感じに読めます。

df.pipe(filter_category, "book") という書き方は、filter_category(df, "book") と完全に等価です。違いは「DataFrame を関数の第1引数として明示的に渡すか、メソッドチェーンの一部として暗黙に渡すか」だけで、挙動は変わりません。

pandas の組み込みメソッドと混ぜられるのが嬉しい

.pipe() の便利なところは、pandas の組み込みメソッドと自作関数を1つのチェーンに混ぜられる点です。

.dropna().sort_values() は pandas が用意してくれているメソッドなので、そのままドット繋ぎで書けます。一方で filter_category は自作関数なので、本来なら filter_category(df, "book") と関数呼び出しの形でしか書けません。.pipe() はこの自作関数を 「あたかも pandas のメソッドのように」チェーンに差し込めるブリッジになっています。

自作関数も組み込みも区別なくつなげられるので、頭の切り替えコストが減ります。pandas 公式ドキュメントの「Tablewise Function Application」セクションでも推奨されている書き方です。

pandas encourages the second style, which is known as method chaining. pipe makes it easy to use your own or another library’s functions in method chains, alongside pandas’ methods.

pandas User Guide / Tablewise Function Application

「pandas はメソッドチェーンのスタイルを推奨する」「pipe は自作関数や他ライブラリの関数を pandas のメソッドと並べてチェーンに組み込みやすくする」と明言されている形です。

まとめ

中間変数だらけになりがちな pandas の前処理コードは、.pipe() を使うことで 「データが上から下へ流れていく」形に書き直せます。処理のためだけの変数ばかりのコードに違和感を感じている人は、一度試してみる価値ありです。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA