pandas map()の使い方|辞書で値を変換・新しい列を作る方法を初心者向けに解説

CSVを読み込んだあと、列の値が 12AB のようなコードで入っていて、「この数字や記号が何を意味しているのか分かりにくい」と感じることがあります。

たとえば、次のようなデータです。

gender_code member_rank 意味
1 A 男性・通常会員
2 B 女性・優良会員
3 D 対応表にまだ登録していないコード

このまま value_counts()groupby() で集計することもできますが、結果が 1A のままだと読み取りにくくなります。

そこで使いやすいのが、Pandasの map() です。
map() は、1列の値を、辞書などの対応表に従って別の値へ変換したいときに使います。

この記事では、pandas map()の使い方を、辞書で値を変換する基本から、新しい列を作る方法、辞書にない値が NaN になる注意点まで、初心者向けに整理します。

まず結論:map()は「対応表で1列を変換する」ときに使う

結論
pandasの map() は、DataFrameの1列に入っている値を、辞書などの対応表に従って別の値へ変換したいときに使います。
たとえば、1男性2女性A通常会員 のように、コード値を人が読めるラベルへ変換するときに便利です。

この記事では、まず辞書を使った基本形に絞って説明します。
難しい関数処理や速度比較には深入りせず、CSVを読み込んだあとに実際によく使う前処理として、map() の使いどころを整理します。

この記事でわかること

  • map() がどんな場面で役立つか
  • 辞書を使って値を変換する基本
  • 数値コードや文字列コードをラベルに変換する方法
  • map() で新しい列を作る方法
  • 辞書にない値が NaN になる理由と確認方法
  • map()replace()astype()merge() の違い
  • 集計前の前処理として map() を使う流れ

Pandas DataFrame入門シリーズでの位置づけ

map() は、DataFrameを集計・可視化する前に、値を読みやすく整えるための前処理でよく使います。

流れとしては、次の位置づけです。

流れ よく使う処理 役割
読み込み read_csv() CSVをDataFrameとして読み込む
確認 head() / info() データの中身や型を確認する
値の確認 value_counts() どんな値が入っているか確認する
値の変換 map() / replace() コード値や表記ゆれを整える
欠損値処理 fillna() 足りない値を補う
型変換 astype() 数値・文字列などの型を整える
集計 groupby() 整えた列を使って集計する

DataFrameの基本から確認したい場合は、Pandas DataFrame入門 もあわせて確認すると流れがつかみやすくなります。

map()はどんな場面で使うのか

結論からいうと、map()1列の値を、対応表に従って別の値へ変換したいときに使います。

たとえば、次のような変換です。

変換前 変換後
1 男性
2 女性
A 通常会員
B 優良会員
C VIP

map() は、特に次のような場面で便利です。

  • 数値コードをわかりやすいラベルに変換したい
  • ABC のようなランクコードを名前に変えたい
  • 既存列をもとに、新しい説明用の列を作りたい
  • groupby() やグラフ化の前に、集計結果を読みやすくしたい

ここで大事なのは、map() は基本的に DataFrame全体ではなく、1列、つまりSeriesに使うという点です。

map()と似た機能の使い分け

Pandasには、値を変える処理がいくつかあります。
ここで先に整理しておくと、map() を使う場面がわかりやすくなります。

やりたいこと 向いている方法 初心者向けの判断基準
1列の値を対応表どおりに変換したい map() 1 → 男性A → 通常会員 コード値をラベルに変えたいとき
表記ゆれを置換したい replace() Tokyotokyo東京 にそろえる 既存値の表記をそろえたいとき
欠損値を埋めたい fillna() NaN → 未分類 足りない値を補いたいとき
データ型を変えたい astype() 文字列の "100" を数値の 100 にする 値の意味ではなく型を変えたいとき
別DataFrameの対応表と結合したい merge() 商品マスタと売上データを結合する 対応表が別の表としてあるとき
複雑な条件や関数を使いたい apply() 複数条件で判定する 単純な対応表では足りないとき

この記事では、まず初心者が使いやすい 辞書を使った map() に絞って説明します。

表記ゆれの置換を詳しく知りたい場合は、pandas replace()の使い方 を参考にしてください。
型変換を確認したい場合は、pandas astype()の使い方 が近い内容です。

