Machine Learning Academy · บทเรียน

การสุ่มลดตัวอย่างและ ClusterCentroids

ผู้เรียนจะลดตัวอย่างของคลาสส่วนใหญ่แบบสุ่มและด้วย ClusterCentroids พร้อมเปรียบเทียบการสูญเสียข้อมูลกับประสิทธิภาพของแบบจำลองที่ได้

บทเรียน 3 จาก 413 ขั้นตอน

การสุ่มลดตัวอย่างและ ClusterCentroids เป็นบทเรียน Machine Learning Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Machine Learning Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน

การลดตัวอย่าง: ลดคลาสส่วนใหญ่

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

การลดตัวอย่างแบบสุ่ม: ลบตัวอย่างของคลาสส่วนใหญ่แบบสุ่ม

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

from imblearn.under_sampling import RandomUnderSampler
from sklearn.datasets import make_classification
import numpy as np

X, y = make_classification(n_samples=1000, weights=[0.95, 0.05],
                            n_features=10, random_state=42)

print('Before undersampling:', np.bincount(y))

rus = RandomUnderSampler(sampling_strategy=1.0, random_state=42)
X_res, y_res = rus.fit_resample(X, y)

print('After undersampling:', np.bincount(y_res))
print('New total samples:', len(y_res))

การควบคุมกลยุทธ์การสุ่มตัวอย่าง

พารามิเตอร์ sampling_strategy ใช้ควบคุมอัตราส่วนสุดท้ายระหว่างคลาสส่วนน้อยกับคลาสส่วนใหญ่ ค่า 1.0 ทำให้ทั้งสองคลาสมีจำนวนเท่ากัน ส่วนค่า 0.5 ทำให้คลาสส่วนใหญ่มีจำนวนมากกว่า 2:1 สำหรับชุดข้อมูลขนาดใหญ่มาก คุณอาจตั้งค่า 0.1 เพื่อสร้างอัตราส่วน 10:1 ซึ่งยังดีกว่าอัตราส่วนเดิม 100:1 และช่วยให้การฝึกยังรวดเร็ว เลือกค่าตามต้นทุนทางธุรกิจของผลบวกลวงเทียบกับผลลบลวง

from imblearn.under_sampling import RandomUnderSampler
from sklearn.datasets import make_classification
import numpy as np

X, y = make_classification(n_samples=10000, weights=[0.99, 0.01], random_state=42)
print('Original:', np.bincount(y))

for ratio in [1.0, 0.5, 0.2]:
    rus = RandomUnderSampler(sampling_strategy=ratio, random_state=0)
    _, y_r = rus.fit_resample(X, y)
    counts = np.bincount(y_r)
    print(f'ratio={ratio}: {counts} ({counts[1]/counts[0]:.2f} min:maj)')

Cluster Centroids: การลดตัวอย่างอย่างชาญฉลาด

ClusterCentroids ใช้การจัดกลุ่มแบบ K-Means กับคลาสส่วนใหญ่ แล้วแทนที่แต่ละกลุ่มด้วยเซนทรอยด์ แทนที่จะเก็บตัวอย่างจากคลาสส่วนใหญ่แบบสุ่ม วิธีนี้จะเก็บชุดข้อมูลที่กระชับและเป็นตัวแทนของข้อมูลไว้ ซึ่งรักษาโครงสร้างโดยรวมของคลาสส่วนใหญ่ได้ดีกว่าการลบแบบสุ่ม แต่ทำงานช้ากว่าและต้องปรับจำนวนกลุ่ม (ซึ่งจะเท่ากับจำนวนเป้าหมายของคลาสส่วนใหญ่หลังการสุ่มตัวอย่างใหม่)

from imblearn.under_sampling import ClusterCentroids
from sklearn.datasets import make_classification
import numpy as np

X, y = make_classification(n_samples=1000, weights=[0.9, 0.1],
                            n_features=5, random_state=42)

print('Before:', np.bincount(y))

cc = ClusterCentroids(sampling_strategy=1.0, random_state=42)
X_cc, y_cc = cc.fit_resample(X, y)

print('After ClusterCentroids:', np.bincount(y_cc))
print('Note: synthetic centroids replace real majority samples')

การเปรียบเทียบวิธีลดจำนวนตัวอย่าง

เราจะทดสอบประสิทธิภาพของการลดจำนวนตัวอย่างแบบสุ่ม การใช้เซนทรอยด์ของกลุ่ม และการไม่สุ่มตัวอย่างใหม่ โดยใช้ชุดข้อมูลที่ไม่สมดุลชุดเดียวกัน และใช้ F1-score ของคลาสส่วนน้อยเป็นเมตริกประเมินผล

