ml/ library Learn by doing
ALGORITHM 49 · PYTHON / JAVASCRIPT

Generalized Additive Model

รวมเส้นโค้งเล็ก ๆ ที่ยังอธิบายได้

LEARNING LEVEL3
ผสานหลายแนวคิดควรรู้มาก่อน · Polynomial Regression และ Ridge Regression
ลองใน Playground

01Overall Concept

OVERALL CONCEPT

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

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

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

02อธิบายภาษาคนเข้าใจง่ายๆ

เล่าแบบไม่ใช้ศัพท์ยาก

GAM อยู่ตรงกลางระหว่างโมเดลที่ง่ายมากกับโมเดลที่ซับซ้อนมาก

มันยอมรับว่า

“โลกไม่ได้เป็นเส้นตรง แต่เรายังอยากเข้าใจว่าปัจจัยแต่ละตัวมีผลยังไง”

ตัวอย่างเช่น เราต้องการดูว่ายอดขายขึ้นอยู่กับอุณหภูมิอย่างไร

อาจพบว่า

ตอนอากาศ 20°C ยอดขายต่ำ 25°C เริ่มดี 30°C ดีมาก 35°C เริ่มตก 40°C ตกหนัก

ถ้าใช้ Linear Regression จะจับรูปแบบแบบนี้ไม่ค่อยดี เพราะมันคิดว่าอุณหภูมิเพิ่ม → ยอดขายควรเพิ่มหรือลดในทิศทางเดียว

GAM ยอมให้ความสัมพันธ์เป็นเส้นโค้งได้

และที่ดีคือเรายังสามารถเปิดดูได้ว่า

อายุส่งผลแบบไหน รายได้ส่งผลแบบไหน ฤดูกาลส่งผลแบบไหน

มันจึงเป็นตัวเลือกที่น่าสนใจเมื่อเราต้องการ โมเดลที่ยืดหยุ่น แต่ยังอธิบายมนุษย์ได้

ภาพจำ: ให้แต่ละตัวแปรวาดเส้นโค้งของตัวเอง แล้วเอาเส้นเหล่านั้นมาประกอบกัน

03How it works

ค่อยๆ ทำไปด้วยกัน ตั้งแต่ข้อมูลแถวแรกจนถึงการตรวจคำตอบ

  1. ต่อเรื่องอุณหภูมิกับยอดขาย

    เตรียม X เป็นอุณหภูมิ ราคา และปัจจัยที่รู้ล่วงหน้า ส่วน y คือยอดขาย แยกวันหลังไว้ทดสอบ GAM จะให้แต่ละปัจจัยมีเส้นของตัวเอง เช่น เส้นอุณหภูมิอาจขึ้นแล้วลง ส่วนเส้นราคาอาจค่อยๆ ลด โดยยังอ่านผลแยกคอลัมน์ได้

  2. ต่อเส้นโค้งจากชิ้นส่วนเล็กๆ

    ตัวอย่าง Python ในหน้านี้ใช้ SplineTransformer ตามด้วย Ridge เพื่อสร้างโมเดล additive แบบ spline สำหรับ regression ตัว transformer เปลี่ยนแต่ละคอลัมน์เป็นชุดเส้นพื้นฐานที่เรียกว่า spline basis แล้ว Ridge หาน้ำหนักของชิ้นส่วนเหล่านั้น จึงไม่ต้องวาดเส้นความสัมพันธ์เองทีละจุด

  3. รวมเรื่องของแต่ละคอลัมน์เป็นคำตอบเดียว

    แนวคิดคือยอดขาย = ค่าตั้งต้น + f(อุณหภูมิ) + g(ราคา) แต่ละฟังก์ชันเป็นผลรวม spline ที่เรียนรู้ หากอยากให้ผลของราคาขึ้นกับอุณหภูมิด้วย ต้องเพิ่ม interaction โดยตั้งใจ เพราะรูปแบบบวกแยกนี้ไม่ได้เรียนความสัมพันธ์ข้ามคอลัมน์ทั้งหมดอัตโนมัติ

  4. เลือกจำนวนจุดต่อและแรงควบคุม

    เริ่ม make_pipeline(SplineTransformer(n_knots=5, degree=3, include_bias=False), Ridge(alpha=1.0)) แล้ว fit(X_train, y_train) n_knots มากขึ้นเปิดพื้นที่ให้เส้นเปลี่ยนรูปละเอียดขึ้น degree กำหนดกำลังของ spline ส่วน alpha เป็นค่าปรับน้ำหนักของ Ridge ตัวอย่างนี้ไม่เหมือนการลงโทษความโค้งโดยตรงของ GAM ทุกไลบรารี

  5. ดูทั้งเส้นและการทายจริง

    predict(X_test) ให้ยอดขาย ตรวจ MAE และลอง n_knots หลายค่าร่วมกับ alpha ผ่านการแบ่งตามเวลา หากอยากดูผลอุณหภูมิ ให้สร้างตารางใหม่ที่ไล่อุณหภูมิแต่คงคอลัมน์อื่นไว้ แล้ววาดค่าทำนายเป็นเส้น ใช้ช่วงที่มีข้อมูลรองรับและอย่าอ่านเส้นนั้นเป็นเหตุและผลโดยอัตโนมัติ

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

