2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pandasのget_dummies()は使えない。そんな風に考えていた時期が俺にm

Last updated at Posted at 2021-03-10

pandasのget_dummies()は使えない

特徴量中のカテゴリ変数をダミー変数化する際、pandasget_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

パチパチ:clap:。(定義してないカテゴリ変数が出てきたらどうなるのかは不明 <- astype()を適用した段階でNaNに変換されちゃうっぽい)

2
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?