サンプルデータを作成する

ここでは、会員データを例にします。

gender_code には性別コード、member_rank には会員ランクのコードが入っているとします。
また、あえて対応表にない値も入れて、map() でよくあるつまずきを確認できるようにします。

import pandas as pd

data = {
    "customer_id": [101, 102, 103, 104, 105, 106],
    "gender_code": [1, 2, 1, 3, 2, 1],
    "member_rank": ["A", "B", "C", "A", "D", "B"],
    "purchase_amount": [1200, 3500, 5800, 900, 1500, 4200]
}

df = pd.DataFrame(data)
df
customer_id gender_code member_rank purchase_amount
0 101 1 A 1200
1 102 2 B 3500
2 103 1 C 5800
3 104 3 A 900
4 105 2 D 1500
5 106 1 B 4200

このデータでは、gender_code12member_rankAB は、そのままだと意味が伝わりにくい状態です。

列名 今の状態 変換したい内容
gender_code 123 男性女性、未対応など
member_rank ABCD 通常会員優良会員VIP、未分類など

このようなときに、map() で対応表を使って変換します。

変換前に値の種類を確認する

map() を使う前に、まずどんな値が入っているかを確認しておくと安全です。

特に、辞書にない値があると NaN になることがあるため、変換前に value_counts() で確認しておくと失敗に気づきやすくなります。

print("gender_code の値の種類")
display(df["gender_code"].value_counts(dropna=False))

print("member_rank の値の種類")
display(df["member_rank"].value_counts(dropna=False))

gender_code の値の種類

count
1 3
2 2
3 1

member_rank の値の種類

count
A 2
B 2
C 1
D 1

ここで、gender_code には 123 があり、member_rank には ABCD があることがわかります。

この確認をせずに変換すると、「辞書に入れ忘れた値」があとから NaN として出てきて、原因がわかりにくくなることがあります。

value_counts() の基本は、pandas value_counts()の使い方 でも詳しく解説しています。

辞書を使って数値コードをラベルに変換する

まずは、gender_code12 を、それぞれ 男性女性 に変換します。

map() では、次のように「変換前の値」と「変換後の値」を辞書で用意します。

gender_map = {
    1: "男性",
    2: "女性"
}

df["gender_code"].map(gender_map)
gender_code
0 男性
1 女性
2 男性
3 NaN
4 女性
5 男性

結果を見ると、1男性2女性 に変換されています。

一方で、3 は辞書に含まれていないため、NaN になっています。
ここが map() で初心者がつまずきやすいポイントです。

元の値 辞書にあるか map()後の値
1 ある 男性
2 ある 女性
3 ない NaN

NaN は必ずしもエラーではありません。
「対応表にない値があった」というサインとして確認することが大切です。

map()で新しい列を作る

初心者のうちは、元の列をいきなり上書きするより、新しい列として追加するほうが安全です。

たとえば、gender_code はそのまま残し、変換後の値を gender_label という新しい列に入れます。

df["gender_label"] = df["gender_code"].map(gender_map)
df
customer_id gender_code member_rank purchase_amount gender_label
0 101 1 A 1200 男性
1 102 2 B 3500 女性
2 103 1 C 5800 男性
3 104 3 A 900 NaN
4 105 2 D 1500 女性
5 106 1 B 4200 男性

新しい列に入れると、変換前と変換後を横に並べて確認できます。

方法 元データを残せるか 初心者におすすめか 確認しやすさ
既存列を上書きする 残らない 慣れてから 変換前を確認しにくい
新しい列を追加する 残る おすすめ 変換前後を比べやすい

上書き自体が悪いわけではありません。
ただし、最初は gender_label のような新しい列を作るほうが、ミスに気づきやすくなります。

新しい列の作り方を広く確認したい場合は、pandasで新しい列を追加する方法 も参考になります。

辞書にない値がNaNになる例

map() では、辞書にない値は元の値のまま残るのではなく、NaN になることがあります。

この性質は便利でもあります。
なぜなら、「対応表に入っていない値がある」と気づけるからです。

print("gender_label の欠損数")
display(df["gender_label"].isnull().sum())

print("gender_label の値の種類")
display(df["gender_label"].value_counts(dropna=False))

gender_label の欠損数