from imblearn.under_sampling import RandomUnderSampler, ClusterCentroids
from imblearn.pipeline import Pipeline as ImbPipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import f1_score
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import numpy as np

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_tr = sc.fit_transform(X_train)
X_te = sc.transform(X_test)

for name, sampler in [('None', None),
                       ('RUS', RandomUnderSampler(random_state=0)),
                       ('ClusterCentroids', ClusterCentroids(random_state=0))]:
    if sampler:
        Xr, yr = sampler.fit_resample(X_tr, y_train)
    else:
        Xr, yr = X_tr, y_train
    lr = LogisticRegression().fit(Xr, yr)
    f1 = f1_score(y_test, lr.predict(X_te))
    print(f'{name:20s}: F1={f1:.4f}  n_train={len(yr)}')

การสูญเสียข้อมูลจากการลดจำนวนตัวอย่าง

ข้อเสียสำคัญของการลดจำนวนตัวอย่างคือ การสูญเสียข้อมูล เมื่อทิ้งตัวอย่างจากคลาสส่วนใหญ่ 95 ตัวจากทุก ๆ 100 ตัว โมเดลจะเห็นการกระจายของข้อมูลฝึกที่แตกต่างจากความเป็นจริงอย่างมาก ซึ่งอาจทำให้อัตราผลบวกลวงในการใช้งานจริงสูงขึ้น ด้วยเหตุนี้ จึงมักใช้การลดจำนวนตัวอย่างร่วมกับการเพิ่มจำนวนตัวอย่าง (เช่น ใช้ SMOTEENN หรือ SMOTETomek) เพื่อสร้างสมดุลให้ชุดข้อมูลพร้อมลดการสูญเสียข้อมูลให้น้อยที่สุด

การผสานการเพิ่มและลดจำนวนตัวอย่าง

SMOTETomek ผสาน SMOTE (เพิ่มจำนวนตัวอย่างของคลาสส่วนน้อย) กับการลบ Tomek Links (ทำความสะอาดตัวอย่างของคลาสส่วนใหญ่ที่อยู่บริเวณขอบเขตและมีความกำกวม) ผลลัพธ์คือคลาสทั้งสองมีความสมดุล และตัวอย่างของคลาสส่วนใหญ่ที่อยู่ใกล้เส้นแบ่งซึ่งทำให้ตัวจำแนกสับสนจะถูกลบออก วิธีผสานนี้มักให้ผลดีกว่าการเพิ่มหรือลดจำนวนตัวอย่างเพียงอย่างเดียว

from imblearn.combine import SMOTETomek
from sklearn.datasets import make_classification
import numpy as np

X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
print('Before:', np.bincount(y))

st = SMOTETomek(random_state=42)
X_res, y_res = st.fit_resample(X, y)
print('After SMOTETomek:', np.bincount(y_res))

Near Miss: การลดจำนวนตัวอย่างตามระยะห่างอย่างมีข้อมูลประกอบ

NearMiss เลือกตัวอย่างจากคลาสส่วนใหญ่โดยพิจารณาระยะห่างจากตัวอย่างของคลาสส่วนน้อย โดยเลือกตัวอย่างที่ใกล้ที่สุด (NearMiss-1) หรือไกลที่สุด (NearMiss-3) ต่างจากการลดจำนวนตัวอย่างแบบสุ่ม NearMiss จะเก็บตัวอย่างของคลาสส่วนใหญ่ที่เกี่ยวข้องกับการกำหนดเส้นแบ่งการตัดสินใจมากที่สุด NearMiss-3 จะเก็บตัวอย่างของคลาสส่วนใหญ่ที่อยู่ไกลจากตัวอย่างของคลาสส่วนน้อยทั้งหมดมากที่สุด ทำให้บริเวณเส้นแบ่งสะอาดขึ้น

from imblearn.under_sampling import NearMiss
from sklearn.datasets import make_classification
import numpy as np

X, y = make_classification(n_samples=1000, weights=[0.9, 0.1], random_state=42)
print('Before:', np.bincount(y))

for version in [1, 2, 3]:
    nm = NearMiss(version=version)
    _, y_nm = nm.fit_resample(X, y)
    print(f'NearMiss-{version}:', np.bincount(y_nm))

การลดจำนวนตัวอย่างภายในไปป์ไลน์ imblearn

