[Project-ソウル市のスモッグ予測]3Random Forestを用いてスモッグ濃度を予測する


...ソウル市の大気品質データで2日間行われた小さなプロジェクトの記録.

Random Forest


Random Forestは,複数のツリーを収集することによって過剰なマッチングを防止するモデルといえる.この記事では、詳しくは説明しませんが、複数のモデルを用いた組み合わせ(Ensemble)には大きなbaggingとboostingがあり、Random Forestは複数の同じモデルDecision Treeを用いたbagging方式です.

ソース:GreyAtom's medium
繰り返し抽出(with replacement)でデータを抽出して複数のツリーに入れるだけでなく、各ツリーで使用される特徴もそれぞれ異なるサンプリングを行う.最後に,各ツリー区分の結果(分類)を投票で集計する.その利点は、数本の木が過度にフィットしても、複数の木があるために1、2本の木の影響力を減らすことです.
このプロジェクトはスモッグの危険レベルを分類する任務であるため、ランダムForestを使用するのに適している.重要なデータを扱うのは難しいが、データセット作成時にTIMETEP T-1の大気質とTの予想天気を調整したため、Tのスモッグ濃度を求めることができるのである程度の補完が得られる.
また、bad、fastデータ(以下の2番と3番のデータ)が少ないため、データサンプリング中に比重を高めるためにbad caseを容易に調整できる点も魅力的です.この部分は以下の実験の部分で補足説明する.

Split Test set


以前に機械学習のために整理したデータではtestにtest setを区分した.ここではtest ratioを30%に設定します.
from sklearn.model_selection import train_test_split

X = df.drop('pm25_cat', axis=1)
y = df['pm25_cat']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=opt.test_ratio, random_state=SEED)
print('X_train: {:,} \nX_test: {:,}\ny_train: {:,} \ny_test: {:,}'.format(len(X_train), len(X_test), len(y_train),
                                                                  len(y_test)))

test setは30%で構築され、train:test=20358:8725が分割された.featureデータとlabelをそれぞれ異なる変数に割り当て、trainとtestに再分割する場合はtorchを使用します.utils.data.sklearnのtrain test splitはrandom splitより便利です.

Test Metric


シリーズの最初の記事では、このプロジェクトの目的はBad Recallを向上させることとして定義されています.そのため、相応の評価指標を制定した.


Sklernの混同行列を求め,次いでPredict bad+Predict mustをTrue bad+True mustに分ける.すなわち,実際のbadと最悪の場合の数字では,モデルはbadと最悪の分類数字の比率を求めた.ここでは、実際の状況が最悪であり、badと予測される場合と実際の状況がbadであり、最悪の場合も適切な場合に含まれる.単純F 1 scoreや精度とは異なり、本目的でカスタマイズしたメジャーです.
結果の混同行列から,{realt bad and predicated bad(1300)+realt bad and predicated mast(21)+realt must and predicated bad(139)+realt mastandpredpredicated(85)}/{realt bad total(1510)+realt mast total(274)}値はbad recall scoreとなった.

Various weight and max depth


sklearningのRandom Forestはmax depthとclass weightをパラメータとしてモデリングすることができる.max depthはtree labelの最大値を設定するパラメータです.最大深さを適切に調整し、貼り過ぎを防止します.
class weightは、ツリーに入るデータをサンプリングして置き換えるときに、クラスごとにより頻繁に発生する頻度を提供します.badとfastを見つけることに集中しなければならないが、実際のデータには対応するケースが欠けているため、この2つの重みを高めようとしている.以下は実験カタログです.Weightは3種類,depthは4種類あり,それぞれ試験を行い,合計12の組合せを有した.


じっけんコード
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, f1_score
from sklearn.metrics import classification_report

def custom_metric(matrix):
    bad = matrix.loc['truth_bad'][:-1]
    worst = matrix.loc['truth_worst'][:-1]
    t_bad = sum(bad)
    t_worst = sum(worst)
    right_bad = bad['pr_bad']+bad['pr_worst']
    right_worst = worst['pr_worst']+worst['pr_bad']
    return round(((right_bad + right_worst) / (t_bad + t_worst)), 4)

def modeling(depth, weight, X_train, y_train, X_test):
    clf = RandomForestClassifier(max_depth=depth, class_weight=weight, random_state=SEED)
    clf.fit(X_train, y_train)
    predicted = clf.predict(X_test)
    return predicted

def get_scores(y_test, predicted):
    cf = pd.DataFrame(confusion_matrix(y_test, predicted))
    cf.index = ['truth_good', 'truth_moderate', 'truth_bad', 'truth_worst']
    cf.columns = ['pr_good', 'pr_moderate', 'pr_bad', 'pr_worst']
    cf['truth_total'] = cf['pr_good']+cf['pr_moderate']+cf['pr_bad']+cf['pr_worst']
    recall_bad = custom_metric(cf)
    acc = round(accuracy_score(y_test, predicted), 4)
    f1 = round(f1_score(y_test, predicted, average='macro'), 4)
    
    print(' >> recall_bad: {:.02f}%'.format(recall_bad*100))
    print(' >> total acc.: {:.02f}%'.format(acc*100))
    print(' >> total F1: {:.02f}'.format(f1*100))
    return recall_bad, acc, f1, cf

def run(X_train, y_train, X_test, y_test, depth, weight):
    predicted = modeling(depth, weight, X_train, y_train, X_test)
    print('max_depth: {:} | class_weight: {:}'.format(depth, weight))
    _, _, _, cf = get_scores(y_test, predicted)
    return

weight = [None, {0:1, 1:1, 2:2, 3:3}, {0:1, 1:1, 2:3, 3:5}]
depth = [8, 10, 12, 15]

for i in weight:
    for j in depth:
        run(X_train, y_train, X_test, y_test, j, i)

Result


maxdepthが8、クラスウェイトが{1、1、3、5}に設定されている場合、最高のbad recallスコアが記録されます.すなわち,badcaseに対して3の重み付けを行い,最悪のcaseに対して5の重み付けサンプリングを行った.データを増やして学習することで,両者を予測する上で良好な成果を収めた.
一番下の表は深さ学習モデルを含むすべての実験結果であり,学習過程でbad,fastケースを増加させることは簡単なLSTMモデルの結果よりも得点が良い原因のようである.しかし,総合性能(精度とf 1 score)はbad,最悪強化度が低下したり,適用されなかったりするモデルよりも低かった.最も目標を達成できるモデルのために,一般的に用いられるパフォーマンス指標が取引されているといえる.


Random Forestフルコード>github