どうも、こんにちは。
コンです。
また最近は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")動作上は問題ありません。ただ、中間変数の filtered や cleaned は 「次の行に渡すためだけに作った」一時変数で、命名にも地味に気を使います。あとから読み返したときに「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.
— pandas User Guide / Tablewise Function Applicationpipemakes it easy to use your own or another library’s functions in method chains, alongside pandas’ methods.
「pandas はメソッドチェーンのスタイルを推奨する」「pipe は自作関数や他ライブラリの関数を pandas のメソッドと並べてチェーンに組み込みやすくする」と明言されている形です。
まとめ
中間変数だらけになりがちな pandas の前処理コードは、.pipe() を使うことで 「データが上から下へ流れていく」形に書き直せます。処理のためだけの変数ばかりのコードに違和感を感じている人は、一度試してみる価値ありです。