เช่นเดียวกับการเพิ่มจำนวนตัวอย่าง การลดจำนวนตัวอย่างต้องทำภายในไปป์ไลน์เพื่อป้องกันข้อมูลรั่วไหลระหว่างการตรวจสอบไขว้ ให้ใช้ imblearn.pipeline.Pipeline โดยวางตัวลดจำนวนตัวอย่างเป็นขั้นตอนก่อนตัวจำแนก ระบบจะเรียกใช้ fit_resample ของตัวสุ่มตัวอย่างใหม่กับชุดฝึกในแต่ละส่วน และจะไม่มีการแก้ไขชุดทดสอบ

from imblearn.pipeline import Pipeline as ImbPipeline
from imblearn.under_sampling import RandomUnderSampler
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_classification
import numpy as np

X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)

pipe = ImbPipeline([
    ('sc', StandardScaler()),
    ('rus', RandomUnderSampler(random_state=42)),
    ('lr', LogisticRegression())
])

scores = cross_val_score(pipe, X, y, cv=5, scoring='f1')
print(f'CV F1 (RUS): {np.mean(scores):.4f} +/- {np.std(scores):.4f}')

เมื่อใดควรเลือกการลดจำนวนตัวอย่างแทนการเพิ่มจำนวนตัวอย่าง

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

การประเมินผลหลังลดจำนวนตัวอย่าง

หลังการสุ่มตัวอย่างใหม่ ให้ประเมินผลด้วย ชุดทดสอบเดิมที่ไม่สมดุล เสมอ — ห้ามใช้ชุดทดสอบที่สุ่มตัวอย่างใหม่ การสุ่มตัวอย่างข้อมูลทดสอบใหม่จะทำให้เห็นประสิทธิภาพในการใช้งานจริงอย่างไม่สมจริง เป้าหมายคือการปรับปรุงพฤติกรรมของโมเดลบนการกระจายข้อมูลจริง ไม่ใช่การปรับให้เหมาะกับการกระจายข้อมูลที่สร้างสมดุลขึ้นมาเทียม

from sklearn.metrics import classification_report
from imblearn.under_sampling import RandomUnderSampler
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, test_size=0.2, stratify=y, random_state=42)

sc = StandardScaler()
X_train_s = sc.fit_transform(X_train)
X_test_s = sc.transform(X_test)

rus = RandomUnderSampler(random_state=0)
X_r, y_r = rus.fit_resample(X_train_s, y_train)

lr = LogisticRegression().fit(X_r, y_r)
# Evaluate on ORIGINAL imbalanced test set
print(classification_report(y_test, lr.predict(X_test_s)))

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับการลดจำนวนตัวอย่างและ Cluster Centroids จากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า RandomUnderSampler ลบตัวอย่างของคลาสส่วนใหญ่ออกแบบสุ่ม ซึ่งทำงานได้รวดเร็วแต่เสี่ยงสูญเสียข้อมูลสำคัญบริเวณเส้นแบ่ง ClusterCentroids แทนที่กลุ่มของคลาสส่วนใหญ่ด้วยเซนทรอยด์ เพื่อรักษาการกระจายของคลาสให้ใกล้เคียงความเป็นจริงมากขึ้น และ ควรประเมินผลด้วยชุดทดสอบเดิมที่ไม่สมดุลเสมอ เพื่อวัดพฤติกรรมของโมเดลในโลกจริง บทถัดไปเราจะสำรวจการให้น้ำหนักคลาสและการเลื่อนค่าเกณฑ์เพื่อใช้เป็นทางเลือกแทนการสุ่มตัวอย่างใหม่

เริ่มต้นได้ฟรี

เรียนรู้ Python ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “การสุ่มลดตัวอย่างและ ClusterCentroids” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การสุ่มลดตัวอย่างและ ClusterCentroids” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Machine Learning Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การสุ่มลดตัวอย่างและ ClusterCentroids”

ผู้เรียนจะลดตัวอย่างของคลาสส่วนใหญ่แบบสุ่มและด้วย ClusterCentroids พร้อมเปรียบเทียบการสูญเสียข้อมูลกับประสิทธิภาพของแบบจำลองที่ได้ คุณปฏิบัติ Machine Learning Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Machine Learning Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Machine Learning Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การสุ่มลดตัวอย่างและ ClusterCentroids” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Machine Learning Academy นี้ได้ไหม

ได้ บทเรียน Machine Learning Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การตรวจจับความไม่สมดุล: การกระจายของคลาสและข้อผิดพลาดของค่าพื้นฐาน
  2. การสุ่มเพิ่มตัวอย่างและ SMOTE
  3. การสุ่มลดตัวอย่างและ ClusterCentroids
  4. น้ำหนักคลาสและการเลื่อนเกณฑ์ตัดสินใจ
← กลับไปที่ Machine Learning Academy