注目キーワード
  1. Python
  2. コンペ

【図解】pandas mapとapplyの違いと使い分け|複数列・DataFrameでの完全ガイド

  • 2024年2月23日
  • 2025年9月8日
  • Python
  • 1602回
  • 0件

Pandasでデータ処理を行う際、mapapplyのどちらを使うべきか迷った経験はありませんか?この記事では、両者の明確な違いと具体的な使い分け方法を、豊富なコード例とともに解説します。

mapとapplyの違い(一覧表で比較)

まず最初に、mapapplyの基本的な違いを表形式で確認しましょう。

項目 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: 処理速度を向上させたい場合は?

以下の順序で検討してください:

  1. ベクトル化演算(最高速)
  2. map(辞書使用)
  3. apply
  4. 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全体の操作
  • ✅ カスタム関数の適用

実践的な判断フロー

  1. 辞書で値を変換したいmap
  2. 複数列を使う必要があるapply
  3. DataFrame全体を処理したいapply
  4. どちらでも可能だが速度重視map
  5. どちらでも可能だが可読性重視apply

この記事で紹介したテクニックを使いこなすことで、pandasでのデータ処理がより効率的になります。実際のプロジェクトでは、データの特性と処理の要件に応じて適切に使い分けることが重要です。

最新情報をチェックしよう!