วิธีทำ Cross Validation สำหรับ Time series model
The same concept as usual K-Fold Cross Validation but there are some(s) for more consideration.
สำหรับการสร้างโมเดลขึ้นมา 1 โมเดล Process ที่ควรทำคือ Model evaluation ไม่แน่ใจว่าภาษาไทยในวงการเรียกว่า “การประเมินโมเดล” หรือไม่อย่างไร แต่ก็ไม่ใช่สาระสำคัญของตอนนี้
สาระสำคัญของตอนนี้เกิดจากปัญหา ที่เจอจากการทำงานเหมือนเคย อาจไม่ลงรายละเอียดถึงต้นต่อของปัญหา แต่เล่าโดยสรุปคือ Final model ไม่มี Independence data หรือข้อมูลนอกช่วง Training สำหรับการทดสอบ
K-Fold Cross Validation
วิธีการแก้ไขปัญหานี้ไม่ได้ซับซ้อน เพราะมีเทคนิคให้เลือกใช้งานอย่างมากมาย เช่น K-Fold Cross Validation ซึ่งเป็นการแบ่งข้อมูลแบบสุ่ม ออกเป็นส่วน ๆ ในที่นี้ถูกแทนค่าตัว K โดยในแต่ละสวนต้องมีกระจายข้อมูลให้เท่า ๆ กัน
เมื่อแบ่งข้อมูลได้แล้ว ให้ทำการ Training model โดยเหลือ “ส่วนหนึ่ง” (1/K) เอาไว้สำหรับเป็นส่วน Testing เมื่อ Training model รอบแรกเสร็จ ข้อมูลที่เหลือไว้จะนำกลับเข้าไปเป็น Training set แล้วแบ่งอีกส่วนไว้สำหรับ Testing ดังนั้นการ Training model จะ Iteration เท่ากับจำนวน K
Time based Cross Validation
สำหรับข้อมูลที่เป็น Time series แล้ว การใช้งาน K-Fold Cross Validation ตรง ๆ อาจไม่เหมาะสม เพราะ Time series มีตัวแปรสำคัญที่ต้องการความต่อเนื่องคือ Time ดังนั้นการแบ่งข้อมูลแบบสุ่ม ทำให้ความหมายของ Time series ผิดไป
ใช้หลักการเดิม K-Fold Cross Validation มา Apply กับ Time series data แต่เปลี่ยนจากการสุ่มข้อมูล ให้เป็น “ทยอย” Training model แทน มีศัพท์เทคนิคเรียกวิธีการนี้ว่า Forward chaining ตัวอย่างเช่น
จากรูปตัวอย่างมีการแบ่งการ Training model ออกเป็นทั้งหมด 10 ครั้ง การทำ Time series split จะแบ่งข้อมูลช่วงนี้ Testing ของแต่ละ Iteration ให้มีขนาดเท่ากัน และทยอย Training model ด้วยชุดข้อมูลที่เป็น Training set เพิ่มขึ้นเรื่อย ๆ ในแต่ละรอบ
ใน Scikit-learn มี Library ที่ออกแบบมาเพื่อการทำงานในลักษณะนี้ ชื่อว่า TimeSeriesSplit()
Code
ใช้เป็นข้อมูลเดิมที่เคยใช้สำหรับทำ Regression analysis ต่าง ๆ จากหลายตอนที่แล้วมาเป็นตัวอย่าง แต่ก่อนการ Training model อยากให้เห็นทำงานของ TimeSeriesSplit()
ก่อน
สร้างตัวแปรเพื่อรับ Object ที่ Return จาก TimeSeriesSplit()
ที่กำหนด n_splits = 5
หมายถึงการแบ่งรอบการ Training ออกเป็นทั้งหมด 5 รอบ print()
Index ที่เกิดขึ้นจากแบ่งออกมาเพื่อให้ดูความต่อเนื่องของ Time series
Train index: [ 0 1 2 3 4 5 6 7 8 9 10]
Test index: [11 12 13 14 15 16 17 18]
Train index: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18]
Test index: [19 20 21 22 23 24 25 26]
Train index: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26]
Test index: [27 28 29 30 31 32 33 34]
Train index: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34]
Test index: [35 36 37 38 39 40 41 42]
Train index: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42]
Test index: [43 44 45 46 47 48 49 50]
เห็นได้ว่า Testing set จาก Iteration ก่อนหน้าจะโดนรวมเข้าไปเป็น Training set ของรอบถัดไป และวนแบบนี้ไปเรื่อย ๆ จนกว่าจะใช้ข้อมูลครบ
เนื่องจากวิธีการค่อนข้างตรงไปตรงมา ขอเขียนเป็น Loop ใหญ่ ๆ สำหรับการใช้ Time series split ในการ Evaluate model
- ใช้
TimeSeriesSplit()
โดยกำหนดn_splits = 5
เหมือนตัวอย่าง - ใช้
LinearRegression()
เป็นโมเดลที่ใช้หาความสัมพันธ์ - เริ่มวน For… loop… ใน Time series split object ด้วย
.split()
และผ่านข้อมูล Features ทั้งหมดเข้าไป เพื่อ Return ออกมาเป็น Index - ทำการแบ่งข้อมูลออกเป็น 2 ส่วน Train/Test ตาม Index ที่เกิดขึ้นในแต่ละรอบ
- ทำการ Fitting model ตามข้อมูลที่ถูกแบ่งจาก Index รวมไปถึงการคำนวณ Accuracy matrix (R-Square และ MSE) และการ Plot เพื่อแสดงผลลัพธ์ในแต่ละรอบ
รูปด้านล่างเป็นผลจากการทำ Back-testing กับข้อมูล และการใช้งาน Model กับข้อมูลนอกช่วง (Independence data) หรือเป็นสิ่งที่โมเดลไม่เคยเห็น
ถ้าเกณฑ์คือ R-Square มากกว่าหรือเท่ากับ 50% และ MSE น้อยกว่าหรือเท่ากับ 10%โมเดลนี้สามารถสรุปได้ว่าผ่านเกณฑ์ แม้ว่าจะไม่มีข้อมูลนอกช่วงเวลามาใช้ในการทดสอบก็ตาม
สุดท้ายแล้วสามารถหาค่าเฉลี่ยที่เกิดขึ้นแต่ละรอบ จาก DataFrame ที่ทำเป็นตารางสรุปผลขึ้นมา
ค่าเฉลี่ยที่เกิดขึ้น จะไม่เท่ากับการใช้ข้อมูลทั้งหมดในการสร้าง Model เพราะว่าการแบ่งข้อมูลไม่เหมือนกับ K-Fold Cross Validation แต่ใน Iteration สุดท้ายจะมีค่าใกล้เคียงค่าที่มาจากโมเดลสุดท้ายที่สุด
Conclusion
เรื่องที่เป็นข้อสรุปของตอนนี้คือ การไม่มี Data ในช่วง Out of time ไม่ใช่เป็นประเด็นที่ใหญ่โตอะไร เพราะปัจจุบันมีเทคนิคหลายอย่าง ที่สามารถนำมาประยุกต์ใช้เพื่อแก้ปัญหาบางจุดได้