pandas.Seriesのmapメソッドで列の要素を置換

pandas.Seriesのmap()は、引数に関数を渡すことでpandas.Seriesの各要素に関数を適用するメソッド。

map()の引数には辞書型dictを指定することもできて、その場合は要素の置換になる。 要素の置換を行うメソッドにはreplace()があるが、pandas.Seriesまたはpandas.DataFrameの列(=pandas.Series)のすべての要素を別の値に置換するのであれば、map()のほうが高速になる場合が多い。

ここでは、

要素の置換におけるmap()とreplace()の違い 速度比較

map()の活用例: 質的データを量的データに変換

について説明します。 例として以下のデータを使用します。

import pandas as pd

df = pd.read_csv('data/src/sample_pandas_normal.csv')

print(df)
#       name  age state  point
# 0    Alice   24    NY     64
# 1      Bob   42    CA     92
# 2  Charlie   18    CA     70
# 3     Dave   68    TX     70
# 4    Ellen   24    CA     88
# 5    Frank   30    NY     57

s = df['state']
print(s)
# 0    NY
# 1    CA
# 2    CA
# 3    TX
# 4    CA
# 5    NY
# Name: state, dtype: object

サンプルのcsvファイルはコチラ。

sample_pandas_normal.csv

要素の置換におけるmap()とreplace()の違い

map()の引数に辞書dict({key: value})を指定すると、keyと一致する要素がvalueに置き換えられる。

s_map_all = s.map({'NY': 'NewYork', 'CA': 'California', 'TX': 'Texas'})
print(s_map_all)
# 0       NewYork
# 1    California
# 2    California
# 3         Texas
# 4    California
# 5       NewYork
# Name: state, dtype: object

replace()の引数にも辞書を指定することが可能。pandas.Seriesのすべての要素に対して置換が行われる場合はreplace()と同様の結果となります。

s_replace_all = s.replace({'NY': 'NewYork', 'CA': 'California', 'TX': 'Texas'})
print(s_replace_all)
# 0       NewYork
# 1    California
# 2    California
# 3         Texas
# 4    California
# 5       NewYork
# Name: state, dtype: object

結果が異なるのは、辞書のkeyがpandas.Seriesのすべての要素の値を網羅していない場合。 map()では置換されない値がNaNとなってしまう。replace()では元の値のまま。

s_map = s.map({'NY': 'NewYork'})
print(s_map)
# 0    NewYork
# 1        NaN
# 2        NaN
# 3        NaN
# 4        NaN
# 5    NewYork
# Name: state, dtype: object

s_replace = s.replace({'NY': 'NewYork'})
print(s_replace)
# 0    NewYork
# 1         CA
# 2         CA
# 3         TX
# 4         CA
# 5    NewYork
# Name: state, dtype: object

map()とupdate()を組み合わせると置換されない要素を元の値のままにすることができます。ただし、update()を使うと元のオブジェクトが変更され、replace()で引数inplaceをTrueとするのと同じ動作となります。

s_copy = s.copy()
s_copy.update(s_copy.map({'NY': 'NewYork'}))
print(s_copy)
# 0    NewYork
# 1         CA
# 2         CA
# 3         TX
# 4         CA
# 5    NewYork
# Name: state, dtype: object

s_copy = s.copy()
s_copy.replace({'NY': 'NewYork'}, inplace=True)
print(s_copy)
# 0    NewYork
# 1         CA
# 2         CA
# 3         TX
# 4         CA
# 5    NewYork
# Name: state, dtype: object

速度比較

Jupyter Notebookの%timeitで簡易的な速度比較を行った。 すべての要素に対して置換が行われる場合はmap()のほうがreplace()よりも高速。

%timeit s.map({'NY': 'NewYork', 'CA': 'California', 'TX': 'Texas'})
# 345 µs ± 14 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit s.replace({'NY': 'NewYork', 'CA': 'California', 'TX': 'Texas'})
# 519 µs ± 15.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

update()を組み合わせるとmap()よりreplace()のほうが高速。

s_copy = s.copy()
%timeit s_copy.update(s_copy.map({'NY': 'NewYork'}))
# 643 µs ± 21.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

s_copy = s.copy()
%timeit s_copy.replace({'NY': 'NewYork'}, inplace=True)
# 230 µs ± 10 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

update()を使ってもmap()のほうが高速という報告もあり、元のpandas.Seriesのサイズ、置換を指定する辞書のサイズによって結果が異なる。

python - Using replace efficiently in pandas - Stack Overflow

特にreplace()は置換を指定する辞書のサイズによる変化が大きい。

s_copy = s.copy()
%timeit s_copy.update(s_copy.map({'NY': 'NewYork', 'CA': 'California', 'TX': 'Texas'}))
# 627 µs ± 10.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

s_copy = s.copy()
%timeit s_copy.replace({'NY': 'NewYork', 'CA': 'California', 'TX': 'Texas'}, inplace=True)
# 441 µs ± 22.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

小さいデータの置換処理を一度するだけであればどちらでも大差ないが、巨大なデータに対して同じような置換処理を繰り返し行うといった場合は速度が効いてくるので、実際に置換を行う条件でmap()とreplace()を試してみてからどちらを使うか決定するといいかもしれない。 すべての要素を別の値に置換するのであれば、map()のほうが高速になる場合が多い。 速度の計測については以下の記事を参照。

map()の活用例: 質的データを量的データに変換

map()を使う例として実際によくあるのが、質的データ(カテゴリデータ)の文字列を量的データの数値に変換する場合。 機械学習のデータとして使うときなどに、例のような地名や男女の区分(male, female)などの文字列を0, 1の数値に置き換える。

s_map_num = s.map({'NY': 0, 'CA': 1, 'TX': 2})
print(s_map_num)
# 0    0
# 1    1
# 2    1
# 3    2
# 4    1
# 5    0
# Name: state, dtype: int64

map()には元のオブジェクトを更新する引数inplaceがないので、pandas.DataFrameの列をmap()で置換する場合は、元の列に代入します。

df['state'] = df['state'].map({'NY': 0, 'CA': 1, 'TX': 2})
print(df)
#       name  age  state  point
# 0    Alice   24      0     64
# 1      Bob   42      1     92
# 2  Charlie   18      1     70
# 3     Dave   68      2     70
# 4    Ellen   24      1     88
# 5    Frank   30      0     57

print(df['state'].dtype)
# int64

なお、質的データ(カテゴリ変数)をダミー変数に変換するにはpandas.get_dummies()という関数があります。詳細は以下の記事を参照。

シェア

関連カテゴリー

Python pandas

pandas.DataFrameの行を条件で抽出するquery pandasで時系列データをリサンプリングするresample, asfreq pandasのピボットテーブルでカテゴリ毎の統計量などを算出 pandas.DataFrameをJSON文字列・ファイルに変換・保存(to_json) pandas.DataFrameの行番号、列番号を取得 pandasで特定の条件を満たす要素数をカウント(全体、行・列ごと) pandasでstack, unstack, pivotを使ってデータを整形 pandas.DataFrame, Seriesを連結するconcat pandas.DataFrameの行・列を指定して削除するdrop pandasで欠損値NaNを除外(削除)・置換(穴埋め)・抽出 pandas.DataFrameから特定の型dtypeの列を抽出(選択) pandasで日付・時間の列を処理(文字列変換、年月日抽出など) pandasの時系列データのタイムゾーンを処理(tz_convert, tz_localize) pandasで任意の位置の値を取得・変更するat, iat, loc, iloc 『Python Data Science Handbook』(英語の無料オンライン版あり)

Last Updated: 6/26/2019, 10:34:03 PM