LoginSignup
0
1

More than 1 year has passed since last update.

Kaggleの臨床検査データセットを使ってみた④ ~外れ値の取り扱い~

Last updated at Posted at 2022-04-04

概要

Kaggleの血液検査データセットを使ってデータ分析をしてみた。
いろいろ試してみた結果、量が多くなったので分割します。
今回はその④ (全5回)

他の回はこちらから
①~モデルの性能比較をしてみた~
②~特徴選択をして、重要度を可視化してみた~
③~アンサンブル学習をしてみた~
⑤~不均衡データの取り扱い~

使用したデータセット:Patient Treatment Classification (Electronic Health Record Dataset)
インドネシアの病院で集められた血液検査の結果から、患者に治療が必要かどうかを判定する

モデル

今回はXGBoostで外れ値の影響を確認する

  1. XGBoost

データ確認

データは血液検査の結果。
データの検査方法が分からなかったため、正常値は2016年度国立がん研究センターのデータをお借りしました。(※ 正常値は測定方法などにより若干のばらつきあり)

列No 検査値 和訳  正常値 高いと 低いと
1 HAEMATOCRIT ヘマトクリット 男性:40.7~50.1 %,
女性:35.1~44.4 %
多血症など 貧血など
2 HAEMOGLOBINS ヘモグロビン 男性:13.7~16.8 g/dl,
女性:11.6~14.8 g/dl
多血症など 貧血など
3 ERYTHROCYTE 赤血球 男性:4.35~5.55 x 106 /μL,
女性:3.86~4.92 x 106 /μL
多血症など 貧血など
4 LEUCOCYTE 白血球 3.3~8.6 x 103/μL 感染症・白血病など 一部感染症・膠原病・貧血など
5 THROMBOCYTE 血小板 158~348 x 103/μL 血小板血症・白血病・多血症など 貧血・紫斑病など
6 MCH 平均赤血球ヘモグロビン量 27.5~33.2 pg 巨赤芽球性貧血など 鉄欠乏性貧血など
7 MCHC 平均赤血球ヘモグロビン濃度 31.7~35.3 g/dL 脱水・多血症など 貧血など
8 MCV 平均赤血球容積 83.6~98.2 fL  巨赤芽球性貧血など 鉄欠乏性貧血など
9 AGE 年齢
10 SEX 性別
11 SOURCE 治療が必要か out: 治療不要, in: 治療が必要

前処理は①と同じなので割愛

外れ値検索

LOFによる外れ値検索
from sklearn.neighbors import LocalOutlierFactor

outlier_LOF = []
clf = LocalOutlierFactor(n_neighbors=30)
predictions = clf.fit_predict(df_samp)
for index in df_samp[predictions == -1].index:
  outlier_LOF.append(df_samp.index.get_loc(index))

# 外れ値を除外
df_samp_LOF = df_samp.drop(df_samp.index[outlier_LOF])

# 除外後のデータ数を確認
print(f'{len(df_samp_LOF)}/{len(df_samp)}')

>>

print(f'{len(df_samp_LOF)}/{len(df_samp)}')
4348/4412

外れ値を除外

学習と結果
X_GBDT_LOF, y_GBDT_LOF, df_GBDT_LOF = dframe_copy(df_samp_LOF, "SOURCE")

train_X, test_X, train_y, test_y = train_test_split(X_GBDT_LOF, y_GBDT_LOF, test_size=0.2, random_state=42)
train_X, val_X, train_y, val_y = train_test_split(train_X, train_y, test_size=0.1, random_state=42)

# GBDTで学習
dtrain = xgb.DMatrix(train_X, label=train_y)
dval = xgb.DMatrix(val_X, label=val_y)
dtest = xgb.DMatrix(test_X)

params = {'objective': 'binary:logistic', 'silent':1, 'random_state': 71, 'eval_metric': 'auc'}
num_round = 25

watchlist = [(dtrain, 'train'), (dval, 'eval')]
GBDT_LOF_model = xgb.train(params, dtrain, num_round, evals=watchlist)

val_pred = GBDT_LOF_model.predict(dval)
val_y = val_y.tolist()
score_val = log_loss(val_y, val_pred)
print(f'logloss_val: {score_val: 4f}')

test_pred = GBDT_LOF_model.predict(dtest)

test_y = test_y.tolist()
AUC_GBDT_LOF = create_ROCcurve(test_y, test_pred)
tn_GBDT_LOF, fp_GBDT_LOF, fn_GBDT_LOF, tp_GBDT_LOF, specificity_GBDT_LOF, recall_GBDT_LOF, f1_GBDT_LOF = create_cm(test_y, test_pred, True)
AUC_list.append(["AUC_GBDT_LOF", np.round(AUC_GBDT_LOF, 3)])
specificity_list.append(["specificity_GBDT_LOF", np.round(specificity_GBDT_LOF, 3)])
recall_list.append(["recall_GBDT_LOF", np.round(recall_GBDT_LOF, 3)])
f1_score_list.append(["f1_GBDT_LOF", np.round(f1_GBDT_LOF, 3)])

結果

image.png
image.png

