こんにちは、かつコーチです。
「標準のメソッドだけでは実現できない、独自の変換処理をしたい」というときに活躍するのがapplyとlambdaです。
少しとっつきにくく感じる方も多い組み合わせですが、パターンを覚えてしまえば実務で頻繁に使うことになります。
applyとlambdaとは?
applyの定義:各要素・各行に関数を適用する
applyとは、Series(列)の各要素、またはDataFrameの各行・各列に対して、指定した関数を適用するためのメソッドです。
import pandas as pd
df = pd.DataFrame({
"商品名": ["りんご", "みかん", "ぶどう"],
"価格": [150, 100, 300]
})
def add_tax(price):
return int(price * 1.1)
df["税込価格"] = df["価格"].apply(add_tax)
print(df)
商品名 価格 税込価格
0 りんご 150 165
1 みかん 100 110
2 ぶどう 300 330
lambdaの定義:名前をつけない一時的な関数
lambda(ラムダ)とは、defを使わずにその場限りの簡単な関数を定義できる書き方です。
df["税込価格"] = df["価格"].apply(lambda price: int(price * 1.1))
先ほどのadd_tax関数と同じ処理を、1行で書けています。
なぜapply×lambdaが重要なのか
pandasにはsumやmeanのような標準の集計・変換メソッドが数多く用意されていますが、「独自のルールで新しい列を作りたい」といった場面では、標準メソッドだけでは対応できません。applyとlambdaを組み合わせることで、どんな複雑な条件・変換処理も列・行単位で柔軟に実装できるようになります。
基本の書き方:apply・lambdaの使い方
手順1:Seriesに対するapply(1列の各値を変換)
df["価格帯"] = df["価格"].apply(lambda p: "高価格" if p >= 200 else "通常価格")
print(df)
商品名 価格 価格帯
0 りんご 150 通常価格
1 みかん 100 通常価格
2 ぶどう 300 高価格
手順2:DataFrameに対するapply(行ごとに複数列を使う処理)
複数の列を組み合わせて判定したい場合は、axis=1を指定して行単位で処理します。
df2 = pd.DataFrame({
"商品名": ["りんご", "みかん", "ぶどう"],
"価格": [150, 100, 300],
"在庫": [5, 0, 10]
})
def check_status(row):
if row["在庫"] == 0:
return "在庫切れ"
elif row["価格"] >= 200:
return "高価格"
else:
return "通常"
df2["ステータス"] = df2.apply(check_status, axis=1)
print(df2)
商品名 価格 在庫 ステータス
0 りんご 150 5 通常
1 みかん 100 0 在庫切れ
2 ぶどう 300 10 高価格
複数の条件を組み合わせるような処理は、lambdaよりもdefで関数を定義した方が読みやすくなります。
手順3:applyとlambdaの使い分け
# シンプルな1行の処理 → lambdaが便利
df["税込価格"] = df["価格"].apply(lambda p: int(p * 1.1))
# 複数の条件分岐がある処理 → defで関数を定義した方が読みやすい
def classify(row):
if row["在庫"] == 0:
return "在庫切れ"
elif row["価格"] >= 200:
return "高価格"
return "通常"
df2["ステータス"] = df2.apply(classify, axis=1)
つまずきやすい設定・注意点
axis=0(デフォルト)は列単位、axis=1は行単位で処理するという意味です。指定を間違えると意図しない結果になりますapplyは便利ですが、内部的にはPythonのループに近い動きをするため、大量データでは処理が遅くなりがちです
よくあるつまずきポイント・エラー対処
applyが遅くて処理が終わらない
❌Before:数十万行のデータに対して、単純な四則演算までapplyで書いてしまう
df["税込価格"] = df["価格"].apply(lambda p: p * 1.1)
私が10万行を超えるデータでこの書き方をしたとき、処理に想定以上の時間がかかり、「applyは何にでも使える便利な機能」という認識を改めることになりました。applyは柔軟な反面、内部で1行ずつPythonの関数を呼び出すため、単純な計算にはオーバーヘッドが大きいのです。
✅After:単純な四則演算はapplyを使わず、pandasのベクトル演算(列全体に対して直接計算する書き方)を使う
df["税込価格"] = df["価格"] * 1.1
実行時間を計測したところ、10万行のデータでapplyが数秒かかっていた処理が、ベクトル演算では一瞬で終わりました。
「単純な計算はベクトル演算、複雑な条件分岐はapply」という使い分けを意識すると、処理速度を大きく改善できます。
応用・一歩先の使い方
mapとの違いを理解する
似た機能にmapがあります。mapはSeriesの各値を、辞書や関数で置き換える処理に特化しています。
category_map = {"りんご": "果物", "みかん": "果物", "キャベツ": "野菜"}
df["カテゴリ"] = df["商品名"].map(category_map)
「対応表(辞書)に基づいて単純に置き換えたいだけ」ならmap、「条件分岐や計算を伴う」ならapply、という使い分けが基本です。
applymapの代わりにmapを使う(pandas 2.x系の変更点)
DataFrame全体の各要素に処理をかけたい場合、以前はapplymapが使われていましたが、pandas 2.1以降では非推奨となり、代わりにDataFrame.mapを使うことが推奨されています。
# pandas 2.1以降で推奨される書き方
df_numeric = df[["価格", "在庫"]]
result = df_numeric.map(lambda x: x * 2)
古い記事ではapplymapが紹介されていることが多いので、新しくコードを書く際はmapを使うようにしましょう。
まとめ
この記事のポイント
applyは列・行に対して任意の関数を適用できる柔軟な機能lambdaは名前のない一時的な関数を1行で定義する書き方- 単純な計算にはベクトル演算、複雑な条件分岐には
applyを使い分ける - 対応表による単純な置き換えには
mapが適している - pandas 2.x系では
applymapが非推奨になり、DataFrame.mapが推奨されている
次に読むべき記事
ここまででpandasの基本〜実践的な処理は一通り学べました。
最後は、Excelとpandas、それぞれの得意分野を整理した「Excelでの集計とpandasでの集計、業務で使い分けるポイント」で、実務での使い分けを確認しておきましょう。
タグ: Pandas, 中級者向け, 実践Tips