Pythonのさまざまなバイナリ分類子を比較したいと思います。そのために、ROC AUCスコアを計算し、95%信頼区間(CI)、およびを測定します。 p値統計的有意性にアクセスします。
以下は、バイナリ分類データセットで3つの異なるモデルをトレーニングし、ROC曲線をプロットし、AUCスコアを計算するscikit-learnの最小限の例です。
これが私の具体的な質問です:
。
import numpy as np
np.random.seed(2018)
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import roc_auc_score, roc_curve
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
import matplotlib
import matplotlib.pyplot as plt
data = load_breast_cancer()
X = data.data
y = data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=17)
# Naive Bayes Classifier
nb_clf = GaussianNB()
nb_clf.fit(X_train, y_train)
nb_prediction_proba = nb_clf.predict_proba(X_test)[:, 1]
# Ranodm Forest Classifier
rf_clf = RandomForestClassifier(n_estimators=20)
rf_clf.fit(X_train, y_train)
rf_prediction_proba = rf_clf.predict_proba(X_test)[:, 1]
# Multi-layer Perceptron Classifier
mlp_clf = MLPClassifier(alpha=1, hidden_layer_sizes=150)
mlp_clf.fit(X_train, y_train)
mlp_prediction_proba = mlp_clf.predict_proba(X_test)[:, 1]
def roc_curve_and_score(y_test, pred_proba):
fpr, tpr, _ = roc_curve(y_test.ravel(), pred_proba.ravel())
roc_auc = roc_auc_score(y_test.ravel(), pred_proba.ravel())
return fpr, tpr, roc_auc
plt.figure(figsize=(8, 6))
matplotlib.rcParams.update({'font.size': 14})
plt.grid()
fpr, tpr, roc_auc = roc_curve_and_score(y_test, rf_prediction_proba)
plt.plot(fpr, tpr, color='darkorange', lw=2,
label='ROC AUC={0:.3f}'.format(roc_auc))
fpr, tpr, roc_auc = roc_curve_and_score(y_test, nb_prediction_proba)
plt.plot(fpr, tpr, color='green', lw=2,
label='ROC AUC={0:.3f}'.format(roc_auc))
fpr, tpr, roc_auc = roc_curve_and_score(y_test, mlp_prediction_proba)
plt.plot(fpr, tpr, color='crimson', lw=2,
label='ROC AUC={0:.3f}'.format(roc_auc))
plt.plot([0, 1], [0, 1], color='navy', lw=1, linestyle='--')
plt.legend(loc="lower right")
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('1 - Specificity')
plt.ylabel('Sensitivity')
plt.show()
データの複数のリサンプリングで分析を繰り返したいと考えています。一般的なケースでは、データx
から必要な統計を決定する関数f(x)
があり、次のようにbootstrap:
def bootstrap(x, f, nsamples=1000):
stats = [f(x[np.random.randint(x.shape[0], size=x.shape[0])]) for _ in range(nsamples)]
return np.percentile(stats, (2.5, 97.5))
これにより、95%信頼区間のいわゆるプラグイン推定値が得られます(つまり、bootstrap分布)のパーセンタイルを取得するだけです)。
あなたの場合、あなたはこのようなより具体的な関数を書くことができます
def bootstrap_auc(clf, X_train, y_train, X_test, y_test, nsamples=1000):
auc_values = []
for b in range(nsamples):
idx = np.random.randint(X_train.shape[0], size=X_train.shape[0])
clf.fit(X_train[idx], y_train[idx])
pred = clf.predict_proba(X_test)[:, 1]
roc_auc = roc_auc_score(y_test.ravel(), pred.ravel())
auc_values.append(roc_auc)
return np.percentile(auc_values, (2.5, 97.5))
ここで、clf
はパフォーマンスをテストする分類子であり、X_train
、y_train
、X_test
、y_test
はあなたのコードのようです。
これにより、次の信頼区間が得られます(3桁に四捨五入、1000 bootstrapサンプル):
順列テストは、技術的には観測シーケンスのすべての順列を調べ、並べ替えられたターゲット値を使用してroc曲線を評価します(機能は並べ替えられません)。これは、いくつかの観測がある場合は問題ありませんが、より多くの観測がある場合は非常にコストがかかります。したがって、順列の数をサブサンプリングし、単純にいくつかのランダム順列を実行するのが一般的です。ここで、実装は、テストする特定のものにもう少し依存します。次の関数は、roc_auc値に対してそれを行います
def permutation_test(clf, X_train, y_train, X_test, y_test, nsamples=1000):
idx1 = np.arange(X_train.shape[0])
idx2 = np.arange(X_test.shape[0])
auc_values = np.empty(nsamples)
for b in range(nsamples):
np.random.shuffle(idx1) # Shuffles in-place
np.random.shuffle(idx2)
clf.fit(X_train, y_train[idx1])
pred = clf.predict_proba(X_test)[:, 1]
roc_auc = roc_auc_score(y_test[idx2].ravel(), pred.ravel())
auc_values[b] = roc_auc
clf.fit(X_train, y_train)
pred = clf.predict_proba(X_test)[:, 1]
roc_auc = roc_auc_score(y_test.ravel(), pred.ravel())
return roc_auc, np.mean(auc_values >= roc_auc)
この関数は、分類子をclf
として再び受け取り、シャッフルされていないデータのAUC値とp値(つまり、シャッフルされていないデータにあるもの以上のAUC値を観測する確率)を返します。
これを1000個のサンプルで実行すると、3つの分類子すべてのp値が0になります。これらはサンプリングのために正確ではありませんが、これらの分類子のすべてが偶然よりも優れたパフォーマンスを発揮することを示していることに注意してください。
これははるかに簡単です。 2つの分類子が与えられると、すべての観測値の予測があります。このように、予測と分類子の間の割り当てをシャッフルするだけです。
def permutation_test_between_clfs(y_test, pred_proba_1, pred_proba_2, nsamples=1000):
auc_differences = []
auc1 = roc_auc_score(y_test.ravel(), pred_proba_1.ravel())
auc2 = roc_auc_score(y_test.ravel(), pred_proba_2.ravel())
observed_difference = auc1 - auc2
for _ in range(nsamples):
mask = np.random.randint(2, size=len(pred_proba_1.ravel()))
p1 = np.where(mask, pred_proba_1.ravel(), pred_proba_2.ravel())
p2 = np.where(mask, pred_proba_2.ravel(), pred_proba_1.ravel())
auc1 = roc_auc_score(y_test.ravel(), p1)
auc2 = roc_auc_score(y_test.ravel(), p2)
auc_differences(auc1 - auc2)
return observed_difference, np.mean(auc_differences >= observed_difference)
このテストと1000のサンプルでは、3つの分類子の間に有意差は見つかりませんでした。
ここで、diffは2つの分類子間のroc曲線の差を示し、p(diff>)は、シャッフルされたデータセットでより大きな差を観測する経験的確率です。
以下のコードを使用して、ニューラルネットのAUCと漸近正規分布信頼区間を計算できます。
tf.contrib.metrics.auc_with_confidence_intervals(
labels,
predictions,
weights=None,
alpha=0.95,
logit_transformation=True,
metrics_collections=(),
updates_collections=(),
name=None)