Solar Power Prediction Model
บทความนี้ถูกเขียนขึ้นมาเนื่องจาก เราได้ร่วมเป็นส่วนหนึ่งของโครงการ Super AI Engineer โดยบทความนี้เป็นบทความของสัปดาห์ที่ 2 นะ (สัปดาห์แรก ยังเขียนไม่เสร็จ รอแปบนะทุกคนนนนน :)
คราวนี้มาในหัวข้อ Model Learning & Evaluation
โจทย์มีด้วยกันทั้งหมด 4 ข้อแหละ
- Solar power generation
- Titanic (ที่เราคุ้นเคย)
- Air bnb
- Hypothesis Testing
สำหรับบทความนี้ ขอโฟกัสกันที่ โจทย์ Solar power generation กันก่อน เพราะว่า ส่งก่อน T^T
Solar Power Generation Data
โจทย์คือ ให้ทำนายค่า ‘TOTAL_YIELD’ โดยใช้ข้อมูลย้อนหลัง 3 วัน , 7 วัน
สั้นๆ ง่ายๆ แค่นี้เลย แต่เอ๊ะ พอลงมือทำแล้ว ก็แอบไม่ง่ายนะ ยังไงไปดูกัน
Load Data
เริ่มต้น load data ทั้งหมดด้วย pd.read_csv(‘file_name’)
ไฟล์ของเรามีทั้งหมด 4 ไฟล์ นั่นคือ
สำหรับการทำ Model เราขออนุญาตโฟกัสกันที่ Plant 1 อย่างเดียวก่อน
Exploratory data analysis (EDA)
โจทย์ต้องการให้เราทำนาย TOTAL_YIELD โดยให้ข้อมูลสองชุดนี้มา เมื่อเราสังเกตจะพบว่า ใน gen1 นั้น จะเป็น result ของการวัดค่า DC_POWER, AC_POWER, DAILY_YIELD ของทุกเวลา 15 นาที ของแต่ละ SOURCE_KEY หากอยากเห็นภาพชัดเจนเราจะขอหยิบตัวอย่างมาตัวหนึ่ง ดังภาพด้านล่าง
สังเกตได้ว่าที่ SOURCE_KEY 1 ตัวนั้น จะมีการวัดผลจาก sensor ออกมาทุกๆ 15 นาที แต่เห็นอะไรไหมนั่น ทำไม ช่วงเวลาที่เริ่มต้นมีค่าของผลการวัดมันเริ่มที่ 6 โมงเช้าหละ??? (เกือบลืมบอก PLANT_ID ตัดทิ้งได้เลยนะครับ มันเป็น ID เดียวทั้ง dataset เลย)
เห็นอะไรจากรูปข้างบนไหมครับ??? แน่นอน code ไง เดี๋ยวก่อนๆๆๆ ไม่ใช่แบนั้นสิ!!!
ลองดู code ด้านบนอีกทีครับ ผมเขียนเพื่อหาว่า ช่วงเวลาที่ DC_POWER มีค่าเป็น 0 เนี่ย เวลาที่มากที่สุดและน้อยที่สุด คือ ช่วงไหน >>> 0,23
และช่วงเวลาที่ DC_POWER ไม่เป็น 0 เวลามากสุดและน้อยสุดคือ 6,18
แล้วยังไงต่อ??? ลองดูดีๆสิ
มันหมายความว่า sensor ของเราเนี่ย แสดงผลตอนช่วงเวลา 6.00–18.45 ไง ก็คือช่วงเวลาที่ยังมีแสดงแดดนั่นเอง (ก็ make sense อยู่นาาา)
ถ้าอย่างนั้น เราลองไปพลอตกราฟกันดูหน่อยดีกว่า ว่าทุกๆ SOURCE_KEY เนี่ย มี การวัดผลของ TOTAL_YIELD เป็นยังไง (ขออนุญาต ยกมาแค่วันที่ 15–05–2020 นะครับ)
แกน x คือช่วงเวลา 6.00–18.45, แกน y คือ ค่าของ TOTAL_YIELD
โอ้โหวววว !!! สวยมากเลยใช่ไหมละ ดูเหมือนว่า SOURCE_KEY ทุกๆตัว จะมีผลที่คล้ายๆกัน แต่ๆ ลองสังเกตดีๆอีกทีสิ เห็นไหมว่า ที่แต่ละ SOURCE_KEY เริ่มต้น ที่คนละค่านะ T^T (จริงๆ เราเองคิดว่าก็ไม่น่าเป็นปัญหาอะไรนะ)
แต่ๆ ลองมาคิดดูอีกทีในแง่ความเป็นจริงสิ ถ้าเราอยากจะทำนายว่า วันนี้เนี่ย เราจะได้ YIELD ทั้งหมดเป็นเท่าไร สิ่งที่เราต้องรู้คืออะไร
TOTAL_YIELD(today) = TOTAL_YIELD(tommorow) + DAILY_YIELD
ถ้าวันนึงเรามี SOURCE_KEY ตัวใหม่เข้ามา มันก็ควรจะเริ่มจาก 0 ใช่ไหมหรือเราไม่มีทางรู้ได้เลยนะว่าก่อนหน้านี้ SOURCE_KEY นี้ มี TOTAL_YIELD มาแล้วเท่าไร ถ้าไม่ได้เก็บข้อมูลในอดีตเอาไว้ใช่ไหมหละ???
ตัวอย่าง
สังเกตว่า ใน dataset เราเนี่ย เริ่มวันที่ 15–05–2020 ใช่ไหม ทุกๆ SOURCE_KEY เนี่ย มี TOTAL_YIELD เก็บมาแล้วนะ ถ้าผมขอคิดใหม่เป็น วันที่ 15 เนี่ย ผมซื้อ sensor ตัวใหม่เข้ามา SOURCE_KEY ตัวใหม่แบบนี้ TOTAL_YIELD ควรจะเป็น 0 ใช่ไหมหละ ถ้าเรานำไปทำนายหลังจากผ่านไป 1 วันเนี่ย มันก็ควรจะออกมาเป็น DAILY_YIELD ของวันนี้ มากกว่าเป็นค่าเฉลี่ยของค่าเริ่มต้นของทุกๆ SOURCE_KEY ใช่ไหมหละ???
งั้นเอางี้ เรามาดูสมการข้างบนใหม่ดีกว่าขอเขียนใหม่เป็น
TOTAL_YIELD(n) = TOTAL_YIELD(n-1) + DAILY_YIELD(n)
n คือ วันที่เราสนใจ
เขียนใหม่อีกได้ไหมอะ
TOTAL_YIELD(n) = (TOTAL_YIELD(n-2)+ DAILY_YIELD(n-1)) + DAILY_YIELD(n)
อ้าวๆๆๆ เห็นอะไรไหม???
TOTAL_YIELD(n) ดูเหมือนจะมีความสัมพันธ์บางอย่างกับ DAILY_YIELD(n),DAILY_YIELD(n-1),DAILY_YIELD(n-2),…DAILY_YIELD(1)
ถ้าอย่างนั้นเนี่ย ผมเปลี่ยน Objective ของเราเป็นทำนาย DAILY_YIELD ดีกว่าไหมนะ
แต่ภายใต้โจทย์ที่ได้รับมาเราจะยังคงทำนาย TOTAL_YIELD อย่าลืมและสำคัญมากว่า เราไม่ควรจะเปลี่ยนโจทย์เอง
แต่เราจะทำนาย TOTAL_YIELD ของเรา โดยตั้งสมมติฐานว่า เรารู้ TOTAL_YIELD ก่อนหน้ามาแล้ว
TOTAL_YIELD(n) = TOTAL_YIELD(n-1) + DAILY_YIELD(n)
ถ้าเราสามาถทำนาย DAILY_YIELD ได้ เราก็จะสามารถทำนาย TOTAL_YIELD(n) ได้
ทีนี้เราลองมาพลอตกราฟของ DAILY_YIELD กันหน่อยดีกว่าว่าที่ อธิบายมาทั้งหมดเนี่ย มันเข้าท่าไหมน้าาาา
เอ้า!!! เหมือนเดิมเลยหนิ???
ดูดีๆก่อน ในทุกๆ SOURCE_KEY ของเรา เริ่มต้นที่ 0 แล้วเหมือนกันนะ ความหมายก็คือ ที่เวลาเริ่มต้น 6 โมง DAILY_YIELD ของเราจะเริ่มเก็บผลของการวัดออกมาจนกระทั่งเวลา 18.45 นั่นเอง คำถามคือ ถ้าวันนี้เราจะทำนาย DAILY_YIELD ของ sensor ตัวที่เราซื้อมาใหม่เนี่ย สมเหตุสมผลรึยัง??? (ก็ make sense แล้วนาาา)
ก็ดูจะสมเหตุสมผลแล้วนะ แต่ขอตั้งสมมติฐานเพิ่มอีกหน่อยก็แล้วกันว่า ทุกๆ sensor เนี่ย ทำงานด้วยประสิทธิภาพแบบเดียวกันภายใต้สภาพแวดล้อมที่เหมือนกัน ถามว่าทำไมต้องตั้งสมมติฐานนี้ ???
ก็ถ้า sensor ที่เราซื้อมามันเจ๋งมากเพราะไม่เคยถูกใช้ สามารถวัดค่าได้ตรงมาก ขณะที่ sensor ที่ใช้มานานแล้วก่อนหน้านี้คุณภาพแย่แล้ว วัดตรงบ้างไม่ตรงบ้าง แบบนี้ก็มีผลต่อ model ของเราอยู่นะ
ทุกๆ SOURCE_KEY ก็ดูจะมีลักษณะการทำงานที่ใกล้เคียงกันอยู่นะ
ลุยกันต่อๆๆ
Feature Engineering
ในโจทย์ครั้งนี้ เราจะใช้ข้อมูลของ 3 วันก่อนหน้า, 7 วันก่อนหน้า เพื่อเปรียบเทียบกัน
หมายความว่าเราจะต้องเพิ่ม feature columns เข้าไป โดยใช้ข้อมูลก่อนหน้า
ในทีนี้เราต้องมาดูกันก่อนว่า dataset ของเราหน้าตาเป็นอย่างไร มาจนถึงตอนนี้ เพื่อนๆอาจจะมีคำถามในหัวกันบ้างแล้วว่า อ้าว!!! แล้วของมูลของ weather1 ละ บอกอะไรได้บ้าง แน่นอนมันเป็นข้อมูลของการวัดสภาพอากาศในแต่ละวัน เราก็สามารถมองได้ว่ามันส่งผลกับ DAILY_YIELD นะ เช่น ในวันที่ แดดแรงกับวันที่ฝนตก มันก็ต้องส่งผลอยู่นะฉะนั้น เราก็ต้องนำข้อมูลส่วนนี้เข้ามาคิดด้วย
จึงต้องนำ gen1, weather1 มารวมกันด้วย key DATE_TIME
ขณะเดียวกันก็ต้องดึงข้อมูลย้อนหลังมาใช้งาน (ขออนุญาตข้าม coding ไปนะ เดี๋ยวจะตาลายกันเปล่าๆ )
ฟังก์ชัน feature_eng รับค่า prevDays ซึ่งเป็นตัวบอกว่า เราจะใช้ข้อมูลย้อนหลังกี่วัน ในทีนี้ใช้ทั้งหมด 3 วัน suffix = _(จำนวนวัน ย้อนหลัง)
เหมือน Data จะใกล้เสร็จสมบูรณ์พร้อมสำหรับนำไปใช้งานแล้วนะ แต่เราขอเพิ่มอีกนิดละกัน สังเกตว่า DAILY_YIELD ของเราเนี่ย ขึ้นกับเวลาด้วย เช่น ช่วง 6.00 จะยังมีค่าน้อยอยู่ พอเริ่มเที่ยงจะขึ้นด้วยความชันสูงมาก พอตกเย็นความชันจะเริ่มตกลงค่าจะเริ่มคงที่ ถ้างั้นเราขอมองว่า ช่วงเวลาของการเก็บค่าก็มีผลเช่นกัน จึงขอเพิ่มมาอีกสองคอลัมน์คือ Hour, Minute
โจทย์กำหนดให้แบ่งใช้ 10-folds และแบ่งเป็น 90% Train, 10% Test
Model
ในที่นี้ขอใช้ 3 model ในการเปรียบเทียบ ได้แก่ Random Forest, XGboost, LinearRegression
Evaulation
ขอใช้ Root-Mean-Square-Error (RMSE) เป็นตัวชี้วัด
Result
ผลที่ได้จะมีหน้าตาดังรูปทางด้านซ้ายมือ
แสดงตัวอย่างผลของการทำ 10-Folds สำหรับ
XGBoost
เมื่อเก็บผลทั้งหมดแล้วจะได้ดังรูปด้านล่าง
พลอตกราฟ DAILY_YIELD เทียบกัน
พลอตกราฟ TOTAL_YIELD เทียบกัน
โดยเชื่อว่าค่าของ TOTAL_YIELD column คือ TOTAL_YIELD ของวันก่อนหน้า
สรุปผล
ผลจากการใช้ข้อมูลย้อนหลัง 7 วันมีประสิทธิภาพที่ดีกว่าการใช้ข้อมูลย้อนหลัง 3 วันเล็กน้อย
ก็ดูสวยอยู่นะ
ทีนี้ ลองเอาไปเทียบกับ gen2,weather2 ดีกว่า ว่าเวิร์คไหม
ขอเลือกใช้ XGboost เป็นตัวแทน modelที่ใช้ เนื่องจากดูแล้วให้ผลที่ดีที่สุด
สำหรับ 3 วัน ย้อนหลัง
ดูไม่เวิร์คสักเท่าไร ทีนี้เพิ่มเติมอีกสักหน่อยหาเหตุผลเบื้องต้นว่าทำไม ใช้กับ dataset ชุดที่ 2 แล้วได้ผลไม่ดีเท่าที่ควร
ลองพลอตกราฟ TOTAL_YIELD, DAILY_YIELD ตามลำดับ
TOTAL_YIELD
DAILY_YIELD
หลังจากที่เราได้ลองใช้ไปแล้วพบว่า
- Data ไม่ได้ถูก clean อย่างสมบูรณ์ มีข้อมูลบางส่วนหายไป อาจเกิดจากการวัดค่าที่แต่ละช่วงเวลาทำให้ไม่มีผลค่านั้นๆอออกมา
- สังเกตที่กราฟ DAILY_YIELD จะพบว่า dataset ชุดที่ 2 นี้ ไม่เป็นไปตามสมมติฐานของเราที่ตั้งไว้ว่าทุก sensor จะมีประสิทธิภาพในการวัดการทำงานที่ใกล้เคียงกันในสภาพแวดล้อมแบบเดียวกัน (สังเกตว่า ค่า range จากสูงสูงไป ต่ำสุด ของ dataset ชุดที่ 2 มีค่ากว้างกว่า dataset ชุดที่ 1 )
สุดท้ายนี้ ขอขอบคุณโครงการ Super AI Engineer ที่จัดโครงการและมอบประสบการณ์ดีๆแบบนี้ขึ้นครับ
ไว้เจอกันบทความหน้าครับ
Ref: Google Colab
https://colab.research.google.com/drive/15NPo_YyyfNPZfj5ImhUskteBRsGtalwg?usp=sharing