note.nkmk.me

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

Date: 2018-04-11 / tags: Python, pandas, 機械学習

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

文字列でカテゴリー分けされた性別などのデータを、男を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ファイルはコチラ。

スポンサーリンク

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

第一引数datapanas.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の場合は、デフォルトではデータ型dtypeobject(おもに文字列)または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-sep>カテゴリー名となる。

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

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

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の場合、デフォルトではデータ型dtypeobject(おもに文字列)または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の列に対して処理して値を更新する場合は、以下のように元の列に代入すればOK。

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()による置換についての詳細は以下の記事を参照。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事