機械学習を実施したいけどデータ数が足りない
前回の記事では
院内での医療機器管理データベースを利用し
過去の傾向から予想したい医療機器の情報を予想しました
0か1で予想する比較的簡単な2値分類を実行しました
ここで特徴量を削減しすぎたため
予測精度が悪くなるといった問題が出ました
それ以外にもデータの傾向を見ると
不均衡データとなっていました
そこで今回はオーバーサンプリングを実施したいと思います
オーバーサンプリング とは
「少数派のデータを多数派に合わせて増やす」という方法
不均衡データという「データ構造に偏りがあるデータ群」に対して有用です
オーバーサンプリングの中で特によく使われる手法がSMOTEと呼ばれるものです
SMOTEは、Synthetic Minority Over-sampling TEchniqueの略で
少数派のサンプルを増やしていきます
1.オーバーサンプリングの前準備 データをtrain, test, validationの3つに分割
#テストデータをtest_df とする
test_dfp = pd.concat([y_test_df,X_test_df], axis=1)
test_df=test_dfp.rename(columns={0:"i"})
test_df
#pd.DataFrame に戻して 縦に train val 結合していく
y_trainp = pd.DataFrame(y_train)
X_trainp = pd.DataFrame(X_train)
train=pd.concat([y_trainp, X_trainp], axis=1)
train
y_valp = pd.DataFrame(y_val)
X_valp = pd.DataFrame(X_val)
val=pd.concat([y_valp, X_valp], axis=1)
val
test_vol=pd.concat([train, val])
test_vol
#yの目的変数のカラムが0になってるので target に変化
order_of_things=test_vol.rename(columns={0:"i"})
order_of_things
order_of_things1=order_of_things
2.オーバーサンプリングの実行
from imblearn import FunctionSampler
from imblearn.over_sampling import SMOTE
#オーバーサンプリング marge_data_over_sampling
X = order_of_things1.drop("target",axis=1).values
Y = order_of_things1["target"].values
columns_name = order_of_things1.drop("target",axis=1).columns
from imblearn.over_sampling import SMOTE
sm = SMOTE(sampling_strategy =0.5, random_state=42)
X_res, Y_res = sm.fit_sample(X, Y)
y_valp_p = pd.DataFrame(Y_res)
y_valp=y_valp_p.rename(columns={0:"target"})
print(y_valp)
X_valp = pd.DataFrame(X_res, columns=columns_name)
print(X_valp)
val=pd.concat([y_valp, X_valp], axis=1)
print(val)
SMOTE_dfp=val.rename(columns={0:"i"})
#ここでシャッフルさせる
SMOTE_df=SMOTE_dfp.sample(frac=1, random_state=0)
print(SMOTE_df.shape)
marge_data_over_sampling=pd.concat([SMOTE_df, test_df])
print("marge_data_over_sampling.shape")
print(marge_data_over_sampling.shape)
marge_data_over_sampling
これでテストデータ以外のデータのオーバーサンプリングができました
3.オーバーサンプリング後のモデルの訓練と評価
# Isolate the objective variable
X = SMOTE_df.drop("target",axis=1).values
y = SMOTE_df["target"].values
columns_name = SMOTE_df.drop("target",axis=1).columns
def Test_data_and_training_data_split(df,X,Y):
N_train = int(len(df) * 0.8)
N_test = len(df) - N_train
X_train, X_test, y_train, y_test = \
train_test_split(X, Y, test_size=N_test,shuffle=False,random_state=42)
return X_train, X_test, y_train, y_test
# Execute a function that separates the data for training from the data for validation.
X_train,X_val, y_train,y_val = Test_data_and_training_data_split(merge_data_p,X,y)
#連番の値にするためあえてカラム名を使わない :: の文字が使えないため
#X_test = pd.DataFrame(X_test, columns=columns_name)
#X_val = pd.DataFrame(X_val, columns=columns_name)
X_val = pd.DataFrame(X_val)
y_valp = pd.DataFrame(y_val)
y_val=y_valp.rename(columns={0:"target"})
#X_train = pd.DataFrame(X_train, columns=columns_name)
X_train = pd.DataFrame(X_train)
y_trainp = pd.DataFrame(y_train)
y_train =y_trainp.rename(columns={0:"target"})
# shape 確認
print("train shape", X_train.shape)
print("test shape", X_test.shape)
print("validation shape", X_val.shape)
X_test_df = pd.DataFrame(X_test)
# shape 確認
print("y_train shape", y_train.shape)
print("y_test shape", y_test.shape)
print("y_validation shape", y_val.shape)
y_test_df = pd.DataFrame(y_test)
print("y_test describe",y_test_df.describe())
print("not_ y_test describe",(~y_test_df.duplicated()).sum())
#y_test_df.value_counts().plot(kind="bar")
print("y_test_df.duplicated().sum()",y_test_df.duplicated().sum())
#print(y_test_df[y_test_df.duplicated()])
#テストデータをtest_df とする
test_dfp = pd.concat([y_test_df,X_test_df], axis=1)
test_df=test_dfp
test_df
#lightGBMの実装
import lightgbm as lgb
# データセットを生成する
from sklearn import metrics
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_val, y_val, reference=lgb_train)
# LightGBM のハイパーパラメータ
lgbm_params = {
# 二値分類問題
'objective': 'binary',
# AUC の最大化を目指す
'metric': 'auc',
}
# 上記のパラメータでモデルを学習する
model = lgb.train(lgbm_params, lgb_train,
valid_sets=lgb_eval,
num_boost_round=100, # 最大イテレーション回数指定
)
# 保存
model.save_model('./model/model.txt')
# テストデータを予測する
y_pred = model.predict(X_test)
# 保存したモデルを使う場合はこんな感じ
#bst = lgb.Booster(model_file='model.txt')
#ypred = bst.predict(X_test, num_iteration=bst.best_iteration)
# AUC (Area Under the Curve) を計算する
fpr, tpr, thresholds = metrics.roc_curve(y_test, y_pred)
auc = metrics.auc(fpr, tpr)
print("auc",auc)
print("fpr False Positive Rate:偽陽性率",fpr)
print("tpr True Positive Rate:真陽性率",tpr)
print("thresholds",thresholds)
# ROC曲線をプロット
plt.plot(fpr, tpr, label='ROC curve (area = %.2f)'%auc)
plt.legend()
plt.title('ROC curve')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.grid(True)
auc 0.66
と前回に比べて向上しました!
今回使用したのはlightGBMと呼ばれる決定木系の
機械学習でしたが それ以外にも様々な機械学習があります
何を対象に機械学習を利用したのか?どのような問題点が医療現場であるのか?
具体的に知りたい方は
第32回日本臨床工学会で 2022年5月14日、BPA8セッションにて発表予定です
BPA8セッションは医療機器業界で有名な大石さんの
『医療機器管理の井戸端会議』のことも聞けるセッションとなってます
興味のある方は是非参加よろしくお願いします!