Machine Learning › Feature engineering
สร้าง feature ใหม่
ประมาณ 30 นาที
เป้าหมายของบท
- สร้าง feature ใหม่ด้วย log transform, อัตราส่วน, flag และการจัดกลุ่ม
- ตรวจว่า feature ใหม่ไม่ leak (รู้ได้ ณ เวลาทำนายจริง)
- ตัดสินใจเก็บ feature ด้วย cross-validation ไม่ใช่ความรู้สึก
feature engineering คือการสร้างข้อมูลที่โมเดลเรียนรู้ได้ง่ายขึ้น
นอกจากแปลงข้อมูลที่มีอยู่ (encoding, scaling) ยังสร้าง feature ใหม่จากคอลัมน์เดิมได้ เทคนิคที่ใช้บ่อย:
| เทคนิค | ตัวอย่างในข้อมูลลูกค้า |
|---|---|
| log transform ลดความเบ้ขวา | np.log1p(first_order_value) — skew จาก 3.33 เหลือ ≈ 0 |
| อัตราส่วน | value_per_item = first_order_value / first_n_items |
| flag (0/1) จากเงื่อนไข | fast_first = days_to_first_order <= 3 |
| จัดกลุ่ม (binning) | pd.cut(first_order_value, [0, 1000, 5000, 20000, 1e9]) |
| ส่วนของวันที่ | ไตรมาสที่สมัคร (signup_month - 1) // 3 + 1 |
df['log_value'] = np.log1p(df['first_order_value']) # ใช้ log1p เผื่อค่าเป็น 0
df['value_per_item'] = df['first_order_value'] / df['first_n_items']
df['fast_first'] = (df['days_to_first_order'] <= 3).astype(int)
feature ใหม่ต้องรู้ได้ตอนทำนายจริง
ทุก feature ต้องคำนวณได้จากข้อมูลที่มี ณ เวลาที่ต้องทำนาย เท่านั้น (จำ leakage จากบทแรก) เช่น value_per_item คำนวณจากออเดอร์แรกได้จึงใช้ได้
แต่ “จำนวนออเดอร์ทั้งหมด” ไม่ได้
วัดด้วย cross-validation ไม่ใช่ความรู้สึก
feature ที่ “ดูสมเหตุสมผล” ไม่ได้แปลว่าช่วยโมเดล ในข้อมูลนี้ลองเพิ่ม fast_first หรือ value_per_item + log_value เข้า pipeline แล้ววัด CV AUC —
ค่าเฉลี่ยไม่ได้ดีขึ้นเลย (0.636 → 0.634 / 0.635) เพราะสัญญาณหลักของข้อมูลนี้อยู่ที่ช่องทางสมัครอยู่แล้ว
ดังนั้นควรเพิ่มทีละกลุ่ม วัดด้วย CV แล้วเก็บเฉพาะที่ช่วยจริง — feature เยอะขึ้นไม่ได้แปลว่าดีขึ้น
ตัวอย่างแก้โจทย์
กด "ขั้นต่อไป" ทีละขั้น ลองรันและแก้โค้ดในแต่ละขั้นได้
log transform แก้ข้อมูลเบ้
มูลค่าออเดอร์แรกเบ้ขวามาก — ลอง log
skew ของ first_order_value ดิบ ≈ 3.3 (หางขวายาวมาก)
เพิ่ม feature แล้ววัดด้วย CV
feature ใหม่ช่วยโมเดลจริงไหม
สร้างฟังก์ชัน cv_auc ที่ประกอบ pipeline แล้ววัด AUC แบบ 5-fold แล้ววัด baseline
เติมช่องว่าง
แทน ___ ด้วยโค้ดที่ถูกต้อง แล้วกดตรวจคำตอบ
สร้างคอลัมน์ value_per_item = มูลค่าออเดอร์แรกหารจำนวนชิ้น แล้วเก็บค่าเฉลี่ย (ปัด 2 ตำแหน่ง) ไว้ในตัวแปร vpi_mean เติม ___ ให้ครบ
แบบฝึกท้ายบท
บทนี้จะนับว่าเสร็จเมื่อผ่านข้อพื้นฐานและประยุกต์ครบ ข้อท้าทายได้ดาวเพิ่ม
🟢 พื้นฐาน
skew ของ first_order_value ดิบ ปัด 3 ตำแหน่ง เก็บไว้ในตัวแปร skew_raw
skew หลัง np.log1p ปัด 3 ตำแหน่ง เก็บไว้ในตัวแปร skew_log
สัดส่วนลูกค้าที่สั่งออเดอร์แรกภายใน 3 วันหลังสมัคร (days_to_first_order <= 3) ปัด 4 ตำแหน่ง เก็บไว้ในตัวแปร fast_share
มีลูกค้ากี่คนที่มูลค่าออเดอร์แรกเกิน 20,000 บาท เก็บไว้ในตัวแปร n_vip
🟡 ประยุกต์
อัตราซื้อซ้ำของลูกค้าที่ fast_first = 1 และ = 0 ตามลำดับ (ปัด 4 ตำแหน่ง) เก็บไว้ในตัวแปร repeat_fast, repeat_slow
อัตราซื้อซ้ำเฉลี่ยแยกตามไตรมาสที่สมัคร (signup_q = (signup_month - 1) // 3 + 1) ปัด 4 ตำแหน่ง เป็น Series เรียงตามไตรมาส เก็บไว้ในตัวแปร result
ค่า correlation ระหว่าง value_per_item กับ repeated ปัด 4 ตำแหน่ง เก็บไว้ในตัวแปร vpi_corr
🔴 ท้าทาย
CV AUC เฉลี่ย (5-fold stratified pipeline ตามฟังก์ชัน cv_auc ที่ให้ไว้) ของ baseline ที่ใช้ feature เดิมทั้งหมด ปัด 4 ตำแหน่ง เก็บไว้ในตัวแปร auc_base
เพิ่ม fast_first เข้าไปใน feature ตัวเลข แล้ววัด CV AUC ใหม่ (ปัด 4 ตำแหน่ง) พร้อมผลต่างจาก baseline (auc_with_fast − auc_base ปัด 4 ตำแหน่ง) เก็บไว้ในตัวแปร auc_with_fast, auc_gain
Quiz
สรุป
- log1p ลดความเบ้ขวาของ first_order_value (skew 3.33 → ≈0) และปลอดภัยกับค่า 0
- feature ใหม่ต้องคำนวณได้จากข้อมูล ณ เวลาที่ต้องทำนายจริง
- เพิ่ม feature แล้ววัดด้วย CV — ในข้อมูลนี้ fast_first หรือ value_per_item ไม่ทำให้ AUC ดีขึ้น (สัญญาณหลักอยู่ที่ช่องทางสมัคร) จึงไม่ควรเก็บ feature ที่ไม่ช่วย
คำถามสัมภาษณ์
บอกวิธีตัดสินใจว่า feature ที่สร้างขึ้นใหม่ควรเก็บหรือไม่
สร้างเป็นชุดสมมติฐาน (เช่น อัตราส่วน flag การจัดกลุ่ม) แล้วเพิ่มทีละกลุ่มเข้า pipeline เดียวกัน วัดด้วย cross-validation เทียบกับ baseline ที่ไม่มี feature นั้น ดูทั้งค่าเฉลี่ยและความผันผวน (std) ถ้าไม่ดีขึ้นอย่างมีความหมายก็ตัดออก เพราะ feature ที่ไม่ช่วยเพิ่มความซับซ้อนและความเสี่ยง overfit และตรวจด้วยว่า feature นั้นรู้ได้ ณ เวลาทำนายจริง
ยกตัวอย่าง feature ที่ leak และวิธีเลี่ยง
ตัวอย่าง: จำนวนออเดอร์ทั้งหมดของลูกค้า หรือค่าเฉลี่ยของ target ที่คำนวณจากข้อมูลทั้งชุด — ทั้งคู่ใช้ข้อมูลที่ยังไม่มีตอนทำนายจริง วิธีเลี่ยงคือกำหนดจุดเวลาที่ทำนาย (เช่น ณ ออเดอร์แรก) แล้วสร้าง feature จากข้อมูลก่อนหน้านั้นเท่านั้น และคำนวณสถิติที่ใช้ target จาก train เท่านั้น