np.int64(1)

gender_label の値の種類

count
男性 3
女性 2
NaN 1

この結果から、gender_labelNaN があることが確認できます。

今回のサンプルでは、gender_code3 を辞書に入れていないため、NaN になっています。
つまり、3 は「欠損値そのもの」ではなく、対応表にまだ登録していないコードとして扱います。

このように、map() 後は次の確認をすると安心です。

  • isnull().sum()NaN の数を確認する
  • value_counts(dropna=False) で変換後の値を確認する
  • 必要に応じて、辞書に値を追加するか、fillna() で補う

欠損値の確認や考え方は、Pandas info()とdescribe()の違いpandas fillna()の使い方 ともつながります。

fillna()で未対応コードを補う

辞書にない値を NaN のままにしたくない場合は、fillna() で補う方法があります。

今回は、gender_code3 を「未対応」として表示します。

df["gender_label"] = df["gender_code"].map(gender_map).fillna("未対応")
df
customer_id gender_code member_rank purchase_amount gender_label
0 101 1 A 1200 男性
1 102 2 B 3500 女性
2 103 1 C 5800 男性
3 104 3 A 900 未対応
4 105 2 D 1500 女性
5 106 1 B 4200 男性

fillna("未対応") を使うことで、辞書にない値をわかりやすく表示できました。

ただし、すべての NaN を機械的に「未対応」にしてよいとは限りません。
本当に未対応コードなのか、入力ミスなのか、欠損値なのかは、データの意味を確認して判断する必要があります。

文字列のコードをカテゴリ名に変換する

次に、member_rankABC を会員ランク名に変換します。

ここでも、元の member_rank を残し、変換後の値を rank_label という新しい列にします。

rank_map = {
    "A": "通常会員",
    "B": "優良会員",
    "C": "VIP"
}

df["rank_label"] = df["member_rank"].map(rank_map)
df
customer_id gender_code member_rank purchase_amount gender_label rank_label
0 101 1 A 1200 男性 通常会員
1 102 2 B 3500 女性 優良会員
2 103 1 C 5800 男性 VIP
3 104 3 A 900 未対応 通常会員
4 105 2 D 1500 女性 NaN
5 106 1 B 4200 男性 優良会員

ABC は変換できましたが、D は辞書にないため NaN になっています。

ここでも、変換前後を確認しておきます。

print("rank_label の値の種類")
display(df["rank_label"].value_counts(dropna=False))

print("rank_label の欠損数")
display(df["rank_label"].isnull().sum())

rank_label の値の種類

count
通常会員 2
優良会員 2
VIP 1
NaN 1

rank_label の欠損数

np.int64(1)

D を未分類として扱うなら、fillna("未分類") のように補うことができます。

df["rank_label"] = df["member_rank"].map(rank_map).fillna("未分類")
df
customer_id gender_code member_rank purchase_amount gender_label rank_label
0 101 1 A 1200 男性 通常会員
1 102 2 B 3500 女性 優良会員
2 103 1 C 5800 男性 VIP
3 104 3 A 900 未対応 通常会員
4 105 2 D 1500 女性 未分類
5 106 1 B 4200 男性 優良会員

これで、会員ランクのコードを読みやすいラベルに変換できました。

変換前の列 変換後の列 役割
gender_code gender_label 性別コードをラベルに変換
member_rank rank_label 会員ランクコードをラベルに変換

このように、map() は「コードの意味を人が読める形にする」前処理で役立ちます。

map()とreplace()の違い

迷ったら、コード値をラベルに変えるなら map()、表記ゆれを直すなら replace() と考えるとわかりやすいです。

map()replace() はどちらも値を変える処理なので、混同しやすいです。

大きく分けると、次のように考えるとわかりやすいです。

比較 map() replace()
主な使いどころ 対応表に従って1列を変換する 表記ゆれや特定の値を置換する
辞書にない値 NaN になりやすい 元の値が残ることが多い
1 → 男性A → 通常会員 tokyo → 東京なし → NaN
初心者向けの判断 コード値をラベルにしたいならこちら 表記ゆれを直したいならこちら

違いを確認するために、簡単な例を見てみます。

s = pd.Series([1, 2, 3])

mapping = {
    1: "男性",
    2: "女性"
}

