Scikit วิธีที่ถูกต้องในการปรับเทียบตัวแยกประเภทด้วย CalibratedClassifierCV


16

Scikit มีCalibratedClassifierCVซึ่งช่วยให้เราสามารถสอบเทียบโมเดลของเราในคู่ X, y ที่เฉพาะเจาะจง มันยังระบุไว้อย่างชัดเจนว่าdata for fitting the classifier and for calibrating it must be disjoint.

หากพวกเขาจะต้องแยกจากกันมันถูกต้องหรือไม่ที่จะฝึกตัวจําแนก

model = CalibratedClassifierCV(my_classifier)
model.fit(X_train, y_train)

ฉันกลัวว่าด้วยการใช้ชุดฝึกอบรมชุดเดียวกันฉันกำลังฝ่าฝืนdisjoint dataกฎ ทางเลือกอื่นอาจมีชุดการตรวจสอบความถูกต้อง

my_classifier.fit(X_train, y_train)
model = CalibratedClassifierCV(my_classifier, cv='prefit')
model.fit(X_valid, y_valid)

ซึ่งมีข้อเสียคือการทิ้งข้อมูลไว้เพื่อการฝึกอบรมน้อยลง นอกจากนี้หากCalibratedClassifierCVควรพอดีกับรุ่นที่พอดีกับชุดการฝึกอบรมที่แตกต่างกันเหตุใดจึงเป็นตัวเลือกเริ่มต้นcv=3ซึ่งจะพอดีกับตัวประมาณการพื้นฐาน การตรวจสอบความถูกต้องไขว้จัดการกฎความไม่ลงรอยกันด้วยตัวเองหรือไม่?

คำถาม: วิธีที่ถูกต้องในการใช้ CalibratedClassifierCV คืออะไร?

คำตอบ:


18

มีสองสิ่งที่กล่าวไว้ในเอกสาร CalibratedClassifierCVที่บอกใบ้ถึงวิธีการใช้:

base_estimator:ถ้า cv = prefit ตัวแยกประเภทต้องพอดีกับข้อมูลอยู่แล้ว

cv:ถ้าผ่าน“ prefit” จะถือว่ามีการติดตั้ง base_estimator ไว้แล้วและข้อมูลทั้งหมดจะถูกใช้สำหรับการสอบเทียบ

เห็นได้ชัดว่าฉันอาจตีความผิดนี้ แต่ดูเหมือนว่าคุณสามารถใช้ CCCV (ย่อมาจาก CalibratedClassifierCV) ได้สองวิธี:

ที่หนึ่ง:

  • คุณฝึกฝนโมเดลของคุณตามปกติ, your_model.fit(X_train, y_train).
  • จากนั้นคุณสร้างตัวอย่าง CCCV your_cccv = CalibratedClassifierCV(your_model, cv='prefit')ของคุณ ขอให้สังเกตว่าคุณตั้งค่าcvสถานะว่าแบบจำลองของคุณเหมาะสมแล้ว
  • your_cccv.fit(X_validation, y_validation)สุดท้ายคุณเรียก ข้อมูลการตรวจสอบนี้ใช้สำหรับการสอบเทียบเท่านั้น

หมายเลขสอง:

  • คุณมีโมเดลใหม่ที่ไม่ได้รับการฝึกฝน
  • your_cccv=CalibratedClassifierCV(your_untrained_model, cv=3)จากนั้นคุณสร้าง การแจ้งให้ทราบในcvขณะนี้คือจำนวนเท่า
  • your_cccv.fit(X, y)สุดท้ายคุณเรียก เนื่องจากโมเดลของคุณไม่ได้รับการฝึกฝน X และ y จึงต้องใช้สำหรับการฝึกอบรมและการสอบเทียบ วิธีการตรวจสอบให้แน่ใจว่าข้อมูลคือ 'disjoint' คือการตรวจสอบความถูกต้องไขว้กัน: สำหรับการพับใด ๆ CCCV จะแยก X และ y ออกเป็นข้อมูลการฝึกอบรมและการสอบเทียบของคุณดังนั้นจึงไม่ทับซ้อนกัน

TLDR: วิธีที่หนึ่งช่วยให้คุณควบคุมสิ่งที่ใช้สำหรับการฝึกอบรมและการสอบเทียบ วิธีที่สองใช้การตรวจสอบความถูกต้องไขว้เพื่อพยายามใช้ประโยชน์จากข้อมูลของคุณให้เกิดประโยชน์สูงสุดสำหรับทั้งสองจุดประสงค์


14

ฉันสนใจในคำถามนี้เช่นกันและต้องการเพิ่มการทดลองบางอย่างเพื่อทำความเข้าใจ CalibratedClassifierCV (CCCV) ให้ดีขึ้น

ตามที่ได้กล่าวไปแล้วมีสองวิธีในการใช้งาน

#Method 1, train classifier within CCCV
model = CalibratedClassifierCV(my_clf)
model.fit(X_train_val, y_train_val)

#Method 2, train classifier and then use CCCV on DISJOINT set
my_clf.fit(X_train, y_train)
model = CalibratedClassifierCV(my_clf, cv='prefit')
model.fit(X_val, y_val)

อีกวิธีหนึ่งเราสามารถลองวิธีที่สอง แต่เพียงปรับเทียบข้อมูลเดียวกันกับที่เราติดตั้ง

#Method 2 Non disjoint, train classifier on set, then use CCCV on SAME set used for training
my_clf.fit(X_train_val, y_train_val)
model = CalibratedClassifierCV(my_clf, cv='prefit')
model.fit(X_train_val, y_train_val)

