【随時更新】Kaggleテーブルデータコンペできっと役立つTipsまとめ
これはなに?
- Kaggleのテーブルデータコンペに参加するときに役立つ(と思う)Tipsを Kaggle Coursera の授業メモに色々追記する形でまとめたものです
- 自分で理解できている内容を中心にまとめました。各種資料の内容はまだまだ理解できていない内容が多く、今後も随時更新していきます(随時更新できるように勉強します)。
- この記事に書いてあるTipsをどのように活かしたかはKaggle参戦記に書いたので、併せてどうぞ。
参考文献
主として以下の資料の内容をピックアップさせていただきました。引用を明記していない部分は(ほぼ100%) Kaggle Coursera の内容です。
- Kaggle Coursera
- kaggle_memo by nejumiさん
- Kaggleで世界11位になったデータ解析手法〜Sansan高際睦起の模範コードに学ぶ
- Kaggle TalkingData Fraud Detection コンペの解法まとめ(応用編)
- Kaggle Memo by amaotoneさん
- 最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング
- Santander Product RecommendationのアプローチとXGBoostの小ネタ
- Tips for data science competitions
- Feature Engineering
('20/02/09追記) テーブルコンペできっと役立つ本
- このブログ記事を書いた後に、テーブルコンペで役立つ技術が満載の本が出版されました。
- この記事ではkaggle-couseraを大いに参考にしていますが、2020年2月現在ではまずはこの本を読むのが良い、というか日本語話者のkagglerなら読まないと大いに不利になると思いますので、紹介しておきます。
リンク
EDA
全般
- データはちゃんと見よう、たまに間違ってるよ。(だからカラムの意味は理解しよう)
- EDAのとっかかりがなかったらXGBoostやLightGBMのfeature_importanceをまず見るのでも良い(2)
- 間違ってる列は消すんじゃなくて、間違ってるデータ列だとアルゴリズムに教えよう。(あなたよりアルゴリズムのほうが賢いこともよくあるよ)
- 可視化は大切だよ
- 一軸が役に立たないなら二軸に散布図かこう
- 散布図はTrain/Testが同質なデータか否かもわかるし便利だよ
- 以下のコードで一発
- 一軸が役に立たないなら二軸に散布図かこう
pd.scatter_matrix(df)
- スパイク見つけるためにヒストグラム書こう (これは絶対)
- Excelなどで色つけて眺めてみよう
- anonymous featureはリバースエンジニアリングしたらたまに良いことあるよ
- 誕生日の年とか出てきて役立った例とかあるよ
- 以下の使える表現は覚えよう
df.dtypes, df.info, x.value_counts, x.isnull
- 時系列などの場合は特に意味のある順序にソートして眺めよう(5)
データクリーニングの話
- 情報量ゼロのカラムを消そう
- 1種類の値しか入ってないカラム
- 完全にダブってるカラム
- 相関係数が1のカラム
- 参考Kernel
- Testでしか新しい値が出てこないカラム消そう
- ラベル変えたら同じになるカラム消そう
pd.factorize
使えば楽だよ
- Train/Testでデータ被ってることあるので、念のため理由を推測してみよう。
- 移動平均取ってみたらデータが正常にシャッフルされてないこと気付けるかも?
- プロットしてみるとデータがシャッフルされてるとかもわかるよ
- 線が出現したらその値が頻出とかもよくわかるよ
- カテゴリ変数の列を抜き出す表現は覚えよう
df.select_dtypes(include=['object']).columns
Numerical Data
概要
- 採用するモデルによって前処理の方法は変えよう
- 線形モデルと決定木モデルでは必要なデータが違うよ
- 異なる前処理を行ったモデルを混ぜると効くことがあるよ
Scaling
- 決定木はスケーリングは基本的に関係ないよ
- MinMaxScaler ⇔ StandardScaler
- 線形モデルではどっちでも変わらないよ
- kNNは結構影響あるかも
異常値排除 / 各種変換
clipping
- 99%タイルにクリッピングするとか効くよ
upperbound, lowerbound = np.percentile(x, [1, 99]) y = np.clip(x, upperbound, lowerbound)
rank transformation
- outliersをしこしこ処理できないときはrankに変換してしまおう
- kNNやNNはこの変換が効くよ
scipy.stats.rankdata
log transformation
- NNに激しく効くよ
np.log(1+x) np.sqrt(x+2/3)
Numericalデータの特徴量作成
- とにかく沢山の特徴量を作ってみよう
count
,sum
,max
,min
,rolling
is_null
,is_zero
,is_not_zero
,over_0.5
- 行ごとの統計情報をまとめてみよう(9)
Nanの数
,0の数
,負の数
とか
- 要素の掛け算、割り算とかしよう
- ◯◯と△△との差
- カテゴリ内の平均XX
- 変数間の相互作用は
PolynomialFeatures
で計算できる
- 小数点以下だけ取り出した要素とか作ろう
- 4980円の
980
円的なやつ- 4ドルと3.98ドルは人間心理的にぜんぜん違うよ
- もちろん切り捨て/切り上げとかも作る価値はあるよ
- それをカテゴリカル変数として扱っても良いかもね(9)
- 4980円の
- 木モデルでは以下のデータ処理が必要
- 積み上げの値を普通の値に戻す (線形モデルでは不要)
- 和、差、積など取るのは重要だから頑張ろう
- 木モデルはカラム間の処理を頑張ると良いよ
- 差や比率を直接表現できないため
- Owen曰く(8)
GBM only APPROXIMATE interactions and non-linear transformations.
Strong interactions benefit from being explicitly defined.
- 木モデルはカラム間の処理を頑張ると良いよ
- データによってはNumerical→Categorical変換するのもあり
- 例: 年齢層(30代前半)とか
- 網羅的にやるよりもビジネス的に意味がある演算をすると効率いい
- HomeCreditでの例
- 借入額と毎月の返済額の比
- 利用限度額と月々の利用額の比
- 支払い予定日と実際の支払日の日数差
- 借入額と頭金の比率 など
- Avitoでの例
- 同一カテゴリ内の平均価格と自分の価格との差/比
- 例: iPhoneの中では安い
商品名の中の名詞
でグループ化した価格平均を使った特徴量
- 同一カテゴリ内の平均価格と自分の価格との差/比
- Kaggle Days Paris by CPMP
- 2Sigma Appt Rental: apartmentの説明文から相場を予測 → その相場予測と家賃との差を特徴量にした
- TalkingData: アプリDLしたらもう広告踏まないよね? → 同じ端末から同じADへの次のクリックへの時間を予測し、実際の時間との差を (ry
- Avito 9th
- HomeCreditでの例
- ビン詰めすると効くこともある(9)
- Testの数値範囲がTrainと外れているときとか
Categorical / Ordinal Data
Encodings
LabelEncoding
- 木モデルに有効
- 線形モデルの場合は
OnHotEncoding
が追加で必要 - 木モデルは
OnHotEncoding
は不要なことが多い- 遅くなるのでむしろ不利かもしれない
- 線形モデルの場合は
- S席、A席、みたいなやつは数字にしてあげると効くこともある
- 木モデルに有効
FrequencyEncoding
- 出現比率でエンコーディングする
- 線形モデルだけではなく、木モデルにも有効
- 異常値に弱い(9)
- logを取ると効くこともある(9)
TargetEncoding
- 強力だけどdata leakageには注意しよう
- leakageを防ぐ工夫はH2O.aiの人のスライドが詳しい
- Smoothing: 日本語記事もある
- leave-one-out
- Weight of Evidence
- その他の工夫
- out-of-fold (Kaggle Meetup #4 LT by Jackさん)
- random noise を加える (Port Seguro Kernel)
- 時系列など過学習が気になる際はTargetそのものではなく、重要特徴量にたいして行うと選択肢もアリ(HomeCredit 2nd)
- 基本的にLeakが気になるケースでは初心者は用いないほうが良い(2)
- 時系列の場合
- CatBoost で過去全体のtargetの平均を用いるという方法もある(kaggler-ja mamasさん)
- Column descriptionsで
Timestamp
を指定し、 - さらにtraining parametersの
has_time
を指定する。
- Column descriptionsで
- 過去N月のtarget平均を使うのも良い
- CatBoost で過去全体のtargetの平均を用いるという方法もある(kaggler-ja mamasさん)
Tips
- 複数のカテゴリカル変数をくっつけて使うこともある
- 性別☓客室等数とか
- 線形モデルで有効
- 多くの掛け合わせをすることを恐れるな
- OwenはAmazonCompetitionで7掛け合わせ変数を使った(8)
- アホみたいな掛け合わせが効くことあるから
weird interaction
も試してみろ(9)
Datetime / Coordinates Data
Date and time
- 日付は重要なこと多いから徹底して特徴量作成しよう
- 通常のDatetimeに加えて、◯◯から△分、とかも使える
- 同様に、◯した日と△した日の差、とかも
- 午前/午後/深夜とか、平日/休日/祝日/祝前日、とか
- 国民の祝日、大きなスポーツイベント、第一土曜日とか(9)
- 重要な日付から近いものの重みを大きくしてみよう
- 逆に遠いものは減衰させて重みを小さくしてみよう
- 曜日・時刻・(月の)日付などの周期性のある特徴量を円周上に配置し、cos・sinに分解して、循環連続性を表現するのも効果的(2)(9)
Coordinates(座標/地理) Data
- 重要なランドマークや都市からの距離とか
- 周辺地価とかの有効なデータの追加とかも効く
- 都市はgeographic feature作ったりいろいろやってみよう
- 近くに何個家があるか、学校があるか、など近くの情報も使おう
- GPS座標、郵便番号の住所への付与とかもやってみたら良いかもね(9)
- ニセの空間情報に気づけ(9)
- 不可能な速度での移動
- 今いる場所と違う場所での出費
その他 特徴量作成 Tips
次元削減系
- PCAよりNMFのほうが木モデルに使いやすい次元縮約をしてくれる
- PCAが効く理由
- XGBoostなどの決定木系アルゴリズムが軸に斜めの表現を不得手(表現できないわけではないが、PCAで回転した方が効率的)としていることに起因するとのこと(2)
- トピックモデル(LDA等)の活用を検討しよう(4)
時系列データ
- 基本的には直近のもので学習させたほうが良いが、1年前などに特徴的な周期性がないかは確認すべき(5)
- 時系列で重み付けしたカウントなどは有効な特徴量になり得る(5)
- 「費用」は先週の費用、先月の費用、昨年の費用などに分解してみよう(9)
- 全てのデータが一度に与えられるコンペではユーザーの未来の行動の情報の特徴量を作ると強い (TalkingData 1st)
- 過去の行動よりも未来の行動に基づく特徴のほうがたいてい強い
- 直前のクリックからの経過時間
- 今後1時間以内でのそのカテゴリ変数の値の出現回数
- 過去の行動よりも未来の行動に基づく特徴のほうがたいてい強い
- 過去のフラグ推移を連結した文字列をカテゴリ変数として扱う(7)
- 水準数が100を超えるような場合に有効なことが多い
- DeepLearningではなぜか効かないことが多い
- 文字列ヒストグラムはbosch 15thでも使われている
- 時系列じゃなくても文字列連結してカテゴリ変数にするのは他のコンペでも使われている模様(kaggle: Porto Seguro's Safe Driver Prediction まとめ)
巨大データを扱う
- データが大きいときは複数あるfoldのうち1つだけで検証するのもあり(Kaggle boschコンペ振り返り)
テクニック系
うまくカテゴライズできなかったテクニック集
- DenoisingAutoEncoder
- kNNによって観測された近傍点の数を特徴量として追加する(2: Facebook Predict check-insの1st place Winner’s solution)
- KMeans等のクラスタリングして、クラスタIDを使う or/and クラスタ中心までの距離を特徴量として加える(Malware '19 kernel)
- 予測値を特徴量に入れてもう一度学習する(Home Credit)
- (Targetではなく)重要特徴量を予測するモデルを作って活用する (HomeCredit 2nd)
- 予測した数値と実際の数値の差なども活用できる (Elo 18th: 予測した日付と実際の日付の差)
- 活用事例は(6)に詳しい
- メインデータとサブデータが1:多のような場合 (Home Credit や Elo の場合)
- サブに時系列性があればカテゴリ変数は最後の値を取る、などが使える
- サブデータにメインデータをマージしてサブだけで学習しすると効くことがある (Home Credit 17th / Elo 1st)
- 先頭/末尾のN行のみでAggregationなども使える
- Nの値をいろいろ変えるとなお良し
- 代表的な特徴量だけで計算したkNNで近傍500点のtargetの平均を特徴量として加える (Home Credit 1st)
- Adversarial Validation できないように特徴量を加工してTrainへの過学習を避ける (Malware '19 6th)
- K近傍を用いた特徴量抽出
- FMを活用した特徴量作成
- Kaggle Past Solutions
- ちゃんと漁れば宝の山のはず
特徴量選択
- Ridgeなどにかけて1変数ずつ有効かどうか確認するstepwiseが早い(5)
- LightGBMなどでできたらそちらのほうが良いが、計算時間との兼ね合いで決めても良い。
- boruta, eli5, NullImportances
- (今の所使って成功したことない…orz)
欠損値処理
見つけ方 & Fillana Approaches
- 見つけ方: ヒストグラムをかこう
- Fill NA Approaches
- カテゴリ変数か数値変数かによって欠損値の扱い方を変えよう
- 適当なoutlierに書き換える
- 木モデルの場合に有効
-99999
や、MAX値+1
とかmin値-1
とか
- 平均や中央値で書き換える
- 線形モデルで有効
- 木モデルにはネガティブ
- カテゴリ変数の場合
- 欠損値を「新たなカテゴリ」として扱うのも良い(3)
- K個のカテゴリがあったら、欠損値もカテゴリとみなしたK+1個の
One Hot Encoding
を行う
- K個のカテゴリがあったら、欠損値もカテゴリとみなしたK+1個の
- 欠損値を「新たなカテゴリ」として扱うのも良い(3)
- 推測する
- 注意
-99999
とかで置き換えたときにCategorycalEncoding
などに影響しないように注意- feature generationの前にfillnaしないほうが良い
Tips
category_x_isnull
の2値カテゴリーも有効- Trainデータに出てこないカテゴリーがTestに出てきたら?
- TrainとTestでの出現回数をカウントしてそれをカテゴリーにする
- XGBoost/LightGBMはNaNを直接扱える
- 値が0である説明変数の数を数えて追加の説明変数として加えてみる(2)
不均衡データの扱い
- Over-/Under-sampling
- SMOTEは効かないことが多い
- Under-samplingでもきちんとバギングすれば精度出るから問題ない(TalkingData 1st)
- imbalanced-learnの実装も使ってみよう
- 利用例: Porto Seguro Kernel
- 重みの変更
- LightGBM:
class_weight
の調整とか
- LightGBM:
Validation
Good Validation is MORE IMPORTANT than Good Model.
(8)- validationのsplitはオーガナイザーのそれを模倣しよう
- 模倣して良いValidationが出来たら
TRUST LOCAL CV
- 正しいValidationなしで進めるのは羅針盤無しで航海するのと同じ(進まないよ)
- 「模倣しろ」の具体例: Malware '19 6th
- ついでに、時系列的の場合のValidationの切り方の注意の勘所もわかって良い
- 模倣して良いValidationが出来たら
Normal-KFold
かStratified-Kfold
か?- 多クラス分類なら
Stratified-Kfold
必須(5) - 回帰でも1変数
k-means
してStratified
にすることも(5)
- 多クラス分類なら
- Adversarial Validation
- Testに近いTrainデータでValidationを行うのもあり
- LBを信じるべきか否か(8)
Ensemble / Stacking
- KAGGLE ENSEMBLING GUIDEが参考になる
- 序盤はEnsemble/Stackingによる安易なスコアアップは控えよう(2)
- 時間と余裕があるうちに、他の多くの人はやらないような独創的な手法を模索しよう
- 人と同じアプローチは後から取り入れれば良い
- パラメータ変えたモデルを配合するだけでもスコア伸びるよ
- random seed average はもはや常識(4)
- Averagingは単純だが強力な手法(2)
- N乗平均、対数平均など試してみると良いかもしれない(2)
- 小さなデータだったら平均アンサンブルで十分
- SingleModelの精度にこだわりすぎないように
- Ensembleすることは大前提として多様な(相関の低い)モデル群、特徴量を作成しよう
- 弱いモデルでもEnsembleで化けることがあるから念の為に取っておこう
- Ottoの例: P57あたりから
- Owen(8):
The strongest individual model does not necessarily make the best blend.
- とはいえ最近は
A great model is better than ensemble of weak models
という考え方も復活してきてはいる- CPMPさんがKaggle Days Parisで「bestfittingさんも言ってた」と紹介
- CPMPさんはTalkingDataで48個の特徴量のLightGBMシングルモデルで大多数のチームのEnsembleモデルに勝ったとのこと
- GBMと相性が良いモデル
- RandomForest(2)
- Neural Network(理由: Tree Baseアルゴリズムは決定境界が特徴軸に平行な矩形になるが、NNなどは曲線(曲面)となるため(2))
- Glmnet(RidgeやLASSO)(8)
- 浅いモデルと深いモデルを混ぜると効果あることがある
- Adversarial Validationが誤分類したデータを重視してEnsemble Weightをきめる(6)
- LightGBMとXGBoostをアンサンブルしてもあまり精度をあげられた例はない(7)
- Stakingの実装例: Porto Seguro Kernel
- AUCが評価指標のときはアンサンブルする前にrank化しよう(KAGGLE ENSEMBLING GUIDE)
様々なモデル
- Regularized Greedy Forest: くそ遅いけど試してみる価値あるよ
- (相対的に)早い実装もある: FastRGF
- CatBoost: デフォパラメータが良いからめっちゃ時間の節約になるよ
- tSNE
- 強力だけどパーフレシティのチューニングが大変難しい
- TSNEのsklearnくそ遅いからtsneパッケージ推奨
学習のTips
- 評価指標にとらわれなくても良い
- (時系列データなどの場合) 特徴的な傾向があれば学習データ期間をずらしてしまうのもあり(7)
- XGBoostにおけるネタ(7)
- 同じデータセットに対しては最適な学習回数はサンプル数に対しておよそ線形なので推測ができる(切片が0じゃないのでそこだけは注意)
- 単一モデルでは学習回数が不足でも過剰でも精度が落ちるが、random seed averagingは学習回数過剰気味でもあまり精度が落ちない
max_depth
が多いほどaveragingの効果が大きくなるので、単一モデル検証で精度が拮抗していたらより深い方を選ぶのがベター学習率
は小さくすれば精度が良くなるが、averagingではその効果が大きく減少するので、必要以上に小さくしないほうが学習時間的に有利。colsample_by*
は小さくすると学習時間が線形に減少する。精度向上にも寄与することが多いので小さめの値を試してみよう。
Tuning
- パラメータの意味は この記事 がとてもわかり易いです
- XGBoost
max_depth=7
あたりから始めるのがよい- Lightgbmは
深さ
に加えて木全体の葉の数
を制御できるので融通が利いて良い bagging_fraction
: 1つの木を育てるのにどれくらいのデータを使って良いかを決める グリーン (オーバーフィッティングしたら下げればよい)feature_fraction
: 1つの木を育てるのにどれくらいの特徴量を使って良いかを決める グリーンmin_data_in_leaf
: 汎化に最も重要なパラメータ レッド (オーバーフィッティングしたら上げる)lambda_l1
,lambda_l2
: これも重要、0,5,15,300 あたりを見てみる。num_round
: =何本の木を作るか。最初の方の木で十分に説明できてしまうこともある。learning_rate
: 高すぎると全く収束しない可能性ある、適切な小ささの学習率は汎化に有効。- trick: 以下を行うと大概精度が上がる (学習時間は長くなるが )
step * alpha
eta / alpha
boosting_type
: dropoutを模したdart
っていうのも有効- Owen流(8)
- CPMP流 (Kaggle Days Paris)
- subsample=0.7 & 他はデフォから始めろ
- min_child_weight: train/val gap 大きければ増やせ
- それから max_Depth or number_of_leaves を調整しろ
- LBがCVより低ければ正則化を強めろ
- LightGBM
- なにはともあれ 公式 Parameters Tuning ガイド
num_leaves
多め、feature_fraction
かなり小さめ、とかもあり(5)feature_fraction = sqrt(n_features)/n_features
程度だと特徴量数の影響を受けづらく、良い(5)- dartだとearly_stoppingしたときに挙動が変だから気をつけて
- Random Forest
- gbmより深い木でも大丈夫なのでトライしてみよう
- giniが大概良いが、たまにエントロピーが勝つ
- コンペの序盤と中〜終盤の2回やるという方法もある(Malware '19 Discussion)
- Optunaが学習中断/再開とかもできて何かと便利
その他Tips
- Testデータに対する
semi-supervised learning
は現状で主要な差別化ポイントのひとつ(2) - 終了直前で激強kernelが出現することがあるので対応が必要(5)
- 特に銅メダル圏内ぐらいのとき
- 最終日は2サブ残しておき自分のsolutionとアンサンブルできるようにしておけば安心
- 1サブ残しだと精神的にきついので、2サブ推奨らしい
黒魔術系
まだ使ってないけど役に立ちそうなもの
- Linear Quiz Blending
- 遺伝的プログラミングによる特徴量作成
未整理: 使えるライブラリとか
あとでまとめる(かも)
- pandas-profiling
- コピペで使える。Kaggleでの実験を効率化する小技まとめ
- あなたの生産性を向上させるJupyter notebook Tips
- Jupyter Notebook Viewer
- kaggle-apiというKaggle公式のapiの使い方をまとめます
- JupyterLabのおすすめ拡張機能7選
- Vaex入門 / 可視化もXGBoostも
- Preemptive Instance のシャットダウン時に使えるScript
- pandas.DataFrame のforループをゆるふわ△改良して300倍高速化する
最後に
冒頭にも書きましたが、個人的に理解できている(と思っている)内容のみ書いています。まだまだ理解できていない内容が多いので、今後も随時更新していきます。
あと、実験に飽きてきたらトーマス・エジソン名言集を読むとたまに元気づけられます。よろしければ参考にしてください笑。
私は失敗したことがない。 ただ、1万通りの、うまく行かない方法を見つけただけだ。
私たちの最大の弱点は諦めることにある。 成功するのに最も確実な方法は、常にもう一回だけ試してみることだ。
ほとんどすべての人間は、もうこれ以上アイデアを考えるのは不可能だ、 というところまで行きつき、そこでやる気をなくしてしまう。 勝負はそこからだというのに。