print("map() の結果")
display(s.map(mapping))

print("replace() の結果")
display(s.replace(mapping))

map() の結果

0
0 男性
1 女性
2 NaN

replace() の結果

0
0 男性
1 女性
2 3

この例では、3 が辞書にありません。

  • map() では、3NaN になります
  • replace() では、3 がそのまま残ります

そのため、対応表にない値を見つけたい場合は map() が気づきやすいことがあります。
一方で、表記ゆれを一部だけ直したい場合は replace() のほうが自然なこともあります。

replace() の詳しい使い方は、pandas replace()の使い方 で確認できます。

map()とastype()・merge()・apply()の違い

map() と似て見える処理も、目的が違います。

map()とastype()の違い

astype() は、値の意味を変えるのではなく、データ型を変えるためのメソッドです。

たとえば、文字列の "100" を数値の 100 に変えるような場面では astype() を使います。
一方、1男性 に変えるように、値の意味をラベルへ変えるなら map() が向いています。

map()とmerge()の違い

小さな対応表を辞書で持てるなら、map() がシンプルです。

一方で、商品マスタ、店舗マスタ、顧客マスタのように、対応表が別のDataFrameとしてある場合は merge() が向いています。
本格的な表結合を学ぶ場合は、pandas mergeの使い方 が近い内容です。

map()とapply()の違い

単純な対応変換なら、まずは map() で十分なことが多いです。

apply() は、複雑な関数を使いたいときに便利ですが、この記事では深入りしません。
初心者のうちは、まず「辞書で対応変換するなら map()」と覚えると迷いにくくなります。

文字列の「1」と数値の1は別物として扱われる

map() では、辞書のキーと列の値が一致している必要があります。

たとえば、列の値が文字列の "1" なのに、辞書のキーが数値の 1 だと、うまく変換されないことがあります。

df_type = pd.DataFrame({
    "gender_code": ["1", "2", "1", "3"]
})

gender_map_number_key = {
    1: "男性",
    2: "女性"
}

df_type["label_ng"] = df_type["gender_code"].map(gender_map_number_key)
df_type
gender_code label_ng
0 1 NaN
1 2 NaN
2 1 NaN
3 3 NaN

gender_code は見た目は 12 ですが、実際には文字列です。
そのため、数値の 12 をキーにした辞書では対応できず、NaN になります。

この場合は、辞書のキーを文字列にそろえるか、列の型を変換します。

gender_map_string_key = {
    "1": "男性",
    "2": "女性"
}

df_type["label_ok"] = df_type["gender_code"].map(gender_map_string_key).fillna("未対応")
df_type
gender_code label_ng label_ok
0 1 NaN 男性
1 2 NaN 女性
2 1 NaN 男性
3 3 NaN 未対応

このように、map() でうまく変換できないときは、次の点を確認しましょう。

  • 列の値が数値なのか文字列なのか
  • 辞書のキーと列の値の型が合っているか
  • 辞書にない値が含まれていないか
  • 変換後に NaN が増えていないか

型の確認や変換は、pandas astype()の使い方 とつながります。

map()後に集計へ進む

map() は、変換して終わりではありません。
読みやすいラベルに整えたあと、groupby() や可視化につなげると、分析結果がわかりやすくなります。

たとえば、会員ランク別に購入金額を集計してみます。

rank_summary = (
    df.groupby("rank_label", as_index=False)["purchase_amount"]
      .sum()
      .rename(columns={"purchase_amount": "total_purchase_amount"})
)

rank_summary
rank_label total_purchase_amount
0 VIP 5800
1 優良会員 7700
2 未分類 1500
3 通常会員 2100

member_rankABCD のまま集計するより、通常会員優良会員VIP未分類 のように表示されたほうが、結果を読み取りやすくなります。

このように、map() は次の流れの中で役立ちます。

  1. CSVを読み込む
  2. head()info() で確認する
  3. value_counts() で値の種類を見る
  4. map() でコード値をラベルに変換する
  5. 必要に応じて fillna()astype() で整える
  6. groupby() やグラフで集計・可視化する

集計の基本は Pandas groupby×aggの使い方 に進むと理解しやすくなります。
グラフ化まで進めたい場合は、Matplotlib 棒グラフ入門 も関連します。

