はじめに
前回の投稿ではKaggleのデータセット1を使って二値分類問題にチャレンジしました。
その際、カテゴリ値の取扱い方法としては、Label Encodingを採用しました。
が、他の方法もあるので、後学のために本稿ではOne-hot Encodingにチャレンジします(LightGBMを利用するなど問題設定は同じ)。
本稿で紹介すること
- データの収集および整形
- 予測モデルの作成
- 予測精度の確認
- 特徴量重要度の確認(可視化)
前回の投稿記事からの変更部分を中心に、説明します。
本稿で紹介しないこと
- 特徴量設計
- ハイパーパラメータのチューニング
分析環境の各種情報
筆者は、いつもながらDockerコンテナとしてJupyterを起動しています。
- Python 3.8.8
- pip 21.3.1
- pandas 1.4.0
- numpy 1.22.1
- scikit-learn 1.0.2
- lightgbm 3.3.2
データの収集
前回に同じです。
データの整形
Nullレコードを除去するところまでは前回に同じです。
前回からの変更部分は、今回の主題となるカテゴリ値の処理です。以下を参考に、カテゴリ値はOne-hot化しました。
元データが15カラム(含む目的変数)だったのに対し、処理後は105カラム(含む目的変数)になりました。
各カラム内の1つのカテゴリ値が、1カラムとして独立するので、カラム数が大きく増えるのは納得でした。
(対象データは、母国語をカラムが含まれており、これが40カテゴリだったことが一因。)
例えば、整形処理はこんな感じ。説明変数の計8カラムを整形しました。
columns_cat = [
'workclass',
'education',
'marital-status',
'occupation',
'relationship',
'race',
'gender',
'native-country',
#'income',
]
:
#!pip install category_encoders
import category_encoders as ce
# One-hot Encodingしたい列をリストで指定
ce_ohe = ce.OneHotEncoder(cols=columns_cat, handle_unknown='impute')
# DataFrameを渡してOne-hot Encodingを適用
df = ce_ohe.fit_transform(df)
df.head(10)
後々の特徴量重要度を確認する際に必要になるので、変換処理での対応関係も確認しました。
変換前のカラム名に対し、変換後のカラム名_${Index値}のIndex値を教えてくれました。
# 変換前:文字列と変換後:数値の対応関係を確認
ce_ohe.category_mapping
:
{'col': 'marital-status',
'mapping': Never-married 1
Married-civ-spouse 2
Widowed 3
Separated 4
Divorced 5
Married-spouse-absent 6
Married-AF-spouse 7
NaN -2
dtype: int64,
'data_type': dtype('O')},
:
予測モデルの作成
こちらも、前回に同じです。
こちらのサイトで公開されているPythonコード2を参考にしました。
# LightGBM のハイパーパラメータ
params = {
# 二値分類問題
'objective': 'binary',
# AUC の最大化を目指す
'metric': 'auc',
# Fatal の場合出力
'verbosity': -1,
# 乱数シード
'seed': 31,
# 学習率
'learning_rate': 0.02,
}
# 上記のパラメータでモデルを学習する
model = lgb.train(params, lgb_train, valid_sets=lgb_valid,
verbose_eval=50, # 50イテレーション毎に学習結果出力
num_boost_round=10000, # 最大イテレーション回数指定
early_stopping_rounds=100
)
Training until validation scores don't improve for 100 rounds
[50] valid_0's auc: 0.913351
[100] valid_0's auc: 0.917335
/opt/conda/lib/python3.8/site-packages/lightgbm/engine.py:181: UserWarning: 'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. Pass 'early_stopping()' callback via 'callbacks' argument instead.
_log_warning("'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. "
/opt/conda/lib/python3.8/site-packages/lightgbm/engine.py:239: UserWarning: 'verbose_eval' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.
_log_warning("'verbose_eval' argument is deprecated and will be removed in a future release of LightGBM. "
[150] valid_0's auc: 0.922076
[200] valid_0's auc: 0.924902
[250] valid_0's auc: 0.926122
[300] valid_0's auc: 0.92682
[350] valid_0's auc: 0.92731
[400] valid_0's auc: 0.9276
[450] valid_0's auc: 0.927851
[500] valid_0's auc: 0.928042
[550] valid_0's auc: 0.928216
[600] valid_0's auc: 0.928317
[650] valid_0's auc: 0.928426
[700] valid_0's auc: 0.928446
[750] valid_0's auc: 0.928452
[800] valid_0's auc: 0.928403
Early stopping, best iteration is:
[710] valid_0's auc: 0.928479
予測精度の確認
こちらも、前回に同じです。
こちらのサイトで公開されているPythonコード3を参考にしました。
実行すると、こんな感じ。想像以上に精度が良かった。
前回に比較すると、精度自体はほんの少し下がりました。
が、有意な差ではなく、乱数シードの差異かなというレベルでした。
特徴量重要度の確認(可視化)
こちらも、前回に同じです。
特徴量重要度の確認ですが、lightgbm.plot_importanceを使いました。
こちらのサイトで公開されているPythonコード4を参考にしました。
実行すると、こんな感じ。特徴量重要度の上位銘柄はあまり変わらず、順位が変動した印象でした。
が、One-hot化によりカテゴリ値を扱うカラムに対して、予測精度に貢献した具体的なカテゴリ値を知ることができ、より予測結果に対して理解を深められました。
importance_type='split'として可視化した結果。
importance_type='gain'として可視化した結果。
特に、2つ目の方式、gainの方をもう少し詳しく確認しました4。
結果について少し考察
特徴量重要度についてです。
特徴量重要度のTopは「Married-civ-spouse」であり、個人の婚姻歴として現在進行形(既婚で配偶者あり)だったことが判明しました。つまり、収入が高いから家庭(≒配偶者)をもてたのだろうな、、、という意味付けですね。
relationship: Wife, Own-child, Husband, Not-in-family, Other-relative, Unmarried.
marital-status: Married-civ-spouse, Divorced, Never-married, Separated, Widowed, Married-spouse-absent, Married-AF-spouse.
Notebook(Pythonコード)
githubで公開しました。このタイミングですが、参考サイトの方々に感謝申し上げます。
まとめ
カテゴリ値を含むデータをOne-hot EncodingしてLightGBMを使った分析の例をご紹介。
category_encodersというPythonライブラリ、非常に便利でした。
One-hot Encodingにより対象データのカラム数こそ増えはしますが、Label Encodingでの分析結果に対して更に理解を深められた、というのが1つの成果だと思いました。
-
Adult Data Set | https://archive.ics.uci.edu/ml/datasets/adult ↩
-
コード | https://qiita.com/d_desuyon/items/807e01311ad08570ee78#%E3%82%B3%E3%83%BC%E3%83%89 ↩
-
モデルの評価 | https://qiita.com/kt38k/items/3c0ee4251475b6407007#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E8%A9%95%E4%BE%A1 ↩
-
特徴量重要度の算出 (2値分類編) | https://mathmatical22.xyz/2020/04/12/%E3%80%90%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91%E3%81%91%E3%80%91%E7%89%B9%E5%BE%B4%E9%87%8F%E9%87%8D%E8%A6%81%E5%BA%A6%E3%81%AE%E7%AE%97%E5%87%BA-lightgbm-%E3%80%90python%E3%80%91%E3%80%90%E6%A9%9F/ ↩ ↩2