01Overall Concept
ไอเดียหลัก — Quantile Regression ตอบคำถามว่า “ค่าต่ำ ค่ากลาง หรือค่าค่อนข้างสูงน่าจะอยู่ตรงไหน” แทนการทำนายค่าเฉลี่ยเพียงเส้นเดียว จึงช่วยให้เราเห็นว่าผลลัพธ์อาจกระจายกว้างเพียงใด
ลองนึกภาพว่า — ถ้าถามว่าไปโรงเรียนใช้เวลาเฉลี่ยกี่นาที เราอาจได้ 20 นาที แต่ถ้าต้องไม่สาย เราอยากรู้เวลาที่ 90% ของวันไปถึงก่อน เช่น 35 นาที Quantile ช่วยตอบคำถามแบบหลัง
ตัวอย่างการนำไปใช้ — คาดเวลาส่งของที่ลูกค้าส่วนใหญ่จะได้รับ วางงบสำรองสำหรับค่าใช้จ่ายสูง หรือดูช่วงล่างและช่วงบนของราคาสินค้า
02อธิบายภาษาคนเข้าใจง่ายๆ
Regression ปกติชอบถามว่า
“ค่าเฉลี่ยน่าจะเท่าไร?”
แต่โลกจริงบางครั้งค่าเฉลี่ยไม่ใช่สิ่งที่เราอยากรู้
สมมติเราทำบริษัทขนส่ง และต้องทำนายเวลาส่งสินค้า
Regression ปกติอาจบอกว่า
ส่งเฉลี่ย 2.3 วัน
แต่ฝ่ายบริการลูกค้าอาจไม่ได้สนใจค่าเฉลี่ย เขาอยากรู้ว่า
“ถ้าจะรับประกันว่า 90% ของพัสดุถึงภายในกี่วัน?”
นี่คือสิ่งที่ Quantile Regression ทำได้
เราอาจถามมันว่า
50th percentile = ประมาณ 2 วัน 90th percentile = ประมาณ 4 วัน 95th percentile = ประมาณ 5 วัน
ทีนี้เราสามารถเอาไปใช้กำหนด SLA ได้ดีกว่าค่าเฉลี่ย
อีกตัวอย่างคือเงินเดือน แทนที่จะถามว่า “คนตำแหน่งนี้ได้เงินเดือนเฉลี่ยเท่าไร” เราอาจถามว่า
คนกลุ่มเงินเดือนต่ำ 25% เป็นแบบไหน คนกลางๆ เป็นแบบไหน คนระดับบน 10% เป็นแบบไหน
จึงเหมาะมากเวลาการกระจายข้อมูลไม่สมมาตร หรือเราสนใจ “กลุ่มบน/กลุ่มล่าง” มากกว่าค่ากลาง
ภาพจำ: ไม่ถามแค่ “คนกลางห้องอยู่ไหน” แต่ถามได้ว่า “หัวแถว ท้ายแถว และคนบนสุดอยู่ตรงไหน”
03How it works
ค่อยๆ ทำไปด้วยกัน ตั้งแต่ข้อมูลแถวแรกจนถึงการตรวจคำตอบ
ตั้งคำถามบริษัทขนส่งให้ตรง
ให้ X เป็นระยะทาง น้ำหนักพัสดุ และข้อมูลจราจรที่ทราบตอนรับงาน ส่วน y เป็นเวลาส่งจริง เก็บงานช่วงหลังไว้ทดสอบ เป้าหมายคราวนี้คือทำนายเวลาที่พัสดุส่วนใหญ่จะไปถึง ไม่ใช่แค่ค่าเฉลี่ยของทุกชิ้น
กำหนดว่าต้องการเผื่อให้กี่เปอร์เซ็นต์
เลือก quantile=0.9 ถ้าอยากประมาณขอบเวลาสำหรับ 90% ของงานที่มีลักษณะใกล้กัน หรือ 0.5 ถ้าอยากได้ค่ามัธยฐาน ค่า 0.9 ไม่ใช่การสั่งว่าทุกกลุ่มต้องได้ตามสัญญา 90% แน่นอน แต่เป็นเป้าหมายที่โมเดลพยายามเรียนรู้จากข้อมูล
คิดค่าความพลาดสองฝั่งไม่เท่ากัน
สมมติส่งจริง 5 วัน แต่ทาย 3 วัน เราประเมินต่ำไป 2 วัน เมื่อ quantile=0.9 ค่าความเสียหายแบบ pinball คือ 0.9 × 2 = 1.8 ถ้าส่งจริง 3 วันแต่ทาย 5 วัน จะคิดเพียง 0.1 × 2 = 0.2 โมเดลจึงมีแรงผลักให้เผื่อเวลาด้านบนมากขึ้น แทนการกดทั้งสองฝั่งให้เข้าใกล้ค่าเฉลี่ย
ฝึกเส้นกลางกับเส้นเผื่อแยกกัน
ใช้ QuantileRegressor(quantile=0.9, alpha=0.01, solver='highs') ภายใน Pipeline ที่ปรับสเกล แล้ว fit(X_train, y_train) ค่า alpha คุมค่าปรับน้ำหนัก ไม่ใช่ระดับเปอร์เซ็นต์ ถ้าอยากเห็น 50% และ 90% ต้องฝึกสองโมเดลด้วย quantile ต่างกัน แล้ว predict ด้วยข้อมูลชุดเดียวกัน
ตรวจว่าที่เผื่อไว้ช่วยจริงไหม
ใช้ mean_pinball_loss(y_test, pred, alpha=0.9) โดย alpha ของฟังก์ชันวัดผลนี้หมายถึง quantile คนละความหมายกับ alpha ในโมเดล นอกจากนี้นับสัดส่วน y_test ≤ pred ว่าใกล้ 90% หรือไม่ และดูแยกตามเส้นทาง ถ้าโมเดลหลาย quantile ให้เส้นข้ามกัน ต้องตรวจเพิ่มก่อนนำไปตั้ง SLA เพราะการฝึกแยกไม่ได้บังคับลำดับเส้น
ข้อมูล พารามิเตอร์ และภาพรวมการคำนวณ
quantilealphasolverข้อมูลที่รับเข้ามา
รับ X เป็นตารางตัวเลขและ y เป็นค่าต่อเนื่องเหมือน regression ทั่วไป แต่ผู้ใช้เลือกตำแหน่งของการกระจายที่ต้องการทำนาย
X = [ระยะทาง, น้ำหนักพัสดุ, จราจร] · y = เวลาส่งจริงพารามิเตอร์ที่ใช้
- quantile
- ตำแหน่งที่ต้องการ เช่น 0.5 ค่ากลาง หรือ 0.9 ขอบสูง
- alpha
- แรง regularization ที่ช่วยคุมขนาดน้ำหนัก
- solver
- วิธี optimization ที่ใช้ลด pinball loss
ผลลัพธ์ที่ได้
ได้ค่าทำนายของ quantile ที่เลือกหนึ่งค่าต่อแถว สามารถฝึกหลายโมเดลเพื่อสร้างช่วงล่าง–กลาง–บน
quantile=0.9 → ประมาณเวลาขอบบน แล้วตรวจ coverage บน testคำนวณทีละขั้น
- 01
สร้างคำทำนายเชิงเส้น ŷ จาก X แล้วหาความต่างระหว่าง y กับ ŷ
- 02
ใช้ pinball loss ซึ่งลงโทษการพลาดด้านบนและด้านล่างไม่เท่ากันตาม quantile
- 03
ปรับน้ำหนักจน loss ต่ำที่สุด ทำให้สัดส่วนข้อมูลใต้เส้นใกล้ quantile ที่เลือก
ควรรู้อีกนิด — quantile สุดขอบต้องใช้ข้อมูลมาก และเส้นหลาย quantile อาจตัดกันหาก fit แยกกัน
04Make it yours
# ติดตั้ง: pip install numpy scikit-learn matplotlibfrom sklearn.linear_model import QuantileRegressorfrom 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 = QuantileRegressor(quantile=0.50)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
ปรับ quantile แล้วสังเกตรูปแบบคำทำนายและตัวชี้วัดที่คำนวณใหม่ทันที
Playground เป็น implementation เพื่อการเรียนรู้ที่คำนวณในเบราว์เซอร์ ส่วนโค้ด Python ใช้ scikit-learn จึงอาจให้ค่าต่างกันเล็กน้อยจากรายละเอียดการ optimize และค่าเริ่มต้นของไลบรารี ผลนี้ไม่ใช่ benchmark บนข้อมูลจริง