หลากหลายวิธีกับการจัดการกับ “Missing Value”

หลายวันก่อนผมไมได้รับคำถามจากผู้เรียนในคอร์สมาว่า "ถ้ามีข้อมูลที่ Missing Value แล้วเราสามารถทำอะไรได้บ้างนอกจากลบวันที่มีค่า Drop มันทิ้งไป เราสามารถ Forward Fill (เติม Missing Value ด้วยค่าล่าสุดที่เรารู้) ได้ไหม"
Photo by Pierre Bamin on Unsplash

โดยปกติ Tutorial ทั้งไทย และต่างประเทศส่วนใหญ่ มักจะนำเสนอก็คือ การดึงข้อมูลมาจากผู้ให้บริการซักเจ้า จากชั้น Check ว่ามี Missing Value aka N.A. อยู่ในข้อมูลนั้นไหม ถ้ามี ก็ Drop มันทิ้ง ซึ่งใช่ครับในคอร์ส Python for Finance เราก็สอนแค่นั้น เพราะนั่นคือ คอร์สเบื้องต้นสอนความรู้กว้างๆ ถ้าในคอร์ส AI for Investment เราสอนอีกแบบโดยการใช้ Forward Fill ซึ่งก็เป็นอีกวิธีในการจัดการกับข้อมูล Missing Value เหล่านั้นเพื่องานเฉพาะสำหรับ Project ในคอร์สนั้นๆ

แต่คำถามนั้นทำให้ผมคิดได้ ว่ามันเราลืมพูดถึงเรื่องนี้ไปสนิทเลย เพราะจริงๆในการโมเดลลิ่ง มีตัวเลือกมากมายเลยครับ ในการจัดการกับ Missing Value และบางวิธีที่เราคิดว่าผิดแน่ๆ ถ้าผู้สร้างโมเดลยอมรับความผิดนั่นได้ มันก็ไม่ผิด เอ๊ะยังไงกัน!!!

ผิดถูกมันขึ้นกับประเภทของงานว่าคุณจะทำอะไรครับ ไม่ได้แปลว่า ถ้าคุณ Backward Filling (การเติมข้อมูลย้อนหลัง ซึ่งอาจก่อให้เกิด Lookahead Bias) แล้วจะผิดเสมอไป สมมุติฐานของคุณคืออะไรต่างหาก แต่ก่อนอื่นมาดูกันก่อนว่า

Photo by Jon Tyson on Unsplash

Misissing Value คืออะไร?

คือ ข้อมูลที่มันหายไปตามชื่อ Missing Value นั่นแหละครับสมมุติเราว่าไปดึงข้อมูลหุ้น กูเกิล (GOOG) มาซัก 1 ปี อาจจะมีบางวันที่ระบบของผู้ให้บริการข้อมูลไม่ได้เก็บข้อมูลราคาของมันไว้ หรือ มันอาจจะหายไปก็ได้ ทำให้ข้อมูลตรงนั้นเป็น Missing Value ไปครับ

ทำไม Missing values จึงสำคัญ?

โมเดลทาง Statistics และ Machine Learning ส่วนมากมันก็ไม่ได้สร้างมารองรับข้อมูลที่ Missing Value หรอกครับ เช่น Autoregressive integrated moving average (ARIMA) ส่วนของ Autoregressive(AR) มันก็บอกชัดแล้วว่า จะเอาตัวมันเองในอดีต กี่วันย้อนหลัง ถ่วงตามค่าสัมประสิทธิ์ (coefficient) ไปช่วยทำนายวันถัดไปยกตัวอย่าง AR = 2 นะครับ

ราคาพรุ่งนี้ = coefficient1 * ราคาวันนี้ + coefficient2 * ราคาเมื่อวาน

coefficient1 =0.6, ราคาวันนี้ = 12, coefficient2 = 0.4, ถ้าราคาเมื่อวาน = 10

ราคาพรุ่งนี้ = 0.6 * 12+ 0.4 * 10

ราคาพรุ่งนี้ = 7.2 + 4 = 11.2

  • ปรกติเราไม่ใช้ราคาปิดมาเข้าโมเดลกันนะครับ เพราะส่วนใหญ่แล้วมันจะไม่มีคุณสมบัติทางสถิติ และคณิตศาสตร์ แต่ขอยกเป็นราคาปิดมาเพื่อความเข้าใจง่ายครับ

ถ้าวันย้อนหลังมาเป็น NA มันก็จะมีปัญหาครับเอาข้อมูลที่ไม่มี ไปทำนายวันถัดๆไปได้อย่างไร ถ้า

coefficient1 =0.6, ราคาวันนี้ = 12, coefficient2 = 0.4, ถ้าราคาเมื่อวาน = NA

