Exploring Mental Health Data とは
Exploring Mental Health Dataとは、性別や年齢、学校の満足度、仕事時間、職業などからその人がうつ病であるかを判定するKaggleのコンペである。
結果
提出結果は785位/2687(上位29.2%)であった。1位との精度差は0.0015ほどであるため、差がつきにくいコンペだったと認識している。
目次
- 自分のソリューション
- 試したがうまくいかなかったこと
- 上位者のソリューション
- 学んだこと
- 課題
自分のソリューション
特徴量エンジニアリング
学業や仕事から感じるストレス(pressure)を合計で計算。この時、学生なのに仕事のストレスも解答している人がいたのでそれを無効にした。また、満足度も同様に作成した。
# Academic PressureもWork Pressureもどちらも回答している人(学生)がいたので、Work Pressureをなかったことにする
df.loc[(~df['Academic Pressure'].isna()) & (~df['Work Pressure'].isna()), 'Work Pressure'] = np.nan
# Pressureを作成
df['Work Pressure'].fillna(0, inplace=True)
df['Academic Pressure'].fillna(0, inplace=True)
df['Pressure'] = df['Work Pressure'] + df['Academic Pressure']
# Job SatisfactionもStudy Satisfactionもどちらも回答している人(学生)がいたので、Job Satisfactionをなかったことにする
df.loc[(df['Job Satisfaction'].notna()) & (df['Study Satisfaction'].notna()), 'Job Satisfaction'] = np.nan
# Satisfactionを作成
df['Job Satisfaction'].fillna(0, inplace=True)
df['Study Satisfaction'].fillna(0, inplace=True)
df['Satisfaction'] = df['Job Satisfaction'] + df['Study Satisfaction']
また、居住都市名に睡眠時間が入力されているなどの異常値があったが、それがどのタイミングで発生したのか分からなかったため特に処理はしなかった。患者の入力結果だった場合、それはうつ病診断の手がかりになると考えたから。(入力欄を間違えるほどに疲れている、集中力が無いなど)
CatBoostで学習、推論
カテゴリー列を指定して学習。
# カテゴリー列を取得
cat_features = df.drop('DataSet', axis=1).select_dtypes(include='object').columns.tolist()
# 交差検証の設定
kf = StratifiedKFold(n_splits=3, shuffle=True, random_state=7)
scores = []
# 交差検証ループ
for train_index, val_index in kf.split(train_df.drop('Depression', axis=1), train_df['Depression']):
X_train_fold, X_val_fold = train_df.drop('Depression', axis=1).iloc[train_index], train_df.drop('Depression', axis=1).iloc[val_index]
y_train_fold, y_val_fold = train_df['Depression'].iloc[train_index], train_df['Depression'].iloc[val_index]
model = CatBoostClassifier(iterations=10000,
depth=6,
learning_rate=0.05,
rsm=0.2,
cat_features=cat_features,
verbose=100,
eval_metric='Accuracy',
early_stopping_rounds=100)
# 評価セットを指定
model.fit(X_train_fold, y_train_fold, eval_set=(X_val_fold, y_val_fold))
# 精度を取得
score = model.score(X_val_fold, y_val_fold)
scores.append(score)
# 平均精度
print(np.mean(scores))
平均精度は0.9389196872778962となった。
試したがうまくいかなかったこと
- カテゴリーデータをEmbedding layerを使用してより高次元に落とし込んで特徴量として利用する方法。しかし、CatBoostのエンコーディング方法の方が精度が高かった
- データ数が23万と多かったのでTabNetを使用したがCatBoostの方が高かった
- 思いつく限りの特徴量を増やしたが精度に差は出なかった
- 予測を間違えたデータを見て有効な特徴量を考えて追加したが、恐らく学習するデータに過適合してしまっていた
上位者のソリューション
- AutoMLという機械学習ライブラリを用いていた。これにより、複数モデルのアンサンブルやチューニングが簡単にできるらしい(AutoGluonを主に使用)
- 1位の人は特徴量エンジニアリングなし、Name列の削除すら行っていない
学んだこと
- 少しでも精度を上げるためには複数モデルのアンサンブルが有効
- シンプルなモデルの方が精度が高いこともある
- 探索範囲が相当小さくない限りは、GridSearchよりOptunaの方がパラメータ最適化に向いている
課題
- AutoGluonのような機械学習ライブラリの使用方法を身につける
- 異常値の確認をして適切に処理できるようにする。複数の処理方法がある場合は、実際に試してみて決めるようにする