外れ値を除外し、特徴選択したパラメータ(②参照)で学習

学習と結果
# スコアが表示されないカラムを削除
X_GBDT_LOF, y_GBDT_LOF, df_GBDT_LOF = dframe_copy(df_samp_LOF, "SOURCE")
df_GBDT_LOF_dropzero = df_GBDT_LOF.drop(['HAEMATOCRIT_AB_1', 'HAEMOGLOBINS_AB_1', 'ERYTHROCYTE_AB_2',
       'LEUCOCYTE_AB_1', 'LEUCOCYTE_AB_2', 'THROMBOCYTE_AB_1',
       'THROMBOCYTE_AB_2', 'MCH_AB_1', 'MCH_AB_2', 'MCHC_AB_1', 'MCHC_AB_2'],axis=1)

X_GBDT_LOF_dropzero = df_GBDT_LOF_dropzero.values
# 変数を訓練用とテスト用に分割
train_X, test_X, train_y, test_y = train_test_split(X_GBDT_LOF_dropzero, y_GBDT_LOF, test_size=0.2, random_state=42)
train_X, val_X, train_y, val_y = train_test_split(train_X, train_y, test_size=0.1, random_state=42)

# GBDTで学習
dtrain = xgb.DMatrix(train_X, label=train_y)
dval = xgb.DMatrix(val_X, label=val_y)
dtest = xgb.DMatrix(test_X)

params = {'objective': 'binary:logistic', 'silent':1, 'random_state': 71, 'eval_metric': 'auc'}
num_round = 25

watchlist = [(dtrain, 'train'), (dval, 'eval')]
GBDT_LOF_dropzero_model = xgb.train(params, dtrain, num_round, evals=watchlist)

val_pred = GBDT_LOF_dropzero_model.predict(dval)
val_y = val_y.tolist()
score_val = log_loss(val_y, val_pred)
print(f'logloss_val: {score_val: 4f}')

pred_y = GBDT_LOF_dropzero_model.predict(dtest)

test_y = test_y.tolist()
AUC_GBDT_LOF_dropzero = create_ROCcurve(test_y, pred_y)
tn_GBDT_LOF_dropzero, fp_GBDT_LOF_dropzero, fn_GBDT_LOF_dropzero, tp_GBDT_LOF_dropzero, specificity_GBDT_LOF_dropzero, recall_GBDT_LOF_dropzero, f1_GBDT_LOF_dropzero = create_cm(test_y, pred_y, True)
AUC_list.append(["AUC_GBDT_LOF_IN", np.round(AUC_GBDT_LOF_dropzero, 3)])
specificity_list.append(["specificity_GBDT_LOF_IN", np.round(specificity_GBDT_LOF_dropzero, 3)])
recall_list.append(["recall_GBDT_LOF_IN", np.round(recall_GBDT_LOF_dropzero, 3)])
f1_score_list.append(["f1_GBDT_LOF_IN", np.round(f1_GBDT_LOF_dropzero, 3)])

結果

image.png
image.png

評価指標の比較

評価指標
AUC_list = sorted(AUC_list, reverse=True, key=lambda x: x[1])
specificity_list = sorted(specificity_list, reverse=True, key=lambda x: x[1])
recall_list = sorted(recall_list, reverse=True, key=lambda x: x[1])
f1_score_list = sorted(f1_score_list, reverse=True, key=lambda x: x[1])

print("---ROC_AUC---")
for i in range(len(AUC_list)):
  print(AUC_list[i])
print("---特異度---")
for i in range(len(specificity_list)):
  print(specificity_list[i])
print("----感度----")
for i in range(len(recall_list)):
  print(recall_list[i])
print("----f1値----")
for i in range(len(f1_score_list)):
  print(f1_score_list[i])

結果

XGBoostの結果はこちらを参照
外れ値除外(_LOF), 重要度の低い特徴量を除外(_NI)

ROC_AUC 特異度 感度 f1値
['AUC_GBDT_LOF', 0.827] ['specificity_GBDT_LOF', 0.873] ['recall_GBDT_LOF_IN', 0.669] ['f1_GBDT_LOF', 0.71]
['AUC_GBDT_LOF_IN', 0.823] ['specificity_GBDT:', 0.855] ['recall_GBDT_LOF', 0.654] ['f1_GBDT_LOF_IN', 0.709]
['AUC_GBDT:', 0.816] ['specificity_GBDT_NI:', 0.855] ['recall_GBDT:', 0.634] ['f1_GBDT:', 0.692]
['AUC_GBDT_NI:', 0.816] ['specificity_GBDT_LOF_IN', 0.854] ['recall_GBDT_NI:', 0.634] ['f1_GBDT_NI:', 0.692]

考察

外れ値を除くだけでも全体的に改善が見られた。
外れ値除外と特徴選択を組みあせた場合は、外れ値除外のみと比較して感度は若干改善したが、全体として大きな改善は見られなかった。

参考資料

機械学習における前処理3 欠損値・外れ値・不均衡データ
【外れ値,python】Local outlier Factor(LoF)の紹介【scikit-learn】
Local Outlier Factor

0
1
0

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
0
1