pandasでカテゴリ変数をダミー変数に変換(get_dummies)

pandasでカテゴリ変数(カテゴリカルデータ、質的データ)をダミー変数に変換するには、pandas.get_dummies()関数を使います。

pandas.get_dummies — pandas 0.22.0 documentation

文字列でカテゴリー分けされた性別などのデータを、男を0, 女を1のように変換したり、多クラスの特徴量をone-hot表現に変換したりすることができます。機械学習の前処理として行うことが多い。 ここでは以下の内容について説明します。

pandas.get_dummies()の基本的な使い方 最初のカテゴリーを除外: 引数drop_first 欠損値NaNもダミー化: 引数dummy_na pandas.DataFrameのダミー変数の列名を指定: 引数prefix, prefix_sep pandas.DataFrameの列を指定して数値・ブール列もダミー化: 引数columns 各カテゴリー(水準)を任意の数値化: map()メソッド

例として以下のデータを使用します。説明のために列を追加しています。

import pandas as pd
import numpy as np

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

df['sex'] = ['female', np.nan, 'male', 'male', 'female', 'male']
df['rank'] = [2, 1, 1, 0, 2, 0]

print(df)
#          age state  point     sex  rank
# name                                   
# Alice     24    NY     64  female     2
# Bob       42    CA     92     NaN     1
# Charlie   18    CA     70    male     1
# Dave      68    TX     70    male     0
# Ellen     24    CA     88  female     2
# Frank     30    NY     57    male     0

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

sample_pandas_normal.csv

pandas.get_dummies()の基本的な使い方

第一引数dataにpanas.Series、配列(Pythonのリスト、NumPy配列ndarrayなど)、および、pandas.DataFrameを指定します。 いずれの場合もpandas.DataFrameの新たなオブジェクトが返される。元のオブジェクトを更新したい場合は、例えば以下のように元のオブジェクトに代入すればよい。

df = df.get_dummies(df)

引数にpandas.Series、配列を指定する場合
pandas.Series、配列(Pythonのリスト、NumPy配列ndarrayなど)の場合、カテゴリー名が列名になる。
print(pd.get_dummies(df['sex']))
#          female  male
# name                 
# Alice         1     0
# Bob           0     0
# Charlie       0     1
# Dave          0     1
# Ellen         1     0
# Frank         0     1

print(pd.get_dummies(['male', 1, 1, 2]))
#    1  2  male
# 0  0  0     1
# 1  1  0     0
# 2  1  0     0
# 3  0  1     0

print(pd.get_dummies(np.arange(6)))
#    0  1  2  3  4  5
# 0  1  0  0  0  0  0
# 1  0  1  0  0  0  0
# 2  0  0  1  0  0  0
# 3  0  0  0  1  0  0
# 4  0  0  0  0  1  0
# 5  0  0  0  0  0  1

配列(Pythonのリスト、NumPy配列ndarrayなど)は一次元配列である必要があります。二次元配列はエラーとなります。

# print(pd.get_dummies(np.arange(6).reshape((2, 3))))
# Exception: Data must be 1-dimensional

引数にpandas.DataFrameを指定する場合 pandas.DataFrameの場合は、デフォルトではデータ型dtypeがobject(おもに文字列)またはcategoryである列がすべてダミー変数化される。 数値(int, float)やブールboolの列は変換されず元のまま。数値やブールの列もダミー化したい場合の設定については後述。 pandas.DataFrameの場合の列名は元の列名_カテゴリー名となります。変更する設定は後述。

print(pd.get_dummies(df))
#          age  point  rank  state_CA  state_NY  state_TX  sex_female  sex_male
# name                                                                         
# Alice     24     64     2         0         1         0           1         0
# Bob       42     92     1         1         0         0           0         0
# Charlie   18     70     1         1         0         0           0         1
# Dave      68     70     0         0         0         1           0         1
# Ellen     24     88     2         1         0         0           1         0
# Frank     30     57     0         0         1         0           0         1

最初のカテゴリーを除外: 引数drop_first

k個のカテゴリーをダミー化する場合、k-1個のダミー変数があればよいが、get_dummies()関数ではデフォルトでk個のダミー変数に変換される。 引数drop_first=Trueとすると、最初のカテゴリーが除外されk-1個のダミー変数に変換される。

print(pd.get_dummies(df, drop_first=True))
#          age  point  rank  state_NY  state_TX  sex_male
# name                                                   
# Alice     24     64     2         1         0         0
# Bob       42     92     1         0         0         0
# Charlie   18     70     1         0         0         1
# Dave      68     70     0         0         1         1
# Ellen     24     88     2         0         0         0
# Frank     30     57     0         1         0         1

欠損値NaNもダミー化: 引数dummy_na

デフォルトでは欠損値NaNは除外して処理される。 NaNも一つのカテゴリーとしてダミー変数化したい場合は、引数dummy_na=Trueとします。 このとき、NaNを含まない列に対してもNaNのダミー変数が生成される。すべての要素が0となります。

print(pd.get_dummies(df, drop_first=True, dummy_na=True))
#          age  point  rank  state_NY  state_TX  state_nan  sex_male  sex_nan
# name                                                                       
# Alice     24     64     2         1         0          0         0        0
# Bob       42     92     1         0         0          0         0        1
# Charlie   18     70     1         0         0          0         1        0
# Dave      68     70     0         0         1          0         1        0
# Ellen     24     88     2         0         0          0         0        0
# Frank     30     57     0         1         0          0         1        0

