Solar Power Prediction Model

Petchakrit Pinyopawasutthi
5 min readSep 30, 2020

--

บทความนี้ถูกเขียนขึ้นมาเนื่องจาก เราได้ร่วมเป็นส่วนหนึ่งของโครงการ Super AI Engineer โดยบทความนี้เป็นบทความของสัปดาห์ที่ 2 นะ (สัปดาห์แรก ยังเขียนไม่เสร็จ รอแปบนะทุกคนนนนน :)

คราวนี้มาในหัวข้อ Model Learning & Evaluation

โจทย์มีด้วยกันทั้งหมด 4 ข้อแหละ

  1. Solar power generation
  2. Titanic (ที่เราคุ้นเคย)
  3. Air bnb
  4. Hypothesis Testing

สำหรับบทความนี้ ขอโฟกัสกันที่ โจทย์ Solar power generation กันก่อน เพราะว่า ส่งก่อน T^T

Solar Power Generation Data

https://canbaral-la.com/few-important-facts-that-you-need-to-know-about-solar-energy-generation/

โจทย์คือ ให้ทำนายค่า ‘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

เมื่อเก็บผลทั้งหมดแล้วจะได้ดังรูปด้านล่าง

ข้อมูลย้อนหลัง 3 วัน
ข้อมูลย้อนหลัง 7 วัน

พลอตกราฟ 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

หลังจากที่เราได้ลองใช้ไปแล้วพบว่า

  1. Data ไม่ได้ถูก clean อย่างสมบูรณ์ มีข้อมูลบางส่วนหายไป อาจเกิดจากการวัดค่าที่แต่ละช่วงเวลาทำให้ไม่มีผลค่านั้นๆอออกมา
  2. สังเกตที่กราฟ 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

--

--