pandasでカテゴリ変数をダミー変数に変換(get_dummies)
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
を指定すると、デフォルトではデータ型dtype
がobject
(主に文字列)または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
でデータ型を指定できる。True
とFalse
はそれぞれ1
と0
とみなされるので、例えばint
を指定すると1
と0
で表される。
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_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 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
例のデータではBob
のSex
が欠損値NaN
で、ダミー変数化するとsex_female
もsex_male
もFalse
となる。このような場合に引数drop_first
をTrue
とすると、NaN
である(どちらにも該当しない)という情報が失われてしまうので注意。NaN
もダミー変数化するには次に紹介する引数dummy_na
を使う。
欠損値NaNもダミー変数化: 引数dummy_na
デフォルトでは欠損値NaN
は無視され、すべてのダミー変数列がFalse
となる。NaN
も一つのカテゴリーとしてダミー変数化したい場合は、引数dummy_na
をTrue
とする。
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
の場合、デフォルトではデータ型dtype
がobject
(主に文字列)または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()
でカテゴリを指定して対象の列をカテゴリ型に変換する。
- Categorical data — pandas 2.1.3 documentation
- pandas.Categorical — pandas 2.1.3 documentation
- Feature Request: allow user defined categories in get_dummies · Issue #22078 · pandas-dev/pandas
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_A
のstate
列には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