Pandasでデータ処理を行う際、map
とapply
のどちらを使うべきか迷った経験はありませんか?この記事では、両者の明確な違いと具体的な使い分け方法を、豊富なコード例とともに解説します。
目次
mapとapplyの違い(一覧表で比較)
まず最初に、map
とapply
の基本的な違いを表形式で確認しましょう。
項目 | map | apply |
---|---|---|
対象 | Seriesのみ | Series・DataFrame両方 |
戻り値 | Series(元と同じ型) | Series・DataFrame・スカラー値 |
引数 | 辞書・Series・関数 | 関数のみ |
典型的な用途 | 値の置換・マッピング | 複雑な計算・集約処理 |
速度 | 辞書使用時は高速 | 関数適用時は柔軟だが重い |
NA値の処理 | NAはNA(変換されない) | 関数内で制御可能 |
💡 使い分けのポイント
- 辞書での値の置換 →
map
を使用 - 複数列にまたがる計算 →
apply
を使用 - DataFrame全体の処理 →
apply
を使用
pandas mapの基本的な使い方
map
は主にSeriesの各要素に対する値の変換・置換に特化した関数です。特に辞書を使った値のマッピングに威力を発揮します。
辞書を使った値の変換
import pandas as pd # DataFrameの作成 df = pd.DataFrame({ 'product': ['A001', 'B002', 'C003', 'A001', 'B002'], 'category': ['electronics', 'clothing', 'books', 'electronics', 'clothing'] }) # 商品コードを商品名に変換 product_map = { 'A001': 'スマートフォン', 'B002': 'Tシャツ', 'C003': 'プログラミング入門書' } df['product_name'] = df['product'].map(product_map) print(df)
product category product_name 0 A001 electronics スマートフォン 1 B002 clothing Tシャツ 2 C003 books プログラミング入門書 3 A001 electronics スマートフォン 4 B002 clothing Tシャツ
関数を使った変換
# 数値の変換 prices = pd.Series([100, 250, 380, 150]) # 税込価格(1.1倍)に変換 tax_included = prices.map(lambda x: int(x * 1.1)) print(tax_included)
0 110 1 275 2 418 3 165 dtype: int64
pandas applyの基本的な使い方
apply
は関数をSeries・DataFrameに適用する汎用的な関数で、複雑な処理や複数列を扱う計算に適しています。
Seriesに対するapply
# 文字列処理の例 names = pd.Series(['田中太郎', '佐藤花子', '鈴木次郎']) # 姓のみを抽出 surnames = names.apply(lambda x: x[:2]) print(surnames)
0 田中 1 佐藤 2 鈴木 dtype: object
DataFrameの行に対するapply
# 複数列を使った計算 df_sales = pd.DataFrame({ 'price': [1000, 1500, 2000], 'quantity': [5, 3, 8], 'discount_rate': [0.1, 0.05, 0.15] }) # 割引適用後の売上を計算 def calculate_sales(row): base_amount = row['price'] * row['quantity'] discount = base_amount * row['discount_rate'] return base_amount - discount df_sales['final_sales'] = df_sales.apply(calculate_sales, axis=1) print(df_sales)
price quantity discount_rate final_sales 0 1000 5 0.10 4500.0 1 1500 3 0.05 4275.0 2 2000 8 0.15 13600.0
複数列・DataFrameでの使い分け
複数列を扱う場合の具体的な使い分け方法を説明します。
複数列の条件分岐処理
# 顧客データの作成 df_customers = pd.DataFrame({ 'age': [25, 45, 35, 60, 28], 'income': [400, 800, 600, 1200, 350], 'has_children': [False, True, True, False, True] }) # 複数条件での顧客セグメント分類 def classify_customer(row): if row['age'] < 30: if row['income'] > 500: return '若年高所得' else: return '若年一般' elif row['age'] < 50: if row['has_children']: return '中年ファミリー' else: return '中年単身' else: return 'シニア' df_customers['segment'] = df_customers.apply(classify_customer, axis=1) print(df_customers)
age income has_children segment 0 25 400 False 若年一般 1 45 800 True 中年ファミリー 2 35 600 True 中年ファミリー 3 60 1200 False シニア 4 28 350 True 若年一般
DataFrameの列に対するapply
# 各列の統計情報を計算 df_numeric = pd.DataFrame({ 'A': [1, 2, 3, 4, 5], 'B': [10, 20, 30, 40, 50], 'C': [100, 200, 300, 400, 500] }) # 各列の変動係数(標準偏差/平均)を計算 cv = df_numeric.apply(lambda x: x.std() / x.mean(), axis=0) print("変動係数:") print(cv)
変動係数: A 0.527046 B 0.527046 C 0.527046 dtype: float64
速度とパフォーマンスの違い
実際の処理速度を比較してみましょう。
辞書マッピングの速度比較
import time import numpy as np # 大きなデータセットで比較 large_series = pd.Series(np.random.choice(['A', 'B', 'C'], 100000)) mapping_dict = {'A': 1, 'B': 2, 'C': 3} # mapの実行時間 start_time = time.time() result_map = large_series.map(mapping_dict) map_time = time.time() - start_time # applyの実行時間 start_time = time.time() result_apply = large_series.apply(lambda x: mapping_dict[x]) apply_time = time.time() - start_time print(f"map実行時間: {map_time:.4f}秒") print(f"apply実行時間: {apply_time:.4f}秒") print(f"mapの方が{apply_time/map_time:.1f}倍高速")
⚡ パフォーマンスのポイント
- 辞書マッピング:
map
が圧倒的に高速 - 複雑な関数:
apply
の方が柔軟で読みやすい - 大量データ: ベクトル化できる処理は
map
を優先
よくある疑問(mapとapplyのどちらを使うべき?)
Q1: 辞書での値の変換時、mapとapplyのどちらがいい?
A: map
を使用してください。辞書マッピングはmapの得意分野で、applyより高速です。
Q2: 複数列を参照する計算はどちらを使う?
A: apply
一択です。mapはSeries専用のため、複数列を同時に参照できません。
Q3: NA値がある場合の挙動の違いは?
# NA値の処理比較 series_with_na = pd.Series(['A', 'B', np.nan, 'C']) mapping = {'A': 1, 'B': 2, 'C': 3} print("mapの結果:") print(series_with_na.map(mapping)) print("\napplyの結果:") print(series_with_na.apply(lambda x: mapping.get(x, 'NA') if pd.notna(x) else 'NA'))
Q4: 処理速度を向上させたい場合は?
以下の順序で検討してください:
- ベクトル化演算(最高速)
- map(辞書使用)
- apply
- swifter(並列処理ライブラリ)
# swifterを使った高速化例 # pip install swifter が必要 import swifter # 通常のapply # result = df.apply(complex_function, axis=1) # swifterを使った高速化 # result = df.swifter.apply(complex_function, axis=1)
まとめ(おすすめの使い分け)
🎯 結論:こう使い分けよう
mapを使うべき場面
- ✅ 辞書・Seriesを使った値の置換
- ✅ カテゴリ変数の変換
- ✅ 単純な1対1のマッピング
- ✅ 処理速度を重視する場合
applyを使うべき場面
- ✅ 複数列を参照する計算
- ✅ 複雑な条件分岐処理
- ✅ DataFrame全体の操作
- ✅ カスタム関数の適用
実践的な判断フロー
- 辞書で値を変換したい →
map
- 複数列を使う必要がある →
apply
- DataFrame全体を処理したい →
apply
- どちらでも可能だが速度重視 →
map
- どちらでも可能だが可読性重視 →
apply
この記事で紹介したテクニックを使いこなすことで、pandasでのデータ処理がより効率的になります。実際のプロジェクトでは、データの特性と処理の要件に応じて適切に使い分けることが重要です。