DataFrameのダミー変数の列名を指定: 引数prefix, prefix_sep

pandas.DataFrameの場合、デフォルトでは生成されるダミー変数の列名は元の列名_カテゴリー名となります。 これを引数prefix, prefix_sepで変更できます。カテゴリー名となります。 引数prefixは、文字列、文字列のリスト、文字列の辞書のいずれかで指定します。 文字列の場合はすべてのプレフィックスが共通になる。ダミー変数の列名をカテゴリー名だけにしたい場合はprefix, prefix_sepを空の文字列''に指定すれば問題ありません。

print(pd.get_dummies(df, drop_first=True, prefix='', prefix_sep=''))
#          age  point  rank  NY  TX  male
# name                                   
# Alice     24     64     2   1   0     0
# Bob       42     92     1   0   0     0
# Charlie   18     70     1   0   0     1
# Dave      68     70     0   0   1     1
# Ellen     24     88     2   0   0     0
# Frank     30     57     0   1   0     1

リスト、辞書の場合は、元の列名のままにしたい列に対しても値を指定する必要があります。リスト、辞書の要素数とダミー化する列の数が一致していないとエラーになる。

print(pd.get_dummies(df, drop_first=True, prefix=['ST', 'sex'], prefix_sep='-'))
#          age  point  rank  ST-NY  ST-TX  sex-male
# name                                             
# Alice     24     64     2      1      0         0
# Bob       42     92     1      0      0         0
# Charlie   18     70     1      0      0         1
# Dave      68     70     0      0      1         1
# Ellen     24     88     2      0      0         0
# Frank     30     57     0      1      0         1

print(pd.get_dummies(df, drop_first=True, prefix={'state': 'ST', 'sex': 'sex'}, prefix_sep='-'))
#          age  point  rank  ST-NY  ST-TX  sex-male
# name                                             
# Alice     24     64     2      1      0         0
# Bob       42     92     1      0      0         0
# Charlie   18     70     1      0      0         1
# Dave      68     70     0      0      1         1
# Ellen     24     88     2      0      0         0
# Frank     30     57     0      1      0         1

DataFrameの列を指定して数値・ブール列もダミー化: 引数columns

上述の通り、pandas.DataFrameの場合、デフォルトではデータ型dtypeがobject(おもに文字列)またはcategoryの列のみがダミー化される。 引数columnsにダミー化したい列の列名をリストで指定すると、数値やブールの列もダミー化できます。指定しない列はダミー化されない。

print(pd.get_dummies(df, drop_first=True, columns=['sex', 'rank']))
#          age state  point  sex_male  rank_1  rank_2
# name                                               
# Alice     24    NY     64         0       0       1
# Bob       42    CA     92         0       1       0
# Charlie   18    CA     70         1       1       0
# Dave      68    TX     70         1       0       0
# Ellen     24    CA     88         0       0       1
# Frank     30    NY     57         1       0       0

大量の列をリストで指定するのが面倒な場合は、ダミー化したい数値やブールの列のデータ型をastype()でobjectに変換してしまうほうが楽かもしれない。 なお、列のデータ型をobjectに変換し元のオブジェクトを更新した場合は、その後その列を使って数値演算やブール演算を行う際に元の型に戻す必要があるので注意。

df['rank'] = df['rank'].astype(object)
print(pd.get_dummies(df, drop_first=True))
#          age  point  state_NY  state_TX  sex_male  rank_1  rank_2
# name                                                             
# Alice     24     64         1         0         0       0       1
# Bob       42     92         0         0         0       1       0
# Charlie   18     70         0         0         1       1       0
# Dave      68     70         0         1         1       0       0
# Ellen     24     88         0         0         0       0       1
# Frank     30     57         1         0         1       0       0

各カテゴリー(水準)を任意の数値化: map()メソッド

ダミー変数のように各カテゴリー(水準)に対して0 or 1の列を生成するのではなく、文字列で分類された各カテゴリーを任意の数値に置換したいときは、map()メソッドを使います。 引数に{元の値: 変換後の値}という辞書を指定します。

print(df['state'].map({'CA': 0, 'NY': 1, 'TX': 2}))
# name
# Alice      1
# Bob        0
# Charlie    0
# Dave       2
# Ellen      0
# Frank      1
# Name: state, dtype: int64

map()はpandas.Seriesのメソッド。pandas.DataFrameの列に対して処理して値を更新する場合は、以下のように元の列に代入すれば問題ありません。

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

map()による置換についての詳細は以下の記事を参照。

シェア

関連カテゴリー

Python pandas 機械学習

『Python Data Science Handbook』(英語の無料オンライン版あり) pandas.DataFrameの各列間の相関係数を算出、ヒートマップで可視化 Python, pandas, seabornでヒートマップを作成 pandasでJSON文字列・ファイルを読み込み(read_json) pandasで文字列と数値を相互変換、書式変更 pandas参考書『Pythonによるデータ分析入門』の注意点 pandasで欠損値NaNを前後の値から補間するinterpolate pandas.DataFrameの行番号、列番号を取得 pandasで窓関数を適用するrollingを使って移動平均などを算出 pandasで欠損値NaNを除外(削除)・置換(穴埋め)・抽出 pandasで数値を丸める(四捨五入、偶数への丸め) pandasでデータを行・列(縦・横)方向にずらすshift pandas.DataFrame, Seriesの先頭・末尾の行を返すheadとtail pandasのjson_normalizeで辞書のリストをDataFrameに変換 TensorFlowでMNISTを分類(ソフトマックス編)

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