Python | データ処理:lambda と組み合わせ

Python
スポンサーリンク

概要(lambdaは「その場で小さな関数」を作り、データ処理を短く書くための道具)

lambda(無名関数)は、名前を付けずに1行で小さな関数を作る仕組みです。短い変換・条件分岐・並べ替えのキー指定などを“その場で”書けるので、前処理や集計のコードを簡潔にできます。コツは「短く・単機能・副作用なし」に徹すること。複雑になりそうならdefで関数名を付けて可読性を優先します。


基本(lambdaの構文と「使いどころ」を押さえる)

構文と最小例

lambdaの形は「lambda 引数: 式」。式の評価結果が“戻り値”になります。

double = lambda x: x * 2
print(double(5))  # 10

# 引数が複数でもOK
add = lambda a, b: a + b
print(add(3, 4))  # 7

# 条件分岐も1行で書ける
label = lambda s: "pass" if s >= 60 else "fail"
print(label(70))  # pass
Python

使いどころの指針

  • 一時的な小さな処理: 並び替えのキー、軽い変換、簡潔な条件分岐。
  • 関数名が不要な場面: その場限りで読み捨てる処理。
  • 複雑になりそうならdefへ退避: 2行以上の処理、複雑な分岐、例外処理が必要な場合は関数化して名前を付ける。

組み合わせ(組み込み関数・pandasと合わせて実用に落とす)

組み込み関数との組み合わせ(sorted/map/filter/reduce)

# 並び替え(sortedのkey)
users = [{"name": "Taro", "age": 25}, {"name": "Hanako", "age": 20}]
by_age = sorted(users, key=lambda u: u["age"])
by_name_lower = sorted(users, key=lambda u: u["name"].lower())

# 要素変換(map)
nums = [1, 2, 3]
squared = list(map(lambda x: x**2, nums))  # [1, 4, 9]

# 条件抽出(filter)
adults = list(filter(lambda u: u["age"] >= 21, users))  # [{'name': 'Taro', 'age': 25}]

# 集約(reduce)
from functools import reduce
total = reduce(lambda acc, x: acc + x, nums, 0)  # 6
Python

pandasとの組み合わせ(Series.map/apply、DataFrame.apply/assign)

import pandas as pd

df = pd.DataFrame({"name": ["  Taro", "HANAKO  "], "score": [85, 92]})

# 1列の要素変換(Series.map/Series.apply)
df["name_clean"] = df["name"].map(lambda s: s.strip().title())

# 行ごとの複合ロジック(DataFrame.apply axis=1)
df["label"] = df.apply(lambda r: f"{r['name_clean']}({r['score']})", axis=1)

# 連鎖的な列追加(assignで読みやすく)
out = (
    df.assign(
        name_clean=lambda d: d["name"].map(lambda s: s.strip().title()),
        passed=lambda d: d["score"].map(lambda x: x >= 60),
    )
)
Python

groupbyと組み合わせ(グループ内変換・指標作成)

gdf = pd.DataFrame({"team": ["A","A","B"], "x": [10, 12, 8]})
# グループ内で標準化(transformを優先)
gdf["z"] = gdf.groupby("team")["x"].transform(lambda s: (s - s.mean()) / s.std(ddof=0))
Python

グループ集計・変換はapplyよりagg/transformの方が表現力と速度で有利です。lambdaは“中の小さな式”として添える感覚で使います。


実践例(前処理・キー指定・新列作成・安全な条件分岐)

前処理を短くまとめる(空白・大小・None対策)

df = pd.DataFrame({"email": [" Taro@Example.com ", None]})
df["email_norm"] = df["email"].map(lambda s: (s or "").strip().lower())
Python

並び替えキーで自然順(辞書やタプルもOK)

products = pd.DataFrame({"name": ["A-2", "A-10", "A-1"]})
# 末尾数字でソート(キーを抽出するlambda)
out = products.sort_values("name", key=lambda s: s.str.extract(r"(\d+)", expand=False).astype(int))
Python

複数列を組み合わせたラベル生成

df = pd.DataFrame({"first": ["taro", None], "last": ["yamada", "suzuki"]})
df["full"] = df.apply(lambda r: ("{} {}".format((r["first"] or "").strip().title(),
                                               (r["last"] or "").strip().title())).strip() or "Unknown", axis=1)
Python

安全な条件分岐(ゼロ割・欠損への防御)

df = pd.DataFrame({"new": [30, 0], "active": [100, 0]})
df["rate"] = df.apply(lambda r: (r["new"] / r["active"]) if r["active"] else 0.0, axis=1)
Python

重要ポイントの深掘り(可読性・性能・引数と外部状態・例外)

可読性を最優先にする

lambdaは短いからこそ強い。1行で収まらない、複数ステップの処理、分岐が長いときはdefで関数名を付けて意味を明示します。レビューや保守が圧倒的に楽になります。

ベクトル化が可能ならそちらを選ぶ

pandasの列演算やstrアクセサ、NumPyの関数はlambda+applyより高速です。まず「列演算で書けるか」を検討し、どうしても行単位の複雑な組み立てが必要な箇所にだけlambdaを使います。

外部変数の取り込み(クロージャ)を理解して使う

threshold = 70
df["flag"] = df["score"].map(lambda x: x >= threshold)  # 外のthresholdを捕まえる
Python

関数の外にある値を中で使えます。動的に変えたい場合は、引数で渡す関数を定義(def)しておくと意図が明確です。

例外と欠損の扱いを先に決める

lambdaはtry/exceptを書きづらいので、前処理で欠損を埋める(fillna)、型を揃える(astype)、分母ゼロの防御を入れるなど“安全策”を事前に施します。必要ならdefで例外処理を含めた関数にします。


つまずき対策(NaNでdtypeが落ちる・チェーン代入・過度なlambda)

NaNが混じるとdtypeがobjectになりがち

数値演算は、先にfillna(0)やastypeで型を固定してからlambdaを適用します。日時はto_datetimeで早めに変換しておくと安全です。

チェーン代入は避け、locで一発指定

# 悪い例(コピーへ代入の恐れ)
# df[df["score"] >= 60]["grade"] = "A"

# 良い例
df.loc[df["score"] >= 60, "grade"] = "A"
Python

lambdaで作ったSeriesを代入するときも、必ずlocで対象行・列を一発指定します。

“なんでもlambda”は禁物

並び替えのkey、map、短いapply以外で乱用すると読みにくくなります。関数に名前を付ける(def)・列演算へ置き換える・groupbyのagg/transformへ寄せる、を常に検討しましょう。


まとめ(lambdaは“短い一時関数”。pandasではmap/applyと組み合わせ、可読性と性能を両立)

lambdaは、その場で小さな関数を作るための道具です。組み込み関数(sorted/map/filter/reduce)やpandasのSeries.map/DataFrame.apply/assign/transformと組み合わせると、前処理・並び替え・新列作成を短く書けます。可読性を最優先にし、ベクトル化できる箇所は列演算へ寄せる。欠損・型・ゼロ割などの安全策を事前に施し、複雑化したら迷わずdefへ。これを徹底すれば、初心者でも“短く、正確に、速く”、気持ちのいいデータ処理が書けるようになります。

タイトルとURLをコピーしました