よくあるつまずきと確認ポイント

map() でうまく変換できないときは、次のポイントを確認してください。

つまずき 原因になりやすいこと 確認方法
変換後にNaNが出る 辞書にない値がある value_counts(dropna=False)
すべてNaNになる 値の型と辞書のキーの型が違う info()astype()
元の値を残したい 既存列を上書きしている 新しい列に追加する
表記ゆれ修正をしたい map()よりreplace()が向く場合がある 変換目的を確認する
別表の情報を付けたい map()よりmerge()が向く場合がある 対応表がDataFrameか確認する

特に大切なのは、変換前と変換後の確認です。
map() のコードだけを見るのではなく、変換前後の表を見比べるとミスに気づきやすくなります。

まとめ

この記事では、pandas map() の使い方を、辞書で値を変換する前処理として解説しました。

重要なポイントは、次のとおりです。

  • map() は、1列の値を対応表に従って変換するときに使う
  • 数値コードや文字列コードを、読みやすいラベルへ変換できる
  • 初心者のうちは、元の列を上書きせず、新しい列として追加すると安全
  • 辞書にない値は NaN になりやすい
  • NaN が出たら、エラーと決めつけず、対応表にない値があるサインとして確認する
  • map() 前後では、value_counts()isnull().sum() で確認するとよい
  • 表記ゆれ修正は replace()、型変換は astype()、別表との結合は merge() と使い分ける
  • map() で値を整えると、groupby() やグラフ化の結果が読みやすくなる

map() は派手な機能ではありませんが、CSVを読み込んだあとに「コード値を人が読める形に整える」ための大切な前処理です。
まずは、対応表で1列を変換するコード値を辞書でラベルに変換するという使い方から覚えておくと、DataFrameの集計や可視化へ進みやすくなります。

次に読みたい関連記事

この記事の内容は、次の記事とつながっています。

▲ ページトップへ戻る

pandasのmap()は何をするメソッドですか?

map() は、Series、つまりDataFrameの1列の値を、辞書や関数などに従って別の値へ変換するメソッドです。
初心者向けには、まず「1列のコード値を対応表でラベルに変換する方法」と考えるとわかりやすいです。

map()とreplace()は何が違いますか?

map() は、対応表に従って1列を変換したいときに向いています。
replace() は、表記ゆれや特定の値を置換したいときに向いています。
たとえば、1 → 男性2 → 女性 のようなコード変換なら map() が自然です。
一方、tokyoTokyoTOKYO を 東京 にそろえるような表記ゆれ修正なら replace() が向いています。

map()で辞書にない値がNaNになるのはなぜですか?

map() は、辞書にあるキーを使って値を変換します。
そのため、辞書にない値は対応先が見つからず、NaN になることがあります。
これはエラーとは限らず、「対応表に登録していない値がある」というサインです。
value_counts(dropna=False) や isnull().sum() で確認しましょう。

map()で新しい列を作るにはどうすればよいですか?

次のように、変換結果を新しい列に代入します。
df["gender_label"] = df["gender_code"].map(gender_map)
初心者のうちは、元の列を上書きするより、新しい列を作って変換前後を確認する方法がおすすめです。

数値の1と文字列の”1″でmap()の結果は変わりますか?

変わることがあります。
map() では、列の値と辞書のキーが一致している必要があります。
列の値が文字列の "1" なら、辞書のキーも "1" にする必要があります。
数値の 1 をキーにした辞書では対応できず、NaN になることがあります。

map()とastype()は何が違いますか?

map() は、値の意味を別の値へ変換するために使います。
astype() は、データ型を変えるために使います。
たとえば、1 → 男性 は map()"100" → 100 のような型変換は astype() と考えるとわかりやすいです。

map()とmerge()はどう使い分けますか?

小さな対応表を辞書で書けるなら、map() がシンプルです。
一方、対応表が別のDataFrameとしてある場合や、複数列をもとに結合したい場合は merge() が向いています。

map()したあとに結果を確認するにはどうすればよいですか?

次のような方法で確認できます。
df.head() で変換前後の列を確認する
value_counts(dropna=False) で変換後の値の種類を確認する
isnull().sum() で NaN の数を確認する
map() は変換して終わりではなく、変換後の確認までセットで行うと安全です。

コメント

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