Pandas Series map()で列の要素を置換する方法【完全ガイド】

 

Pandasでデータ処理を行う際、列の値を別の値に変換・置換したい場面は非常によくあります。Seriesのmap()メソッドを使えば、辞書や関数を使って効率的に要素の置換ができます。この記事では、map()メソッドの使い方を基本から応用まで、実践的なサンプルコードとともに詳しく解説します。

基本的な準備とサンプルデータの作成

まず、この記事で使用するサンプルDataFrameを作成しましょう。

import pandas as pd
import numpy as np

# サンプルデータの作成
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
    'grade': ['A', 'B', 'A', 'C', 'B'],
    'gender': ['F', 'M', 'M', 'M', 'F'],
    'score': [85, 72, 90, 65, 78]
})

print(df)

このコードを実行すると、以下のようなDataFrameが作成されます:

      name grade gender  score
0    Alice     A      F     85
1      Bob     B      M     72
2  Charlie     A      M     90
3    David     C      M     65
4      Eve     B      F     78

map()メソッドの基本的な使い方

辞書を使った要素の置換

最もよく使われる方法は、辞書を使って値をマッピングすることです。

# 成績を数値に変換
grade_mapping = {'A': 4, 'B': 3, 'C': 2, 'D': 1}
df['grade_numeric'] = df['grade'].map(grade_mapping)
print(df[['grade', 'grade_numeric']])

この例では、文字の成績を対応する数値に変換しています。辞書のキーが元の値、バリューが変換後の値になります。

性別コードを日本語に変換

実用的な例として、性別コードを日本語に変換してみましょう。

# 性別を日本語に変換
gender_mapping = {'M': '男性', 'F': '女性'}
df['gender_jp'] = df['gender'].map(gender_mapping)
print(df[['gender', 'gender_jp']])

関数を使った要素の置換

ラムダ関数を使用

辞書だけでなく、関数を使って値を変換することもできます。

# スコアを評価に変換
df['evaluation'] = df['score'].map(lambda x: '優' if x >= 80 else '良' if x >= 70 else '可')
print(df[['score', 'evaluation']])

ラムダ関数を使うことで、複雑な条件分岐による変換も一行で記述できます。

定義済み関数を使用

より複雑なロジックの場合は、事前に関数を定義してから使用します。

# 複雑な変換ロジック
def categorize_score(score):
    if score >= 90:
        return 'S'
    elif score >= 80:
        return 'A'
    elif score >= 70:
        return 'B'
    else:
        return 'C'

df['category'] = df['score'].map(categorize_score)
print(df[['score', 'category']])

欠損値の処理

マッピング辞書にない値の処理

map()メソッドでは、マッピング辞書に存在しないキーはNaNになります。

# 不完全なマッピング辞書
incomplete_mapping = {'A': '優秀', 'B': '良好'}  # Cがない
df['incomplete_result'] = df['grade'].map(incomplete_mapping)
print(df[['grade', 'incomplete_result']])

fillna()と組み合わせたデフォルト値の設定

マッピングされなかった値にデフォルト値を設定できます。

# デフォルト値を設定
df['grade_with_default'] = df['grade'].map(incomplete_mapping).fillna('その他')
print(df[['grade', 'grade_with_default']])

Seriesを使ったマッピング

別のSeriesをマッピング辞書として使用

Seriesオブジェクトをマッピング辞書として使用することもできます。

# マッピング用のSeries作成
mapping_series = pd.Series([4, 3, 2], index=['A', 'B', 'C'])
print("マッピングSeries:")
print(mapping_series)

# Seriesを使ったマッピング
df['grade_from_series'] = df['grade'].map(mapping_series)
print(df[['grade', 'grade_from_series']])

実践的な応用例

カテゴリデータの数値化

機械学習でよく行うカテゴリデータの数値化の例です。

# 部門コードを数値に変換
departments = pd.Series(['IT', 'HR', 'IT', 'Finance', 'HR'])
dept_mapping = {'IT': 1, 'HR': 2, 'Finance': 3}
dept_numeric = departments.map(dept_mapping)
print("部門の数値化:")
print(pd.DataFrame({'部門': departments, '数値': dept_numeric}))

日付データの変換

