【Pandas】データフレームの1行ごとに複雑な処理を実行する -apply()

Pandasのデータフレームで、1行ごとに処理を回したいケースというのはデータの前処理などでよくあると思います。

そういう場合に使えるのがapply()です。今回は、apply()の使い方をまとめていこうと思います。

前提

以下のようなデータフレームを準備します。ウォルマートの株価データです。

import pandas as pd

df = pd.read_csv("../data/walmart_stock.csv").set_index("Date").head(5)
df

このデータにやや複雑な前処理を加えていきます。”Open”列が136.5以上であれば新規列”Diff”を作成し、”High”と”Low”の差分を格納したいとします。

※この処理に意味はないです

処理後は以下のようなデータにしたいです。

処理方法

よくやる手法 -for文

こういう処理をやろうとしたときにまず思いつくのはfor文を使った処理です。for文を使った場合は大体以下のようなコードになると思います。

for i, row in df.iterrows():
    if row[" Open"] >= 136.5:
        df.loc[i, "Diff"] = row[" High"] - row[" Low"]

このコードでも目的の形にデータを整形することができます。でもせっかく1行ごとに取り出しているのに、データフレームに値を入れる際はdf.locを使ってデータフレーム全体から検索しないといけないので、あまりスマートじゃない気もします。

apply()を使う

続いて同じ処理をapply()を用いて実行してみます。apply()では行ごと(あるいは列ごと)に独自に定義した関数を呼び出します。

def SetDiff(row):
    if row[" Open"] >= 136.5:
        row["Diff"] = row[" High"] - row[" Low"]
        
    return row

#1行ごとにSetDiff()を呼び出す
df = df.apply(SetDiff, axis=1)

関数SetDiff()を作成し、apply()で1行ごとにSetDiff()を呼び出します。axis=1とすることで1行ずつの処理となります。

なぜapply()を使うのか

for文もapply()も処理の書き方自体はあまり変わらないのに、なぜわざわざapply()を使うのでしょうか。

その秘密は処理速度にあります。例のような数件のデータであれば差はほとんどありませんが、数万、数十万件を処理する場合では両者に大きな差が出てきます。

データフレームを複製し、10万件、100万件データで両者の処理時間を比較してみます。

For文apply()
10万件37.5s10s
100万件3152.3s324.6s

100万件の場合だと処理時間が10倍程度異なります。この点からもapply()を使うことのメリットは大きと言えます。

まとめ

apply()を使ってPandasデータフレームで1行ずつ処理を回す方法を紹介しました。For文でも同様の処理は実装できますが、処理時間の観点からapply()を使用することをオススメします。

大量データの処理時にはapply()を検討ください。