ราคาพรุ่งนี้ = 0.6 * 12+ 0.4 * NA

ราคาพรุ่งนี้ = Error

โมเดลอีกมากมายก็มีปัญหานี้ครับ

วิธีแก้คืออะไร?

โดยส่วนมากอย่างที่พูดในตอนต้น ถ้าเราจะเอาง่าย เอาเร็วเพื่อดูผลแบบ Prototype การใช้วิธีตัดวันที่มี Missing Value ออกไปเลยจะเป็นวิธีที่ไม่ได้แย่นักครับ

ดังเราจะเห็นได้บ่อยๆในภาษา Python ที่เรามักจะ .dropna()

สมมุติว่ามีข้อมูล 5 วัน วันที่ T1 = 10 , T2 = 12, T3 = 15, T4 = NA, T5 =13 แล้วข้อมูลวันที่ T4 มันเป็น NA เราก็ตัดข้อมูลนั้นทิ้งไป

เหลือเพียงข้อมูลของวันที่ T1= 10 , T2 = 12, T3 = 15, T5 =13

ปัญหาของวิธีนี้

ด้วยวิธีนี้สมขอยกตัวอย่างสมมุติเป็นโมเดลแบบ Autoregressive อีกครั้งนะครับ

ถ้าเรานำข้อมูลดังว่าเข้าโมเดล Autoregressive อาจจะบอกว่า ทางสถิติแล้ว ข้อมูลที่สำคัญกับการทำนายราคาวันถัดไปของหุ้นตัวนี้ คือ ใช้ตัวมันเองย้อนหลัง 3 วัน โดยที่แต่ละวันมีค่า coefficient แต่ละวันไม่เท่ากัน(ซึ่งก็มักจะไม่เท่ากันอยู่แล้ว) ผมยกตัวอย่าง สมมุติผมอยากจะทำนายวันที่ T6 Autoregressive บอกผมว่า ผมต้องใช้ย้อนหลังสามวัน โดยให้

วันที่ t-1 หรือวันที่ T5 มีค่า coefficient1 = 0.5

วันที่ t-2 ซึ่งก็คือวันที่ T4 มีค่า coefficient2 = 0.3

วันที่ t-3 ซึ่งก็คือวันที่ T3 = มีค่าcoefficient3 = 0.2

แต่โมเดลที่เรามี เราทิ้งดาต้าวันที่ 4 ไปแล้วครับ แปลว่าโมเดลนี้จะ ทำงานโดยใช้

coefficient1 * T5 + coefficient2 * T3 (เนื่องจากเราไม่มีวันที่ T4 ในข้อมูล) + coefficient3 * T2

0.5 * T5 + 0.3 *T3 + 0.2 *T2

อันนี้มันก็จะ Miss Leading อย่างหนึงแล้ว แม้ข้อมูลที่เราเอาไปใช้ในโมเดลเพื่อหาความสัมพันธ์เอาค่า coefficient มาจะไม่มีวันที่ 4 แต่ต้นก็เถอะ ลองนึกถึงข้อมูลขนาดใหญ่มากๆครับซัก 10000 วัน ที่ส่วนใหญ่แล้วข้อมูลไม่เป็น Missing Value ความสัมพันธ์ส่วนใหญ่ ได้มาเป็น วันนี้ เมื่อวาน เมื่อวานซืน เอาไปทำนายพรุ่งนี้ อยู่ๆก็มีตัวหนึงนอกแถว แถมนอกแถวดันเอาไปเข้าโมเดลด้วย ทำให้ค่าสรุปออกมาไม่สมจริงครับ(ได้รับอิทธิแม้จะน้อยก็ต้องได้รับอิทธิพลต่อโมเดล) เพราะมีบางวันไม่ได้เข้าข้อสรุป ” วันนี้ เมื่อวาน เมื่อวานซืน เอาไปทำนายพรุ่งนี้”


Photo by marianne bos on Unsplash

วิธีแก้แบบอื่น

อันนี้น่าสนใจครับ มีวิธีแก้เยอะกว่าที่เราคิดครับ อย่างที่ผมบอกไปว่ามันขึ้นกับสมมุติฐานของเราส่วนหนึงด้วยครับเดี๋ยวเราเริ่มมาดูไปทีละแบบ

Forward Fill

ตัวอย่าง Backward Fill จาก towardsdatascience

Forward Fill หรือ .ffil() เป็นการนำค่าที่เรารู้ล่าสุด ไปแทนที่ Missing Value นั้นแบบไปข้างหน้า คือเอาค่าเมื่อวานที่เรารู้มาใส่ค่า Missing Value ของวันนี้

สมมุติฐานของมันก็คือ เราอาจจะคิดว่า เราไม่มีทางรู้ดาต้าในวันที่มัน Missing Value เราก็เอาค่าล่าสุดที่รู้ไปใส่เท่านั้นเอง