日付関連の変換もmap()で行えます。

# 月名を数値に変換
months = pd.Series(['Jan', 'Feb', 'Mar', 'Jan', 'Mar'])
month_mapping = {
    'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4,
    'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8,
    'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12
}
month_numeric = months.map(month_mapping)
print("月の数値化:")
print(pd.DataFrame({'月名': months, '月番号': month_numeric}))

複数条件による複雑なマッピング

# 成績とスコアの組み合わせによる評価
def complex_evaluation(row):
    grade, score = row['grade'], row['score']
    if grade == 'A' and score >= 85:
        return '最優秀'
    elif grade == 'A' or score >= 80:
        return '優秀'
    elif grade == 'B' or score >= 70:
        return '良好'
    else:
        return '要改善'

# apply()と組み合わせて複雑な変換
df['complex_eval'] = df.apply(complex_evaluation, axis=1)
print(df[['grade', 'score', 'complex_eval']])

map()と類似メソッドの使い分け

map() vs replace() vs apply()

それぞれのメソッドの特徴と使い分けを説明します。

# map()の例
grade_map = {'A': 90, 'B': 80, 'C': 70}
mapped_result = df['grade'].map(grade_map)

# replace()の例
replaced_result = df['grade'].replace(grade_map)

# apply()の例
applied_result = df['grade'].apply(lambda x: grade_map.get(x, 0))

print("map()結果:")
print(mapped_result.head())
print("\nreplace()結果:")
print(replaced_result.head())
print("\napply()結果:")
print(applied_result.head())

パフォーマンスの比較

# パフォーマンス測定の例(大きなデータセット用)
large_series = pd.Series(['A', 'B', 'C'] * 10000)
mapping_dict = {'A': 1, 'B': 2, 'C': 3}

# 実際の測定は以下のように行います
# %timeit large_series.map(mapping_dict)      # 最も高速
# %timeit large_series.replace(mapping_dict)  # 中程度
# %timeit large_series.apply(lambda x: mapping_dict[x])  # 最も低速

エラーの回避とベストプラクティス

KeyErrorの回避

マッピング辞書にないキーでエラーが発生する場合の対処法:

def safe_mapping(value, mapping_dict, default=None):
    """安全なマッピング関数"""
    return mapping_dict.get(value, default)

# 安全なマッピングの例
safe_result = df['grade'].map(lambda x: safe_mapping(x, grade_mapping, 'Unknown'))
print("安全なマッピング結果:")
print(safe_result)

大量データでのメモリ効率

# メモリ効率的なマッピング
def memory_efficient_mapping(series, mapping_dict):
    """メモリ効率を考慮したマッピング"""
    # カテゴリ型に変換してからマッピング
    categorical_series = series.astype('category')
    return categorical_series.map(mapping_dict)

# 使用例(大量データの場合)
efficient_result = memory_efficient_mapping(df['grade'], grade_mapping)
print(f"データ型: {efficient_result.dtype}")

連鎖的なマッピング

複数段階の変換

複数のマッピングを連続して適用する場合:

# 第一段階:文字を数値に
stage1_mapping = {'A': 4, 'B': 3, 'C': 2}
stage1_result = df['grade'].map(stage1_mapping)

# 第二段階:数値を評価に
stage2_mapping = {4: '優秀', 3: '良好', 2: '普通'}
final_result = stage1_result.map(stage2_mapping)

print("連鎖マッピング結果:")
print(pd.DataFrame({
    '元の成績': df['grade'],
    '数値': stage1_result,
    '最終評価': final_result
}))

まとめ

Pandas Seriesのmap()メソッドは、列の要素を効率的に置換・変換するための強力なツールです。この記事で紹介した手法を活用することで、様々なデータ変換ニーズに対応できます。

主なポイント:

  • 辞書を使った簡単な値の置換が可能
  • ラムダ関数や定義済み関数で複雑な変換ロジックを実装
  • fillna()との組み合わせで欠損値処理
  • Seriesオブジェクトもマッピング辞書として使用可能
  • replace()apply()との使い分けが重要

データクリーニングや前処理において、map()メソッドは欠かせない機能です。用途に応じて適切な変換方法を選択し、効率的なデータ処理を実現しましょう。