pandasのget_dummies()は使えない
特徴量中のカテゴリ変数をダミー変数化する際、pandas
の get_dummies()
はとってもお手軽で便利なんだけど、
import pandas as pd
df1 = pd.DataFrame([[1,'yukino',3,'f',4],[2,'teio',4,'m',3],[3,'nature',4]], columns=['id','name','age','sex','d'])
df1
id | name | age | sex | d | |
---|---|---|---|---|---|
0 | 1 | yukino | 3 | f | 4.0 |
1 | 2 | teio | 4 | m | 3.0 |
2 | 3 | nature | 4 | None | NaN |
pd.get_dummies(df1) # すべてのobject型をdummy化
id | age | d | name_nature | name_teio | name_yukino | sex_f | sex_m | |
---|---|---|---|---|---|---|---|---|
0 | 1 | 3 | 4.0 | 0 | 0 | 1 | 1 | 0 |
1 | 2 | 4 | 3.0 | 0 | 1 | 0 | 0 | 1 |
2 | 3 | 4 | NaN | 1 | 0 | 0 | 0 | 0 |
pd.get_dummies(df1, columns=['sex']) # dummy化するカラムを指定
id | name | age | d | sex_f | sex_m | |
---|---|---|---|---|---|---|
0 | 1 | yukino | 3 | 4.0 | 1 | 0 |
1 | 2 | teio | 4 | 3.0 | 0 | 1 |
2 | 3 | nature | 4 | NaN | 0 | 0 |
pd.get_dummies(df1, columns=['sex'], drop_first=True) # firstが固定じゃないのでデータによってdropされるカテゴリ変数が変動する
id | name | age | d | sex_m | |
---|---|---|---|---|---|
0 | 1 | yukino | 3 | 4.0 | 0 |
1 | 2 | teio | 4 | 3.0 | 1 |
2 | 3 | nature | 4 | NaN | 0 |
pd.get_dummies(df1, columns=['sex'], dummy_na=True) # NaNを1つのカテゴリ変数とみなしてdummy化
| |id |name |age |d |sex_f |sex_m |sex_nan
|--|--|--|--|--|--|--|--|--|
|0 |1 |yukino |3 |4.0 |1 |0 |0
|1 |2 |teio |4 |3.0 |0 |1 |0
|2 |3 |nature |4 |NaN |0 |0 |1
機械学習ではデータが学習、テスト、CV、ホールドアウトセット、評価といった目的のために分割したり、されたりしているのが一般的。このため分割とdummy変数化のタイミングによっては次の問題が発生する。
- 登場していないカテゴリ変数がdummy化されない
-
drop_first=True
によりdropされるカテゴリ変数が登場順により変動する
2点目はdrop_first
しないことでまだなんとか防止できるにしても(線形依存性を排除するためにあとで手動でdropするとして)、問題は1点目。
例えばdf1とは別のデータセット、df2があった時、
df2 = pd.DataFrame([[3,'palmer',5,'m',1],[4,'legacy',4,'s',3]], columns=df1.columns)
df2
id | name | age | sex | d | |
---|---|---|---|---|---|
0 | 3 | palmer | 5 | m | 1 |
1 | 4 | legacy | 4 | s | 3 |
pd.get_dummies(df2, columns=['sex'])
id | name | age | d | sex_m | sex_s | |
---|---|---|---|---|---|---|
0 | 3 | palmer | 5 | 1 | 1 | 0 |
1 | 4 | legacy | 4 | 3 | 0 | 1 |
df1とdf2で持ってる特徴量が変わってしまうのでいろいろと困ったことになる。というか致命的。
使えない。
そんな風に考えていた時期が以下略
そうは言ってもなんとか使えないものか。他にいいやり方も見つからないし。
そこで
を参考に、
possible_categories = ['m','f','s']
df1['sex'] = df1['sex'].astype('category', categories=possible_categories)
pd.get_dummies(df1, columns=['sex'])
これでいいんですね。
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-159-a2d4da627942> in <module>
1 possible_categories = ['m','f','s']
----> 2 df1['sex'] = df1['sex'].astype('category', categories=possible_categories)
3 pd.get_dummies(df1, columns=['sex'])
~\Anaconda3\lib\site-packages\pandas\core\generic.py in astype(self, dtype, copy, errors, **kwargs)
5880 # else, only a single dtype is given
5881 new_data = self._data.astype(
-> 5882 dtype=dtype, copy=copy, errors=errors, **kwargs
5883 )
5884 return self._constructor(new_data).__finalize__(self)
~\Anaconda3\lib\site-packages\pandas\core\internals\managers.py in astype(self, dtype, **kwargs)
579
580 def astype(self, dtype, **kwargs):
--> 581 return self.apply("astype", dtype=dtype, **kwargs)
582
583 def convert(self, **kwargs):
~\Anaconda3\lib\site-packages\pandas\core\internals\managers.py in apply(self, f, axes, filter, do_integrity_check, consolidate, **kwargs)
436 kwargs[k] = obj.reindex(b_items, axis=axis, copy=align_copy)
437
--> 438 applied = getattr(b, f)(**kwargs)
439 result_blocks = _extend_blocks(applied, result_blocks)
440
~\Anaconda3\lib\site-packages\pandas\core\internals\blocks.py in astype(self, dtype, copy, errors, values, **kwargs)
557
558 def astype(self, dtype, copy=False, errors="raise", values=None, **kwargs):
--> 559 return self._astype(dtype, copy=copy, errors=errors, values=values, **kwargs)
560
561 def _astype(self, dtype, copy=False, errors="raise", values=None, **kwargs):
~\Anaconda3\lib\site-packages\pandas\core\internals\blocks.py in _astype(self, dtype, copy, errors, values, **kwargs)
598 if deprecated_arg in kwargs:
599 raise ValueError(
--> 600 "Got an unexpected argument: {}".format(deprecated_arg)
601 )
602
ValueError: Got an unexpected argument: categories
!?
なんかエラー。astype()
、categories
ないってよ。
※ stackoverflowの記事をよく読むと最新のpandasに対応した修正がされてますね。最初に見てたコピーサイトの記事が古いままだったようです。
なので、
を参考に。
from pandas.api.types import CategoricalDtype
cat_type = CategoricalDtype(categories=list('mfs'))
df1['sex'] = df1['sex'].astype(cat_type)
df1
id | name | age | sex | d | |
---|---|---|---|---|---|
0 | 1 | yukino | 3 | f | 4.0 |
1 | 2 | teio | 4 | m | 3.0 |
2 | 3 | nature | 4 | NaN | NaN |
pd.get_dummies(df1, columns=['sex'])
id | name | age | d | sex_m | sex_f | sex_s | |
---|---|---|---|---|---|---|---|
0 | 1 | yukino | 3 | 4.0 | 0 | 1 | 0 |
1 | 2 | teio | 4 | 3.0 | 1 | 0 | 0 |
2 | 3 | nature | 4 | NaN | 0 | 0 | 0 |
パチパチ。(定義してないカテゴリ変数が出てきたらどうなるのかは不明 <- astype()
を適用した段階でNaN
に変換されちゃうっぽい)