ผมขอตัด Tx ออกไปจะได้เห็นภาพกันง่ายๆนะครับ

ถ้าดาต้าที่เรามีเป็น 10, NA, NA, 12 ก็จะเป็น 10, 10, 10, 12 ตรงไปตรงมาครับ

Backward Fill

Backward Fill หรือ .bfill() เอาค่าที่เรารู้ค่าสุดมาเติมแบบย้อนหลัง เอาค่าพรุ่งนี้มาใส่แทนที่ค่า Missing value ของมันวันนี้

ตัวอย่าง Backward Fill จาก towardsdatascience

สมมุติฐานอาจจะเป็น ข้อมูลจากผู้ให้บริการรายนี้ไม่ดีเอง ถ้าเราไปใช้งานจริง ไม่มีโอกาสที่เราจะไม่ได้รับข้อมูลในวันที่ Missing value หรอก ถ้าเป็นแบบนี้เอาค่าพรุ่งนี้มาเติมก็เป็นไปได้ครับ หรือ สมมุติฐานของเราอาจจะเหมือนของ Forward Fill ก็ได้แต่เราคิดว่า เราสามารถยอมรับ Lookahead Bias ได้เล็กน้อยในการเร่งสร้าง Prototype โมเดลของเรา

10, NA, NA, 12ก็จะเป็น 10, 12, 12, 12

ขอย้ำอีกครั้งว่าวิธีนี้ยังไงก็มี Lookahead Bias ครับ

ใช้ทั้ง Forward Fill และ Backward Fill

เราจะใช้แบบนี้ก็ได้ ขึ้นกับว่าข้อมูล Missing Value ใกล้ค่าอนาคตหรืออดีตมากกว่าครับ อันนี้ก็อาจจะตั้งบนสมมุติฐานว่า ถ้ามีวันที่ Missing Value ติดกันเยอะมากเกินไป การเติมด้วยค่าอดีตอย่างเดียวหรืออนาคตอย่างเดียว มันจะทำให้ดาต้าเรา Lagging หรือ Leading มากเกินไปหรือค่าซ้ำกันมากเกินไปจนเป็นเส้นตรง ก็ได้ครับ

ถ้าเราใช้ Forward Fill อย่างเดียวในข้อมูล 10, 11, NA, NA, NA, NA, 13, 14 จะเป็น 10, 11, 11, 11, 11, 11, 13, 14 หรือถ้า เป็น Backward Fill อย่างเดียวกจะเป็น 10, 11, 13, 13, 13, 13, 13, 14

ถ้าใช้ทั้งคู่ก็จะเป็น 10, 11, 11, 11, 13, 13, 15, 14

อันที่จริงถ้ามี Missing Value ติดกันมากขนาดนั้นเราก็ควรจะดูซักหน่อยแล้วครับว่าข้อมูลมีปัญหาอะไรหรือเปล่า?

Statistical Approach

อันนี้ก็จะมีคนพูดถึงบ้าง เป็นการใช้หลักการทางสถิติมาช่วยเติมข้อมูล Missing Value นั้นๆ อาจจะมีตั้งแต่เบสิคๆ เช่น ค่าเฉลี่ย (Mean) ของข้อมูลมาเติม ถ้าถามว่าค่าเฉลี่ยของอะไรล่ะ ก็ต้องถามอีกครับว่าแล้วเราจะทำอะไรล่ะ ข้อมูลที่เราได้มายาวแค่ไหน ลักษณะการแจกจแจงของข้อมูลเป็นอย่างไร(Data Distribution) เช่น ค่าเบี่ยงเบนต่างๆมากแค่ไหน(Variance, Standard Deviation) ความเบ้(Skewness), ความโด่ง(Kurtosis) เป็นต้น

เราอาจจะใช้ค่าเฉลี่ยของข้อมูลทั้งหมดมาเติม ค่าเฉลี่ยของข้อมูล1วันก่อน Missing Value กับ 1 วันหลัง Missing Value มาเติม

เช่น 10, NA, 15 เป็น 10, 12.5, 15

More Advanced Approach

อันนี้ อย่างน้อยก็ในบ้านเรา แทบไม่มีคนพูดถึงเลยครับ ผมคิดว่าเราสนใจมันน้อยไปครับ ผมคิดว่าพวกเราส่วนใหญ่รีบข้ามสเตปสำคัญไปรีบสร้างโมเดลไปหน่อยครับ

โอเค วิธีนี้มีหลายแบบมากจนผมยกมาไม่หมดหรอกครับ อาจจะใช้ Brownian Motion ก็ได้ แต่ขอยกมาคร่าวๆซัก 2 ตัวครับ ตัวแรกเรารู้จักกันแล้วครับคือ

