Pandasのデータフレームで、1行ごとに処理を回したいケースというのはデータの前処理などでよくあると思います。
そういう場合に使えるのがapply()です。今回は、apply()の使い方をまとめていこうと思います。
前提
以下のようなデータフレームを準備します。ウォルマートの株価データです。
import pandas as pd
df = pd.read_csv("../data/walmart_stock.csv").set_index("Date").head(5)
このデータにやや複雑な前処理を加えていきます。”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.5s | 10s |
100万件 | 3152.3s | 324.6s |
100万件の場合だと処理時間が10倍程度異なります。この点からもapply()を使うことのメリットは大きと言えます。
まとめ
apply()を使ってPandasデータフレームで1行ずつ処理を回す方法を紹介しました。For文でも同様の処理は実装できますが、処理時間の観点からapply()を使用することをオススメします。
大量データの処理時にはapply()を検討ください。