pythonでオーバーサンプリングの実行

# 機械学習を実施したいけどデータ数が足りない

前回の記事では

https://qiita.com/TaichiEndoh/items/77877ac93cdf9dc782e7

院内での医療機器管理データベースを利用し
過去の傾向から予想したい医療機器の情報を予想しました
0か1で予想する比較的簡単な2値分類を実行しました

ここで特徴量を削減しすぎたため
予測精度が悪くなるといった問題が出ました

それ以外にもデータの傾向を見ると
不均衡データとなっていました

そこで今回はオーバーサンプリングを実施したいと思います

# オーバーサンプリング とは
「少数派のデータを多数派に合わせて増やす」という方法
不均衡データという「データ構造に偏りがあるデータ群」に対して有用です

https://toukei-lab.com/imbalance-data-smote

オーバーサンプリングの中で特によく使われる手法が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セッションは医療機器業界で有名な大石さんの
『医療機器管理の井戸端会議』のことも聞けるセッションとなってます
興味のある方は是非参加よろしくお願いします！

https://jace32.com/