แม้ว่าเอกสารเตือนว่าจะใช้ชุด disjoint แต่ก็มีประโยชน์เพราะช่วยให้คุณสามารถตรวจสอบได้my_clf(เช่นเพื่อดูcoef_ซึ่งไม่สามารถใช้งานได้จากวัตถุ CalibratedClassifierCV) (ไม่มีใครรู้วิธีที่จะได้รับสิ่งนี้จากตัวแยกประเภทที่สอบเทียบ --- สำหรับหนึ่งมีสามของพวกเขาดังนั้นคุณจะสัมประสิทธิ์เฉลี่ยหรือไม่)

ฉันตัดสินใจเปรียบเทียบทั้งสามวิธีนี้ในแง่ของการสอบเทียบของพวกเขาในชุดการทดสอบที่จัดขึ้นอย่างสมบูรณ์

นี่คือชุดข้อมูล:

X, y = datasets.make_classification(n_samples=500, n_features=200,
                                    n_informative=10, n_redundant=10,
                                    #random_state=42, 
                                    n_clusters_per_class=1, weights = [0.8,0.2])

ฉันโยนความไม่สมดุลในชั้นเรียนและให้ตัวอย่างเพียง 500 ตัวอย่างเพื่อให้เป็นปัญหาที่ยาก

ฉันรันการทดสอบ 100 ครั้งในแต่ละครั้งที่ลองแต่ละวิธีและวางแผนกราฟการปรับเทียบ

ป้อนคำอธิบายรูปภาพที่นี่

Boxplots ของคะแนน Brier เหนือการทดลองทั้งหมด:

ป้อนคำอธิบายรูปภาพที่นี่

เพิ่มจำนวนตัวอย่างเป็น 10,000:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

หากเราเปลี่ยนลักษณนามเป็น Naive Bayes ให้ย้อนกลับไปที่ 500 ตัวอย่าง:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

สิ่งนี้ดูเหมือนจะไม่เพียงพอสำหรับการสอบเทียบ เพิ่มตัวอย่างเป็น 10,000

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

รหัสเต็ม

print(__doc__)

# Based on code by Alexandre Gramfort <alexandre.gramfort@telecom-paristech.fr>
#         Jan Hendrik Metzen <jhm@informatik.uni-bremen.de>

import matplotlib.pyplot as plt

from sklearn import datasets
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import brier_score_loss
from sklearn.calibration import CalibratedClassifierCV, calibration_curve
from sklearn.model_selection import train_test_split


def plot_calibration_curve(clf, name, ax, X_test, y_test, title):

    y_pred = clf.predict(X_test)
    if hasattr(clf, "predict_proba"):
        prob_pos = clf.predict_proba(X_test)[:, 1]
    else:  # use decision function
        prob_pos = clf.decision_function(X_test)
        prob_pos = \
            (prob_pos - prob_pos.min()) / (prob_pos.max() - prob_pos.min())

    clf_score = brier_score_loss(y_test, prob_pos, pos_label=y.max())

    fraction_of_positives, mean_predicted_value = \
        calibration_curve(y_test, prob_pos, n_bins=10, normalize=False)

    ax.plot(mean_predicted_value, fraction_of_positives, "s-",
             label="%s (%1.3f)" % (name, clf_score), alpha=0.5, color='k', marker=None)

    ax.set_ylabel("Fraction of positives")
    ax.set_ylim([-0.05, 1.05])
    ax.set_title(title)

    ax.set_xlabel("Mean predicted value")

    plt.tight_layout()
    return clf_score

    fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1, figsize=(6,12))

    ax1.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated",)
    ax2.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")
    ax3.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")

    scores = {'Method 1':[],'Method 2':[],'Method 3':[]}


fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1, figsize=(6,12))

ax1.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated",)
ax2.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")
ax3.plot([0, 1], [0, 1], "k:", label="Perfectly calibrated")

scores = {'Method 1':[],'Method 2':[],'Method 3':[]}

for i in range(0,100):

    X, y = datasets.make_classification(n_samples=10000, n_features=200,
                                        n_informative=10, n_redundant=10,
                                        #random_state=42, 
                                        n_clusters_per_class=1, weights = [0.8,0.2])

    X_train_val, X_test, y_train_val, y_test = train_test_split(X, y, test_size=0.80,
                                                        #random_state=42
                                                               )

    X_train, X_val, y_train, y_val = train_test_split(X_train_val, y_train_val, test_size=0.80,
                                                      #random_state=42
                                                     )

    #my_clf = GaussianNB()
    my_clf = LogisticRegression()

    #Method 1, train classifier within CCCV
    model = CalibratedClassifierCV(my_clf)
    model.fit(X_train_val, y_train_val)
    r = plot_calibration_curve(model, "all_cal", ax1, X_test, y_test, "Method 1")
    scores['Method 1'].append(r)

    #Method 2, train classifier and then use CCCV on DISJOINT set
    my_clf.fit(X_train, y_train)
    model = CalibratedClassifierCV(my_clf, cv='prefit')
    model.fit(X_val, y_val)
    r = plot_calibration_curve(model, "all_cal", ax2, X_test, y_test, "Method 2")
    scores['Method 2'].append(r)

    #Method 3, train classifier on set, then use CCCV on SAME set used for training
    my_clf.fit(X_train_val, y_train_val)
    model = CalibratedClassifierCV(my_clf, cv='prefit')
    model.fit(X_train_val, y_train_val)
    r = plot_calibration_curve(model, "all_cal", ax3, X_test, y_test, "Method 2 non Dis")
    scores['Method 3'].append(r)

import pandas
b = pandas.DataFrame(scores).boxplot()
plt.suptitle('Brier score')

ดังนั้นผลลัพธ์ของคะแนน Brier นั้นไม่สามารถสรุปได้ แต่ตามเส้นโค้งมันเป็นวิธีที่ดีที่สุดในการใช้วิธีที่สอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.