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

Modified: | Tags: Python, pandas, 機械学習

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

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

本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。例として以下のデータを使用する。説明のために列を追加している。

import pandas as pd

print(pd.__version__)
# 2.1.2

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

df['sex'] = ['female', float('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

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

pd.get_dummies()の第一引数dataには、Series、array-likeオブジェクト(リストやNumPy配列ndarrayなど)、および、DataFrameを指定できる。いずれの場合も新たなDataFrameが返される。

第一引数にSeries、array-likeオブジェクトを指定する場合

第一引数にSeriesまたはarray-likeオブジェクト(リストやNumPy配列ndarrayなど)を指定すると、カテゴリー名が列名になる。

print(pd.get_dummies(df['sex']))
#          female   male
# name                  
# Alice      True  False
# Bob       False  False
# Charlie   False   True
# Dave      False   True
# Ellen      True  False
# Frank     False   True

print(pd.get_dummies(['female', float('nan'), 'male', 'male', 'female', 'male']))
#    female   male
# 0    True  False
# 1   False  False
# 2   False   True
# 3   False   True
# 4    True  False
# 5   False   True

第一引数にDataFrameを指定する場合

第一引数にDataFrameを指定すると、デフォルトではデータ型dtypeobject(主に文字列)またはcategoryの列がすべてダミー変数化される。数値などの列もダミー変数化したい場合の設定については後述。

DataFrameを指定した場合の列名は元の列名_カテゴリー名となる。変更する設定は後述。

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

ダミー変数のデータ型を指定: 引数dtype

デフォルトではダミー変数はbool値(True, False)で表される。

引数dtypeでデータ型を指定できる。TrueFalseはそれぞれ10とみなされるので、例えばintを指定すると10で表される。

print(pd.get_dummies(df, dtype=int))
#          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個のダミー変数があればよいが、pd.get_dummies()ではデフォルトでk個のダミー変数に変換される。

引数drop_firstTrueとすると、最初のカテゴリーが除外されk-1個のダミー変数に変換される。

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

例のデータではBobSexが欠損値NaNで、ダミー変数化するとsex_femalesex_maleFalseとなる。このような場合に引数drop_firstTrueとすると、NaNである(どちらにも該当しない)という情報が失われてしまうので注意。NaNもダミー変数化するには次に紹介する引数dummy_naを使う。

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

デフォルトでは欠損値NaNは無視され、すべてのダミー変数列がFalseとなる。NaNも一つのカテゴリーとしてダミー変数化したい場合は、引数dummy_naTrueとする。

NaNを含まない列に対してもNaNのダミー変数列が追加され、すべての要素がFalseとなる。

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      True     False      False     False    False
# Bob       42     92     1     False     False      False     False     True
# Charlie   18     70     1     False     False      False      True    False
# Dave      68     70     0     False      True      False      True    False
# Ellen     24     88     2     False     False      False     False    False
# Frank     30     57     0      True     False      False      True    False

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

DataFrameの場合、デフォルトでは生成されるダミー変数の列名は元の列名_カテゴリー名となる。引数prefix, prefix_sepを指定すると、<prefix><prefix-sep>カテゴリー名に変更できる。

引数prefixは、文字列、リスト、辞書のいずれかで指定する。

文字列の場合はすべてのプレフィックスが共通になる。ダミー変数の列名をカテゴリー名だけにしたい場合はprefix, prefix_sepを空の文字列''に指定すればよい。

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

リストの場合は新しい列名を順番に指定する。辞書の場合は{元の列名: 新しい列名}とする。リストや辞書の要素数と変換対象の列の数が一致していないとエラーになるため、元の列名のままにしたい列に対しても値を指定する必要がある。

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

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

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

上述の通り、DataFrameの場合、デフォルトではデータ型dtypeobject(主に文字列)またはcategoryの列がダミー変数化される。

引数columnsにダミー変数化したい列の列名をリストで指定すると、数値やブールの列もダミー変数化できる。指定しない列は変換されない。

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

pd.get_dummies()で複数のデータを変換する場合の注意点

pd.get_dummies()で複数のデータを変換する場合は注意が必要。

以下の二つのDataFrameを例とする。

df = pd.read_csv('data/src/sample_pandas_normal.csv', index_col=0)
df_A, df_B = df[:3].copy(), df[3:].copy()

print(df_A)
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       42    CA     92
# Charlie   18    CA     70

print(df_B)
#        age state  point
# name                   
# Dave    68    TX     70
# Ellen   24    CA     88
# Frank   30    NY     57

それぞれをpd.get_dummies()で変換すると以下のようになる。各データに含まれる要素が異なるため、結果として生成される列が異なってしまう。

print(pd.get_dummies(df_A))
#          age  point  state_CA  state_NY
# name                                   
# Alice     24     64     False      True
# Bob       42     92      True     False
# Charlie   18     70      True     False

print(pd.get_dummies(df_B))
#        age  point  state_CA  state_NY  state_TX
# name                                           
# Dave    68     70     False     False      True
# Ellen   24     88      True     False     False
# Frank   30     57     False      True     False

ダミー変数列を共通にするにはpandasのカテゴリ型を利用する。pd.Categorical()でカテゴリを指定して対象の列をカテゴリ型に変換する。

categories = set(df_A['state'].tolist() + df_B['state'].tolist())
print(categories)
# {'NY', 'TX', 'CA'}

df_A['state'] = pd.Categorical(df_A['state'], categories)
df_B['state'] = pd.Categorical(df_B['state'], categories)

print(df_A['state'].dtypes)
# category

ここでは、それぞれの列をtolist()でリスト化し、連結したリストからset()で重複した要素を取り除いてカテゴリを生成している。

これに対してpd.get_dummies()を実行すると、指定したカテゴリに応じてダミー変数化される。df_Astate列にはTXが存在していないがstate_TX列が生成される。

print(pd.get_dummies(df_A))
#          age  point  state_NY  state_TX  state_CA
# name                                             
# Alice     24     64      True     False     False
# Bob       42     92     False     False      True
# Charlie   18     70     False     False      True

print(pd.get_dummies(df_B))
#        age  point  state_NY  state_TX  state_CA
# name                                           
# Dave    68     70     False      True     False
# Ellen   24     88     False     False      True
# Frank   30     57      True     False     False

上の例では少なくともどちらかのデータに存在する要素をカテゴリとしたが、任意の要素をカテゴリとして指定することも可能。カテゴリに該当しない要素はNaNとして扱われる。

categories = ['CA', 'NY']

df_A['state'] = pd.Categorical(df_A['state'], categories)
df_B['state'] = pd.Categorical(df_B['state'], categories)

print(df_A)
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       42    CA     92
# Charlie   18    CA     70

print(df_B)
#        age state  point
# name                   
# Dave    68   NaN     70
# Ellen   24    CA     88
# Frank   30    NY     57

print(pd.get_dummies(df_A))
#          age  point  state_CA  state_NY
# name                                   
# Alice     24     64     False      True
# Bob       42     92      True     False
# Charlie   18     70      True     False

print(pd.get_dummies(df_B))
#        age  point  state_CA  state_NY
# name                                 
# Dave    68     70     False     False
# Ellen   24     88      True     False
# Frank   30     57     False      True

関連カテゴリー

関連記事