การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน
ผู้เรียนจะคำนวณความถี่ของคลาส เปิดเผยกับดักของตัวจำแนกจำลองบนชุดข้อมูลที่ไม่สมดุล และยืนยันว่าความแม่นยำเป็นตัวชี้วัดที่ทำให้เข้าใจผิดในกรณีนี้
การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน เป็นบทเรียน Machine Learning Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Machine Learning Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
ความไม่สมดุลของคลาสคืออะไร
ความไม่สมดุลของคลาส เกิดขึ้นเมื่อคลาสหนึ่งมีสัดส่วนมากกว่าคลาสอื่นอย่างมากในชุดข้อมูล ในการตรวจจับการฉ้อโกง ธุรกรรมที่เป็นการฉ้อโกงอาจมีเพียง 0.1% ของระเบียนทั้งหมด ส่วนการวินิจฉัยทางการแพทย์ โรคหายากอาจพบในผู้ป่วยเพียง 1 คนจาก 1,000 คน โมเดลที่ทำนายคลาสส่วนใหญ่เสมอจะได้ความแม่นยำ 99.9% ทั้งที่ไม่ได้สนใจคลาสส่วนน้อยที่มีความสำคัญเลย ทำให้ความแม่นยำเป็นตัวชี้วัดที่ทำให้เข้าใจผิดอย่างอันตรายในสถานการณ์เหล่านี้
การวัดการกระจายของคลาส
ก่อนฝึกโมเดลใด ๆ ให้ตรวจสอบการกระจายของคลาสด้วย pd.Series(y).value_counts() หรือ np.bincount(y) ค่าสถิติสรุปที่มีประโยชน์คือ อัตราส่วนความไม่สมดุล ซึ่งเป็นอัตราส่วนระหว่างจำนวนตัวอย่างของคลาสส่วนใหญ่กับคลาสส่วนน้อย อัตราส่วนที่มากกว่า 10:1 ถือว่าไม่สมดุล ส่วนอัตราส่วนที่มากกว่า 100:1 ถือว่าไม่สมดุลอย่างรุนแรงและจำเป็นต้องใช้เทคนิคเฉพาะ
import numpy as np
import pandas as pd
# Simulate imbalanced binary classification dataset
np.random.seed(0)
y = np.array([0] * 950 + [1] * 50) # 95% negative, 5% positive
counts = pd.Series(y).value_counts()
print('Class counts:\n', counts)
print()
print('Class proportions:\n', counts / len(y))
print()
print('Imbalance ratio:', counts[0] / counts[1])กับดักของความแม่นยำเมื่อข้อมูลไม่สมดุล
ในชุดข้อมูลที่มีตัวอย่างเป็นลบ 95% โมเดลที่ ทำนายคลาสส่วนใหญ่ (คลาสลบ) เสมอ จะได้ความแม่นยำ 95% โดยไม่ได้เรียนรู้อะไรที่เป็นประโยชน์เลย นี่คือ กับดักของความแม่นยำ โมเดลไม่มีความสามารถในการตรวจจับกรณีเป็นบวกเลย ซึ่งเป็นคลาสที่คุณสนใจจริง ๆ แต่ความแม่นยำกลับดูน่าประทับใจ นี่จึงเป็นเหตุผลว่าทำไมชุดข้อมูลที่ไม่สมดุลจึงต้องใช้ตัวชี้วัดที่มากกว่าความแม่นยำ
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score, classification_report
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05],
random_state=42, n_features=10)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# Always predict majority class
dummy = DummyClassifier(strategy='most_frequent')
dummy.fit(X_train, y_train)
y_pred = dummy.predict(X_test)
print('Accuracy:', accuracy_score(y_test, y_pred).round(4))
print()
print(classification_report(y_test, y_pred))เหตุใดค่าพื้นฐานจาก DummyClassifier จึงสำคัญ
DummyClassifier ที่ใช้ strategy='most_frequent' คือ ค่าพื้นฐานขั้นต่ำที่ยอมรับได้ โมเดลจริงทุกตัวต้องทำได้ดีกว่านี้อย่างมีนัยสำคัญ ไม่ใช่แค่ในด้านความแม่นยำ แต่รวมถึงตัวชี้วัดที่สำคัญด้วย เช่น ความแม่นยำเชิงบวก ความครอบคลุม F1 หรือ AUC-ROC หากโมเดลจริงของคุณดีกว่าโมเดลจำลองเพียงเล็กน้อย ก็มีแนวโน้มว่าโมเดลนั้นเรียนรู้ที่จะเพิกเฉยต่อคลาสส่วนน้อยเช่นกัน
from sklearn.linear_model import LogisticRegression
from sklearn.dummy import DummyClassifier
from sklearn.metrics import classification_report
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
X_train_s = StandardScaler().fit_transform(X_train)
X_test_s = StandardScaler().fit_transform(X_test)
lr = LogisticRegression().fit(X_train_s, y_train)
print('--- Logistic Regression ---')
print(classification_report(y_test, lr.predict(X_test_s)))ความแม่นยำเชิงบวกและความครอบคลุมเมื่อข้อมูลไม่สมดุล
สำหรับปัญหาที่ข้อมูลไม่สมดุล ตัวชี้วัดที่ให้ข้อมูลมากที่สุดสองรายการคือ: ความแม่นยำเชิงบวก = TP / (TP + FP) — จากทุกกรณีที่ทำนายว่าเป็นบวก มีกี่กรณีที่เป็นบวกจริง ความครอบคลุม = TP / (TP + FN) — จากทุกกรณีที่เป็นบวกจริง โมเดลตรวจพบได้กี่กรณี ในการตรวจจับการฉ้อโกง ความครอบคลุมสำคัญที่สุด (ต้องไม่พลาดการฉ้อโกง) ส่วนการกรองสแปม ความแม่นยำเชิงบวกสำคัญกว่า (ต้องไม่จัดประเภทอีเมลที่ถูกต้องเป็นสแปม)
from sklearn.metrics import precision_score, recall_score, f1_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
X_train_s = StandardScaler().fit_transform(X_train)
X_test_s = StandardScaler().fit_transform(X_test)
lr = LogisticRegression().fit(X_train_s, y_train)
y_pred = lr.predict(X_test_s)
print(f'Precision: {precision_score(y_test, y_pred):.4f}')
print(f'Recall: {recall_score(y_test, y_pred):.4f}')
print(f'F1-Score: {f1_score(y_test, y_pred):.4f}')ROC-AUC: การประเมินที่ไม่ขึ้นกับค่าเกณฑ์
ROC-AUC ประเมินโมเดลที่ค่าเกณฑ์การตัดสินใจที่เป็นไปได้ทั้งหมด และวัดพื้นที่ใต้เส้นโค้งที่ได้ AUC เท่ากับ 0.5 หมายถึงการสุ่ม 1.0 หมายถึงสมบูรณ์แบบ และค่าตั้งแต่ 0.9 ขึ้นไปถือว่ายอดเยี่ยม ต่างจากความแม่นยำ AUC ไม่ได้รับผลกระทบจากความไม่สมดุลของคลาส เพราะประเมิน ความสามารถในการจัดลำดับ ของโมเดล แทนการทำนายด้วยค่าเกณฑ์คงที่ โดยทั่วไปแนะนำให้ใช้ AUC เป็นตัวชี้วัดหลักสำหรับงานจำแนกประเภทแบบสองคลาสที่ข้อมูลไม่สมดุล
from sklearn.metrics import roc_auc_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
sc = StandardScaler()
X_train_s = sc.fit_transform(X_train)
X_test_s = sc.transform(X_test)
lr = LogisticRegression().fit(X_train_s, y_train)
proba = lr.predict_proba(X_test_s)[:, 1]
print('ROC-AUC:', roc_auc_score(y_test, proba).round(4))การแสดงภาพความไม่สมดุลของคลาส
แผนภูมิแท่งอย่างง่ายที่แสดงความถี่ของแต่ละคลาสช่วยสื่อให้ผู้มีส่วนได้ส่วนเสียเห็นความไม่สมดุลได้ทันที ควรใส่แผนภูมินี้ไว้ในสมุดบันทึกการวิเคราะห์ข้อมูลเชิงสำรวจเป็นแนวปฏิบัติมาตรฐาน หากคุณทำงานกับ Pandas DataFrame ควรตรวจสอบความไม่สมดุลที่ซ่อนอยู่ซึ่งเกิดจากอคติในการรวบรวมข้อมูล ไม่ใช่จากความหายากที่แท้จริงในโลกจริงด้วย
import matplotlib.pyplot as plt
import numpy as np
y = np.array([0] * 950 + [1] * 50)
classes, counts = np.unique(y, return_counts=True)
plt.bar(['Negative (0)', 'Positive (1)'], counts, color=['#2196F3', '#F44336'])
plt.ylabel('Count')
plt.title('Class Distribution (95:5 imbalance)')
for i, c in enumerate(counts):
plt.text(i, c + 5, str(c), ha='center', fontweight='bold')
plt.show()การแบ่งข้อมูลแบบแบ่งชั้นเพื่อรักษาอัตราส่วน
เมื่อแบ่งชุดข้อมูลที่ไม่สมดุล ให้ใช้ stratify=y ใน train_test_split หากไม่แบ่งชั้น ความบังเอิญในการสุ่มอาจทำให้ตัวอย่างของคลาสส่วนน้อยทั้งหมดไปอยู่ในส่วนเดียว ส่งผลให้การฝึกหรือการประเมินไม่มีความหมาย การแบ่งแบบแบ่งชั้นช่วยให้ชุดฝึกและชุดทดสอบมีอัตราส่วนของคลาสเดียวกับชุดข้อมูลเดิม
from sklearn.model_selection import train_test_split
import numpy as np
y = np.array([0] * 950 + [1] * 50)
X = np.random.randn(1000, 5)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
print('Train class ratio:', (y_train == 1).mean().round(4))
print('Test class ratio:', (y_test == 1).mean().round(4))
print('Expected ratio:', (y == 1).mean().round(4))Stratified K-Fold สำหรับการตรวจสอบไขว้
ในทำนองเดียวกัน ให้ใช้ StratifiedKFold (หรือส่ง cv=5 ให้กับ cross_val_score โดย scikit-learn จะใช้ StratifiedKFold โดยอัตโนมัติสำหรับตัวจำแนกประเภท) เพื่อให้แต่ละส่วนย่อยรักษาอัตราส่วนของคลาสเดิมไว้ KFold ปกติที่มีคลาสส่วนน้อยจำนวนน้อยอาจสร้างส่วนย่อยที่ไม่มีตัวอย่างเป็นบวกเลย ทำให้เกิดข้อผิดพลาดหรือตัวชี้วัดที่ทำให้เข้าใจผิด
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import numpy as np
y = np.array([0] * 950 + [1] * 50)
X = np.random.randn(1000, 5)
pipe = Pipeline([('sc', StandardScaler()), ('lr', LogisticRegression())])
skf = StratifiedKFold(n_splits=5)
scores = cross_val_score(pipe, X, y, cv=skf, scoring='roc_auc')
print(f'Stratified CV AUC: {np.mean(scores):.4f} +/- {np.std(scores):.4f}')เส้นโค้ง Precision-Recall
สำหรับข้อมูลที่ไม่สมดุลอย่างมาก เส้นโค้ง precision-recall (PR) มักให้ข้อมูลมากกว่าเส้นโค้ง ROC เส้นโค้ง PR แสดง precision บนแกน y และ recall บนแกน x ที่ค่าเกณฑ์ทั้งหมด พื้นที่ใต้เส้นโค้ง PR (คะแนน AP) มีค่าตั้งแต่ 0 ถึง 1 และไวต่อประสิทธิภาพของคลาสส่วนน้อยในลักษณะที่ ROC-AUC อาจบดบังได้เมื่อคลาสส่วนใหญ่มีจำนวนมากเกินไป
from sklearn.metrics import precision_recall_curve, average_precision_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)
sc = StandardScaler()
X_train_s = sc.fit_transform(X_train)
X_test_s = sc.transform(X_test)
lr = LogisticRegression().fit(X_train_s, y_train)
proba = lr.predict_proba(X_test_s)[:, 1]
precision, recall, _ = precision_recall_curve(y_test, proba)
ap = average_precision_score(y_test, proba)
plt.plot(recall, precision, label=f'AP={ap:.3f}')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall Curve')
plt.legend()
plt.show()การจัดทำเอกสารความไม่สมดุลก่อนสร้างโมเดล
แนวปฏิบัติที่ดีคือ จัดทำ รายงานความไม่สมดุล ตั้งแต่เริ่มโครงการจำแนกประเภททุกโครงการ บันทึกจำนวนตัวอย่างของแต่ละคลาส อัตราส่วน และความแม่นยำพื้นฐานจากโมเดลจำลอง วิธีนี้ช่วยกำหนดความคาดหวังและทำให้ทีมตกลงกันได้ว่าควรใช้ตัวชี้วัดความสำเร็จใดก่อนฝึกโมเดล โมเดลตรวจจับการฉ้อโกงที่มีความแม่นยำ 95% มักไม่มีประโยชน์ ผู้มีส่วนได้ส่วนเสียของคุณควรทราบเรื่องนี้ตั้งแต่ต้น
import numpy as np
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score, roc_auc_score
y = np.array([0] * 950 + [1] * 50)
X = np.random.randn(1000, 5)
dummy = DummyClassifier(strategy='most_frequent').fit(X, y)
dummy_acc = accuracy_score(y, dummy.predict(X))
dummy_auc = roc_auc_score(y, dummy.predict_proba(X)[:, 1])
print('=== Imbalance Report ===')
print(f'Class 0: {(y==0).sum()} ({(y==0).mean():.1%})')
print(f'Class 1: {(y==1).sum()} ({(y==1).mean():.1%})')
print(f'Imbalance ratio: {(y==0).sum()/(y==1).sum():.0f}:1')
print(f'Dummy accuracy: {dummy_acc:.4f}')
print(f'Dummy AUC: {dummy_auc:.4f}')
print('Recommended metric: ROC-AUC or Precision-Recall AUC')ตรวจสอบความเข้าใจ
ทดสอบความเข้าใจเกี่ยวกับความไม่สมดุลของคลาสและข้อผิดพลาดของค่าพื้นฐานจากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า ความไม่สมดุลของคลาสทำให้ความแม่นยำเป็นตัวชี้วัดที่ทำให้เข้าใจผิด เพราะโมเดลที่ทำนายเฉพาะคลาสส่วนใหญ่อาจได้ความแม่นยำสูงมาก ควร เปรียบเทียบกับค่าพื้นฐานจาก DummyClassifier เสมอ เพื่อให้แน่ใจว่าโมเดลเรียนรู้สิ่งที่มากกว่าการทำนายแบบพื้นฐาน และควร ใช้ ROC-AUC หรือ AUC ของ precision-recall เป็นตัวชี้วัดหลักสำหรับชุดข้อมูลที่ไม่สมดุล บทถัดไปเราจะใช้ SMOTE และการเพิ่มตัวอย่างแบบสุ่มเพื่อเพิ่มตัวอย่างของคลาสส่วนน้อย
เรียนรู้ Python ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Machine Learning Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน”
ผู้เรียนจะคำนวณความถี่ของคลาส เปิดเผยกับดักของตัวจำแนกจำลองบนชุดข้อมูลที่ไม่สมดุล และยืนยันว่าความแม่นยำเป็นตัวชี้วัดที่ทำให้เข้าใจผิดในกรณีนี้ คุณปฏิบัติ Machine Learning Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Machine Learning Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Machine Learning Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Machine Learning Academy นี้ได้ไหม
ได้ บทเรียน Machine Learning Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน
- การสุ่มเพิ่มตัวอย่างและ SMOTE
- การสุ่มลดตัวอย่างและ ClusterCentroids
- น้ำหนักคลาสและการเลื่อนเกณฑ์ตัดสินใจ