はじめに
機械学習の前処理ライブラリDataLiner 1.2.0をリリースしました。
今回は新たに6つほど前処理を追加しましたので紹介したいと思います。
GitHub: https://github.com/shallowdf20/dataliner
PyPI: https://pypi.org/project/dataliner/
Document: https://shallowdf20.github.io/dataliner/preprocessing.html
インストール
pipを使ってインストールします。
! pip install -U dataliner
データ準備
いつも通りTitanicのデータを使用します。
import pandas as pd
import dataliner as dl
df = pd.read_csv('train.csv')
target_col = 'Survived'
X = df.drop(target_col, axis=1)
y = df[target_col]
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | Braund, Mr. Owen Harris | male | 22 | 1 | 0 | A/5 21171 | 7.250 | NaN | S |
2 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Thayer) | female | 38 | 1 | 0 | PC 17599 | 71.283 | C85 | C |
3 | 3 | Heikkinen, Miss. Laina | female | 26 | 0 | 0 | STON/O2. 3101282 | 7.925 | NaN | S |
4 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35 | 1 | 0 | 113803 | 53.100 | C123 | S |
5 | 3 | Allen, Mr. William Henry | male | 35 | 0 | 0 | 373450 | 8.050 | NaN | S |
では、早速見ていきましょう。
AppendArithmeticFeatures
データに含まれる特徴量同士で四則演算を行い、演算に使った特徴量よりも評価指標が高い特徴量を新たに追加します。
評価はロジスティック回帰で行われます。デフォルトではかけ算、評価指標はAUCですが、足し算、引き算や割り算、Accuracyなども利用可能です。
利用前に欠損値を補完する必要があります。
process = make_pipeline(
dl.ImputeNaN(),
dl.AppendArithmeticFeatures(metric='roc_auc', operation='multiply')
)
process.fit_transform(X, y)
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | PassengerId_multiply_Age | PassengerId_multiply_SibSp | PassengerId_multiply_Parch | Pclass_multiply_Age |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | Braund, Mr. Owen Harris | male | 22 | 1 | 0 | A/5 21171 | 7.250 | B96 B98 | S | 22 | 1 | 0 | 66 |
2 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Thayer) | female | 38 | 1 | 0 | PC 17599 | 71.283 | C85 | C | 76 | 2 | 0 | 38 |
3 | 3 | Heikkinen, Miss. Laina | female | 26 | 0 | 0 | STON/O2. 3101282 | 7.925 | B96 B98 | S | 78 | 0 | 0 | 78 |
4 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35 | 1 | 0 | 113803 | 53.100 | C123 | S | 140 | 4 | 0 | 35 |
5 | 3 | Allen, Mr. William Henry | male | 35 | 0 | 0 | 373450 | 8.050 | B96 B98 | S | 175 | 0 | 0 | 105 |
このように新しい特徴量が追加されます。
RankedEvaluationMetricEncoding
各カテゴリーをダミー変数化した上で、それぞれのカテゴリ列と目的変数でロジスティック回帰を行います。
その結果の評価指標(デフォルトではAUC)を使ってランキングを作成し、その順位で元々のカテゴリーをエンコードします。
各カテゴリに5 foldのロジ回帰をフィットする関係上、カーディナリティの高い特徴量では計算量が膨大になるため事前に
DropHighCardinalityやGroupRareCategoryなどを使ってカーディナリティを下げておくことを推奨します。
process = make_pipeline(
dl.ImputeNaN(),
dl.RankedEvaluationMetricEncoding()
)
process.fit_transform(X, y)
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | 640 | 2 | 22 | 1 | 0 | 288 | 7.250 | 1 | 1 |
2 | 1 | 554 | 1 | 38 | 1 | 0 | 284 | 71.283 | 77 | 2 |
3 | 3 | 717 | 1 | 26 | 0 | 0 | 256 | 7.925 | 1 | 1 |
4 | 1 | 803 | 1 | 35 | 1 | 0 | 495 | 53.100 | 112 | 1 |
5 | 3 | 602 | 2 | 35 | 0 | 0 | 94 | 8.050 | 1 | 1 |
尚、ランキングを出力させることでカテゴリ変数内の各カテゴリーがどのくらい重要かを確認することもできます。
process['rankedevaluationmetricencoding'].dic_corr_['Embarked']
Category | Rank | Evaluation_Metric |
---|---|---|
S | 1 | 0.5688 |
C | 2 | 0.5678 |
Q | 3 | 0.4729 |
AppendClassificationModel
入力データを元に分類器を学習させ、その予測結果を新たな特徴量として追加します。
modelはsklearn準拠モデルであれば何でも使用可能です。また、predict_probaメソッドが実装されていれば
引数probability=Trueを与えることでラベルの代わりにスコアを追加できます。
モデルを学習させるので基本的に欠損値補完とカテゴリ変数の処理が必要になります。
process = make_pipeline(
dl.ImputeNaN(),
dl.TargetMeanEncoding(),
dl.AppendClassificationModel(model=RandomForestClassifier(n_estimators=300, max_depth=5),
probability=False)
)
process.fit_transform(X, y)
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | Predicted_RandomForestClassifier |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | 0.3838 | 0.1889 | 22 | 1 | 0 | 0.3838 | 7.250 | 0.3039 | 0.3390 | 0 |
2 | 1 | 0.3838 | 0.7420 | 38 | 1 | 0 | 0.3838 | 71.283 | 0.3838 | 0.5536 | 1 |
3 | 3 | 0.3838 | 0.7420 | 26 | 0 | 0 | 0.3838 | 7.925 | 0.3039 | 0.3390 | 1 |
4 | 1 | 0.3838 | 0.7420 | 35 | 1 | 0 | 0.4862 | 53.100 | 0.4862 | 0.3390 | 1 |
5 | 3 | 0.3838 | 0.1889 | 35 | 0 | 0 | 0.3838 | 8.050 | 0.3039 | 0.3390 | 0 |
probability=Trueだとこうなります。クラス1に対するスコアが付与されます。
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | Predicted_RandomForestClassifier |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | 0.3838 | 0.1889 | 22 | 1 | 0 | 0.3838 | 7.250 | 0.3039 | 0.3390 | 0.1497 |
2 | 1 | 0.3838 | 0.7420 | 38 | 1 | 0 | 0.3838 | 71.283 | 0.3838 | 0.5536 | 0.8477 |
3 | 3 | 0.3838 | 0.7420 | 26 | 0 | 0 | 0.3838 | 7.925 | 0.3039 | 0.3390 | 0.5401 |
4 | 1 | 0.3838 | 0.7420 | 35 | 1 | 0 | 0.4862 | 53.100 | 0.4862 | 0.3390 | 0.8391 |
5 | 3 | 0.3838 | 0.1889 | 35 | 0 | 0 | 0.3838 | 8.050 | 0.3039 | 0.3390 | 0.1514 |
AppendEncoder
DataLinerに含まれる各種Encoderはカテゴリ列をエンコードした数値で直接置き換えます。
しかし場合によっては置き換えず新しい特徴量として利用したい場合もあるかと思います。(TargetMeanEncoderなど)
その場合は、Encoderをこのクラスでラップしてあげることで特徴量として追加されるようになります。
process = make_pipeline(
dl.ImputeNaN(),
dl.AppendEncoder(encoder=dl.TargetMeanEncoding())
)
process.fit_transform(X, y)
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | Name_TargetMeanEncoding | Sex_TargetMeanEncoding | Ticket_TargetMeanEncoding | Cabin_TargetMeanEncoding | Embarked_TargetMeanEncoding |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | Braund, Mr. Owen Harris | male | 22 | 1 | 0 | A/5 21171 | 7.250 | B96 B98 | S | 0.3838 | 0.1889 | 0.3838 | 0.3039 | 0.3390 |
2 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Thayer) | female | 38 | 1 | 0 | PC 17599 | 71.283 | C85 | C | 0.3838 | 0.7420 | 0.3838 | 0.3838 | 0.5536 |
3 | 3 | Heikkinen, Miss. Laina | female | 26 | 0 | 0 | STON/O2. 3101282 | 7.925 | B96 B98 | S | 0.3838 | 0.7420 | 0.3838 | 0.3039 | 0.3390 |
4 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35 | 1 | 0 | 113803 | 53.100 | C123 | S | 0.3838 | 0.7420 | 0.4862 | 0.4862 | 0.3390 |
5 | 3 | Allen, Mr. William Henry | male | 35 | 0 | 0 | 373450 | 8.050 | B96 B98 | S | 0.3838 | 0.1889 | 0.3838 | 0.3039 | 0.3390 |
AppendClusterTargetMean
データでクラスタリングを行い、クラスター番号を振ります。(ここまではAppendClusterと同一)
その後、各クラスター番号をクラスタ内の目的変数の平均で置き換え、新たな特徴量として追加します。
欠損値の補完とカテゴリ変数の処理が必要になります。
process = make_pipeline(
dl.ImputeNaN(),
dl.TargetMeanEncoding(),
dl.AppendClusterTargetMean()
)
process.fit_transform(X, y)
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | cluster_mean |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | 0.3838 | 0.1889 | 22 | 1 | 0 | 0.3838 | 7.250 | 0.3039 | 0.3390 | 0.3586 |
2 | 1 | 0.3838 | 0.7420 | 38 | 1 | 0 | 0.3838 | 71.283 | 0.3838 | 0.5536 | 0.3586 |
3 | 3 | 0.3838 | 0.7420 | 26 | 0 | 0 | 0.3838 | 7.925 | 0.3039 | 0.3390 | 0.3586 |
4 | 1 | 0.3838 | 0.7420 | 35 | 1 | 0 | 0.4862 | 53.100 | 0.4862 | 0.3390 | 0.3586 |
5 | 3 | 0.3838 | 0.1889 | 35 | 0 | 0 | 0.3838 | 8.050 | 0.3039 | 0.3390 | 0.3586 |
PermutationImportanceTest
特徴量選択手法の一種です。ある特徴量のデータをランダムにシャッフルした場合としなかった場合で、
モデル予測結果の評価指標がどのぐらい悪化するかという観点で特徴量選択を行います。
データをランダムにシャッフルしても評価指標にあまり影響がない場合は、その特徴量は効いていないとして削除します。
process = make_pipeline(
dl.ImputeNaN(),
dl.TargetMeanEncoding(),
dl.PermutationImportanceTest()
)
process.fit_transform(X, y)
Pclass | Sex | Age | SibSp | Ticket | Fare | Cabin | Embarked |
---|---|---|---|---|---|---|---|
3 | 0.1889 | 22 | 1 | 0.3838 | 7.250 | 0.3039 | 0.3390 |
1 | 0.7420 | 38 | 1 | 0.3838 | 71.283 | 0.3838 | 0.5536 |
3 | 0.7420 | 26 | 0 | 0.3838 | 7.925 | 0.3039 | 0.3390 |
1 | 0.7420 | 35 | 1 | 0.4862 | 53.100 | 0.4862 | 0.3390 |
3 | 0.1889 | 35 | 0 | 0.3838 | 8.050 | 0.3039 | 0.3390 |
Name, PassengerIdとParchが削除されました。以下のようにして削除された特徴量を確認することもできます。
process['permutationimportancetest'].drop_columns_
['PassengerId', 'Name', 'Parch']
他にもしきい値thresholdを調整することで感度を調整できます。詳しくはDocument参照。
おわりに
上記が新しく追加した前処理です。RankedEvaluationMetricEncodingはたまにTargetMeanEncoding以上の精度が出たりするのでよく試します。
またPermutationImportanceTestはBorutaやStep-wise法と比べても高速に実行できる割に意外と差がなかったりするので
DropLowAUCよりは真面目に(?)特徴量選択したい場合に使ってみるのもありかと思います。
リリース記事:
[Ver1.1.9更新] 機械学習用データ前処理ライブラリDataLinerを作ってみた
1.2以前の前処理については以下で紹介しています。
Titanicデータを前処理ライブラリDataLinerで処理してみる(Drop編)
Titanicデータを前処理ライブラリDataLinerで処理してみる(Encoding編)
Titanicデータを前処理ライブラリDataLinerで処理してみる(変換編)
Titanicデータを前処理ライブラリDataLinerで処理してみる(Append編)