ข้อมูล พารามิเตอร์ และภาพรวมการคำนวณ

DATA INX · featuresy · targetX = [อุณหภูมิ, ราคา] · y = ยอดขาย
CALCULATEGeneralized Additive Model
n_knotsdegreealpha
RESULTnumeric predictionยอดขาย = b + f(อุณหภูมิ) + g(ราคา)
เส้นทางของข้อมูล: จากค่าที่รับเข้า ผ่านการคำนวณด้วยพารามิเตอร์ ไปเป็นผลลัพธ์
INPUT

ข้อมูลที่รับเข้ามา

ตัวอย่างนี้รับ X ตัวเลขและ y ยอดขายแบบต่อเนื่อง ใช้ SplineTransformer + Ridge เพื่อทำ additive spline regression หากมีหมวดหมู่ต้องจัดการการเข้ารหัสแยกให้เหมาะ

X = [อุณหภูมิ, ราคา] · y = ยอดขาย
PARAMETERS

พารามิเตอร์ที่ใช้

n_knots
จำนวนหลักที่ใช้ต่อเส้นโค้งของแต่ละ feature
degree
ระดับของ spline ที่กำหนดความเรียบของช่วงต่อ
alpha
ค่าปรับน้ำหนักของ Ridge ในตัวอย่างนี้ ลองร่วมกับ n_knots บน validation
OUTPUT

ผลลัพธ์ที่ได้

ได้คำทำนายและเส้นผลกระทบของแต่ละ feature ซึ่งเปิดดูแยกกันเพื่ออธิบายโมเดลได้

ยอดขาย = b + f(อุณหภูมิ) + g(ราคา)
CALCULATION

คำนวณทีละขั้น

  1. 01

    แปลง feature แต่ละตัวเป็น spline basis หรือชิ้นส่วนเส้นโค้งหลายคอลัมน์

  2. 02

    Ridge หาน้ำหนักของ spline basis พร้อมค่าปรับขนาดน้ำหนัก เพื่อประกอบเป็นฟังก์ชัน f₁, f₂, …

  3. 03

    รวมเป็น ŷ = b + f₁(x₁) + f₂(x₂) + … ตัวอย่างนี้ให้ค่าตัวเลขและไม่รวม interaction อัตโนมัติ

ควรรู้อีกนิด — basis มากเกินไปอาจ overfit ต้องมี smoothing penalty และ interaction ระหว่าง feature ต้องเพิ่มอย่างตั้งใจ

04Make it yours

Python · scikit-learn
# ติดตั้ง: pip install numpy scikit-learn matplotlibfrom sklearn.pipeline import make_pipelinefrom sklearn.preprocessing import SplineTransformerfrom sklearn.linear_model import Ridgefrom sklearn.metrics import mean_squared_error import numpy as npfrom sklearn.model_selection import train_test_split rng = np.random.default_rng(42)X = np.linspace(-1, 1, 60).reshape(-1, 1)y = 0.1 + 0.55*X[:, 0] + 0.55*np.sin(3.4*X[:, 0])y += rng.normal(0, 0.14, len(y))X_train, X_test, y_train, y_test = train_test_split(    X, y, test_size=0.2, random_state=42) model = make_pipeline(SplineTransformer(n_knots=6), Ridge(alpha=0.35))model.fit(X_train, y_train)pred = model.predict(X_test)print("RMSE:", mean_squared_error(y_test, pred) ** 0.5)

โค้ดเปลี่ยนตามค่าที่เลือกใน Playground · แต่ละภาษาใช้ข้อมูลตัวอย่างตามที่ระบุในโค้ด

05Learn by playing

ปรับ จำนวน spline แล้วสังเกตรูปแบบคำทำนายและตัวชี้วัดที่คำนวณใหม่ทันที

Sample dataset / Curved signal● คำนวณใหม่เมื่อปรับค่า
จุดควบคุมมากขึ้นจับความโค้งได้ละเอียดขึ้น
ข้อมูลฝึกและผลการทำนายFeature xค่าจริง • / ค่าทำนาย —
RMSE0.076
basis functions8
พารามิเตอร์ที่ลอง6

Playground เป็น implementation เพื่อการเรียนรู้ที่คำนวณในเบราว์เซอร์ ส่วนโค้ด Python ใช้ scikit-learn จึงอาจให้ค่าต่างกันเล็กน้อยจากรายละเอียดการ optimize และค่าเริ่มต้นของไลบรารี ผลนี้ไม่ใช่ benchmark บนข้อมูลจริง