Geometic Brownian Motion

Time Series Model Approach

อย่างARIMA ที่เราทำในคอร์ส Python for Finance เราสามารถใช้ Concept พวกนี้มาช่วยเติม Missing Value ได้เช่นกัน

ตัวอย่างที่ผมยกมาก่อนหน้าคือโมเดล Autoregressive ก็เป็นตัวหนึงที่เอามาเติม Missing Value ได้ครับ ถ้า ข้อมูลมาเป็น ……,10, 11, 12, NA1, NA2, 16, …….

เราก็เอาเข้าโมเดล AR สมมุติว่า = 3 ก็เป็น

predicted_NA1 = coefficient1* 10 + coefficient2 *11 + coefficient3 * 12

predicted_NA2 = coefficient1* 11+ coefficient2 *12+ coefficient3 * predicted_NA1

นั่นแค่ตัวอย่างนะครับ Autoregressive เป็นอะไรที่เรียบง่ายเกินไปซักหน่อย จริงๆเราอาจจะใช้โมเดลที่เหมาะสมกว่าเช่น Autoregressive integrated moving average หรือ Generalized AutoRegressive Conditional Heteroskedasticity (GARCH)  ก็ได้ครับ

ตัวอย่าง MIssing Value ของหุ้น CMG

ผมใช้ ARIMA ในการเติม Missing Value ซึ่งให้ผลที่ใกล้เคียงความเป็นจริงกว่าการเติมแค่ Forward Filled หรือ Backward ไปเรื่อยๆ

ผลลัพธ์จากการเติม Missing Value ด้วย ARIMA

Machine Learning Model Approach

อันนี้ก็กว้างครับ คุณอาจจะใช้ โมเดล Time Series ของ Artificial  Neural Network(ANN) อย่าง Recurrent Neural Network (RNN) หรือ Long Short Term Memory(LSTM)  ก็ได้ครับ หลักการมันก็เหมือนๆกับตอนเราใช้ Time Series Model นั่นแหละครับฉะนั้นไม่ขอพูดซ้ำแล้วกันครับ

แต่ถ้าถามว่าเหมาะไหม ผมคิดว่าพอได้ แต่เราต้องไม่ลืมว่าเรามีโมเดลสำหรับ สังเคราะห์ข้อมูล (Synthesis Data) ของมันอยู่แล้ว เช่น Generative Neural Network (GAN) หรือ เรายังสามารวม Statistical Model เข้ากับ Artificial  Neural Network อย่าง Neural Stochastic Volatility Model (NSVM) ก็ได้ครับ

ตัวอย่าง NSVM จากเปเปอร์วิจัย A Neural Stochastic Volatility Model ของคุณ Rui Luo

จะเห็นว่ามีบางโมเดลอย่าง ARIMA ที่เราเคยเขียนถึงและสอนไปแล้วใน Python for Finance แต่ก็มีอีกหลายโมเดลครับที่เรายังไม่เคยพูดถึง เช่น GARCH, RNN, LSTM, GAN, NSVM มันเป็นอะไรที่รายละเอียดมาก ไว้เราจะพูดถึงในโอกาส/คอร์สต่อไปครับ

ตัวอย่าง GAN สำหรับ electricity consumers จากเปเปอร์ Synthetic demand data generation for individual electricity consumers ของคุณ BilgiYilmaz

สรุป

เรื่องพวกนี้มักจะโดนมองข้ามโดยนักสร้าง Algorithmic Trading *The Quants(*เป็น Quants แน่รึเปล่า?) รุ่นใหม่กันมาก ซึ่งจริงๆมันก็มีรายละเอียดเยอะครับ แต่ไม่ว่าจะเรื่อง Machine Learning หรือ เรื่อง Quantitative เองก็ตาม มันก็ไม่ใช่ปรัชญาที่เราจะมาบอกได้นะครับ ว่าอันไหนดีหรืออันไหนแย่อย่างไร แต่เราต้อง ทดลองและเก็บผลด้วยตัวเองครับ เฉพาะเรื่องพวกนี้เราก็สามารถทำวิจัยได้เป็นเรื่องเป็นราวแล้วครับ ทั้ง การสร้างโมเดลให้ที่ทำงาน หรือ ทำวิจัยระดับปริญญาโท/เอก เพื่อหาว่าเราสามารถปรับปรุงโมเดลที่ว่าเหล่านี้เพื่อพัฒนาการเติม Missing Value แล้วส่งผลให้เราพัฒนาโมเดลของเราได้ดีขึ้นอย่างไรครับ แค่เศษเสี้ยวเล็กๆของกระบวนการสร้างโมเดลลงทุนก็เป็นหัวข้อวิจัยได้ยาวๆแล้วครับ

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s