Machine Learning › Feature engineering
Scaling และ missing values
ประมาณ 30 นาที
เป้าหมายของบท
- ใช้ StandardScaler โดย fit บน train เท่านั้น และรู้ว่าโมเดลแบบไหนไวต่อสเกล
- ไม่เชื่อว่า scaling ช่วยเสมอไป — วัดผลก่อนตัดสินใจ
- เติม missing values ด้วย SimpleImputer โดยใช้ค่าจาก train
scaling: ปรับตัวเลขให้อยู่สเกลใกล้กัน
feature ต่างๆ มีสเกลต่างกันมาก (first_discount_pct 0–20, days_since_first_order 3–728) โมเดลบางแบบไวต่อสเกล — โดยเฉพาะที่ใช้ ระยะทาง
(KNN, SVM) หรือ regularization/gradient (logistic regression, neural network) ส่วน decision tree ไม่สนใจสเกล
StandardScaler ปรับให้แต่ละคอลัมน์มี mean 0 และ std 1: z = (x − mean) / std
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler().fit(X_train[num]) # เรียนรู้ mean/std จาก train เท่านั้น
X_train_s = scaler.transform(X_train[num])
X_test_s = scaler.transform(X_test[num]) # ใช้ mean/std เดิมจาก train
กฎสำคัญ: fit บน train เท่านั้น แล้ว transform ทั้ง train และ test — ถ้า fit บนข้อมูลทั้งชุด ค่า mean/std จะมีข้อมูล test ปนอยู่ (leakage แบบละเอียด)
ผลคือ train จะมี mean = 0 พอดี ส่วน test จะเบี่ยงเล็กน้อย ซึ่งเป็นเรื่องปกติและถูกต้อง
scaling ช่วยเสมอไหม? ไม่เสมอไป
scaling เปลี่ยน “ใครมีอิทธิพลต่อระยะทาง” — ตัวอย่างในบทนี้ KNN ที่ไม่ scale ถูกครอบงำด้วย days_since_first_order (ค่าเป็นร้อย) ซึ่งบังเอิญเป็น feature ที่มีประโยชน์
พอ scale แล้วทุก feature (รวม feature 0/1 ที่มีแต่สัญญาณรบกวน) มีน้ำหนักเท่ากัน ผลกลับแย่ลงเล็กน้อย — ต้องวัดด้วยข้อมูลจริงเสมอ ไม่ใช่เชื่อกฎลอยๆ
missing values
โมเดลส่วนใหญ่ใน scikit-learn (เช่น LogisticRegression) error ถ้าเจอ NaN จึงต้องจัดการก่อน วิธีพื้นฐานคือเติมค่า (impute) ด้วย SimpleImputer:
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='median').fit(X_train[['days_to_first_order']])
imputer.transform(X_test[['days_to_first_order']])
medianทนต่อค่าสุดโต่งกว่าmean— เหมาะกับข้อมูลเบ้- เช่นเดียวกับ scaler: fit บน train เท่านั้น แล้วเติมค่าให้ทั้ง train และ test ด้วยค่าจาก train
ตัวอย่างแก้โจทย์
กด "ขั้นต่อไป" ทีละขั้น ลองรันและแก้โค้ดในแต่ละขั้นได้
StandardScaler ที่ fit บน train
ปรับสเกล feature ตัวเลขโดยไม่ให้ข้อมูล test ปนเข้ามา
fit scaler บน train — ดู mean และ std ของ days_to_first_order ที่เรียนรู้ได้
scaling กับ KNN
KNN ใช้ระยะทาง — scale แล้วดีขึ้นไหม
KNN (k=15) บน feature ตัวเลขทั้ง 6 ตัวโดยไม่ scale
เติมค่าที่หายไปด้วย SimpleImputer
บางแถวไม่มีค่า days_to_first_order — เติมยังไงให้ไม่รั่ว
จำลองข้อมูลหาย: ตั้ง days_to_first_order เป็น NaN ให้ลูกค้า customer_id ที่หาร 10 ลงตัว
เติมช่องว่าง
แทน ___ ด้วยโค้ดที่ถูกต้อง แล้วกดตรวจคำตอบ
fit SimpleImputer แบบ median บน train แล้วเก็บค่ากลางที่เรียนรู้ไว้ในตัวแปร train_median เติม ___ ให้ครบ
แบบฝึกท้ายบท
บทนี้จะนับว่าเสร็จเมื่อผ่านข้อพื้นฐานและประยุกต์ครบ ข้อท้าทายได้ดาวเพิ่ม
🟢 พื้นฐาน
mean ของ days_to_first_order ที่ StandardScaler เรียนรู้จาก train ปัด 3 ตำแหน่ง เก็บไว้ในตัวแปร train_mean
ส่วนเบี่ยงเบนมาตรฐาน (scale_) ของ days_to_first_order ที่เรียนรู้จาก train ปัด 3 ตำแหน่ง เก็บไว้ในตัวแปร train_scale
หลัง scale ชุดทดสอบด้วย scaler จาก train: mean ของ days_to_first_order ในชุดทดสอบ ปัด 4 ตำแหน่ง เก็บไว้ในตัวแปร test_mean_scaled
หลังตั้ง NaN ตามที่จำลองไว้ มีแถว days_to_first_order ที่หายกี่แถว เก็บไว้ในตัวแปร n_missing
🟡 ประยุกต์
ค่ามัธยฐานของ days_to_first_order ที่ SimpleImputer(strategy="median") เรียนรู้จากชุด train เก็บไว้ในตัวแปร train_median
ในชุดทดสอบมี days_to_first_order ที่หายกี่แถว เก็บไว้ในตัวแปร n_test_missing
KNN (n_neighbors=15) บน feature ตัวเลข 6 ตัวโดยไม่ scale (ใช้ข้อมูล FEATS ที่ยังไม่มี NaN): accuracy บนชุดทดสอบ ปัด 4 ตำแหน่ง เก็บไว้ในตัวแปร knn_acc_unscaled
🔴 ท้าทาย
KNN แบบเดียวกันแต่ scale ด้วย StandardScaler ที่ fit บน train ก่อน: accuracy บนชุดทดสอบ ปัด 4 ตำแหน่ง เก็บไว้ในตัวแปร knn_acc_scaled
เติมค่าที่หายในชุดทดสอบด้วยค่ามัธยฐานจาก train แล้วหาค่าเฉลี่ยของ days_to_first_order ในชุดทดสอบหลังเติม ปัด 4 ตำแหน่ง เก็บไว้ในตัวแปร filled_test_mean
Quiz
สรุป
- StandardScaler และ SimpleImputer ต้อง fit บน train เท่านั้น แล้ว transform ทั้ง train และ test
- scaling เปลี่ยนว่า feature ไหนมีอิทธิพลต่อระยะทาง — ในข้อมูลนี้ KNN ที่ scale แล้วได้ accuracy ต่ำกว่า จึงต้องวัดเสมอ
- โมเดลส่วนใหญ่ error เมื่อมี NaN; เติมด้วย median จะทนค่าสุดโต่งกว่า mean
คำถามสัมภาษณ์
อธิบายว่าทำไมการ fit scaler บนข้อมูลทั้งชุดก่อนแบ่ง train/test จึงเป็น leakage
เพราะ mean/std ที่ใช้ปรับสเกลถูกคำนวณจากข้อมูลที่รวมชุด test — ข้อมูล test จึงมีผลต่อการแปลง feature ที่โมเดลเห็นตอนเทรน ทำให้ผลทดสอบดีเกินจริงเล็กน้อยและไม่ตรงกับสถานการณ์จริงที่ข้อมูลใหม่ยังไม่เคยมีอยู่ตอนเทรน วิธีที่ถูกคือ fit บน train แล้ว transform test ด้วยค่าเดิม (หรือใส่ไว้ใน Pipeline)
ถ้าข้อมูลมี missing 5% ควรเลือกวิธีจัดการอย่างไร
ดูก่อนว่าหายแบบสุ่มหรือมีแบบแผน (เช่น หายเฉพาะกลุ่มลูกค้าบางกลุ่ม) แล้วเลือกจากลบแถว เติม median/mean/ค่าคงที่ หรือเพิ่มคอลัมน์ flag ว่าค่านี้เคยหาย และวัดผลด้วย cross-validation โดยต้องคำนวณค่าที่เติมจาก train เท่านั้น