บันทึก training data science EP 4: Scikit-learn & Linear Regression – แนวโน้มของเส้นตรง

บันทึก training data science EP 4: Scikit-learn & Linear Regression – แนวโน้มของเส้นตรง

ตอนก่อนหน้า: บันทึก training data science EP 3: Matplotlib & Seaborn – แผนที่ดูแพง

จาก EP 3 เราได้ดูวิธีการสร้างกราฟ ซึ่งเป็นขั้นตอนการวิเคราะห์เบื้องต้นและนำเสนอไปแล้วนะฮะ คราวนี้ เราจะใช้เวลาเพื่อวิเคราะห์แนวโน้มของข้อมูลกัน

ความรู้พื้นฐานของ Data scientist อันนึง คือ การคาดการณ์แนวโน้มของข้อมูลในแนวเส้นตรง ซึ่งสมการเส้นตรงในวิชาคณิตศาสตร์ คือ \(Y = aX + b\) และเส้นตรงนี้จะลากผ่านจุดข้อมูลแต่ละจุดให้ได้มากที่สุด หรือไม่ก็จะมีระยะห่างระหว่างจุดกับเส้นน้อยที่สุด ถึงจะเป็นเส้นตรงที่ดีที่สุด ถูกมั้ยฮะ

เส้นตรงที่สมมติขึ้นมาในรูปข้างบน มันไม่ได้ลากผ่านทุกจุด จุดที่ไม่ได้ลากผ่าน เราจะเรียกว่า Outlier เป็นค่าข้อมูลที่ถือว่าเป็น error ถ้าเส้นตรงที่เราลากทำให้เกิด outlier มากๆ อาจจะสื่อได้สองอย่างคือ เส้นตรงของเราไม่ได้ดีที่สุด หรือตัวข้อมูลมี error มากเกินไปจนเราลากเส้นตรงไม่ได้

เรามาดูกันว่า มันจะมีวิธีไหนบ้างที่ทำให้เราได้สมการเส้นตรงที่สวยงามฮะ

Theil-Sen estimator

Theil-Sen estimator ใช้การลากเส้นตรงระหว่างจุดสองจุดที่สุ่มขึ้นมา พอได้เส้นตรงเยอะๆ แล้วค่อยหาค่าเฉลี่ยของเส้นพวกนั้น ข้อดีของวิธีนี้ คือ คำนวณได้ค่อนข้างเร็วเลยฮะ แต่มีเงื่อนไขว่าหากข้อมูลมีการกระจายมาก ผลลัพท์ที่ได้จะมี error สูงฮะ

RANSAC algorithm

RANSAC มาจากคำว่า RAndom SAmple Consensus แปลตรงๆ ว่า การเลือกข้อมูลกลุ่มใหญ่แบบสุ่มมาเป็นกลุ่มตัวอย่าง หลักการคือ สุ่มหยิบจุดสองจุดมาขีดเส้นตรง จากนั้น นับจำนวนจุดที่ผ่านเส้นตรงนั้น ทำแบบนี้ไปจนกว่าจะได้เส้นตรงที่มีจำนวนจุดผ่านเส้นมากพอฮะ

เพราะมันใช้วิธีการนับจุดที่ผ่านเส้น แปลว่าผลลัพท์คือค่าความชัน \(slope=\frac{y_1-y_2}{x_1-x_2}\) ที่เหมือนกันมากที่สุด ทำให้ข้อดีคือ หากมี outlier ในแกน y มากขึ้น มันก็ยังทำงานได้ดีอยู่ (outlier แกน x ทำให้ค่าความชันเปลี่ยนไปมากจากสมการ) เช่น ในการหาความสัมพันธ์ระหว่างอายุ (แกน x) กับความสูง (แกน y) ถ้าข้อมูลมีช่วงอายุไล่เลี่ยกันแต่ความสูงต่างกันมาก RANSAC ยังทำงานได้โอเคดีฮะ ทั้งนี้ RANSAC จะใช้เวลาคำนวณมากกว่า Theil-Sen นะ

Huber regression

Huber ใช้การคำนวณจากการกำหนดค่าคงที่ค่านึงมา เรียกว่า \(\epsilon\) (epsilon) ซึ่งมีค่ามากกว่า 1.0 จากนั้นคำนวณสมการเทียบกับค่า epsilon ที่ว่า เพื่อให้ได้ผลลัพท์สมการเส้นตรงออกมาฮะ

ข้อดีคือคำนวณได้เร็วกว่าสองตัวแรก

Reference link: https://scikit-learn.org/stable/auto_examples/linear_model/plot_robust_fit.html


เอาล่ะ เรามาลองเล่นกันบน Jupyter กันฮะ

Scikit-learn

ครั้งนี้เราจะใช้ library sklearn หรือชื่อเต็มว่า scikit-learn กันฮะ มันเป็น library ที่ค่อนข้างครบเครื่องระดับนึงสำหรับงานวิเคราะห์ข้อมูล

เริ่มต้นจาก import sklearn.linear_model เป็น module ที่รวบรวม linear regression model เพื่อวิเคราะห์เป็นสมการเส้นตรงฮะ แล้วเราก็ยัง import sklearn.model_selection เพื่อปรับปรุงข้อมูลก่อนวิเคราะห์นะฮะ

จากนั้น ผมจะใช้ข้อมูล titanic เจ้าเก่า เลือก Pclass, age, และ fare เป็นวัตถุดิบของงานนี้ฮะ

เราจะแยก 3 column ตะกี้เป็นตัวแปรต้น x ได้แก่ Pclass และ age ส่วนตัวแปรตาม y คือ fare นั่นคือเราจะมาหาค่า fare จาก Pclass และ age กันฮะ

ใช้ฟังก์ชัน sklearn.model_selection.train_test_split() เพื่อสุ่มแบ่งชุดข้อมูล x และ y ให้เป็นสองก้อนย่อย คือ ก้อน train และ test ทีนี้ผมกำหนด test_size เป็น 0.1 แปลว่า ก้อน test จะมีขนาดแค่ 10% จากตัวเต็มฮะ เราจะได้ข้อมูล 4 ก้อนมาฮะ

Reference link: https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html

Scikit-learn with Theil-sen

เอาล่ะ เรามาเริ่มวิเคราะห์กัน เริ่มจาก Theil-Sen เราสร้าง TheilSenRegressor object ขึ้นมาก่อน จากนั้นใช้คำสั่ง fit() พร้อมโยนก้อน test ของ x และ y เพื่อคำนวณสมการออกมา เสร็จแล้วก็ทดสอบหาแนวโน้มด้วยคำสั่ง predict() และโยนก้อน test ของ x เราก็จะได้ผลลัพธ์ของสมการเส้นตรงที่มันวิเคราะห์แล้วฮะ

สองค่าข้างล่าง คือ

  • coef_ คือค่าความชัน หรือ \(a\) จากสมการ \(Y = aX + b\) ที่พูดถึงข้างบนฮะ
  • intercept_ คือ \(b\)

จากค่าข้างบน ก็สรุปได้ว่า Theil-Sen estimator ให้สมการเป็น \(fare=-13.19\times Pclass - 0.04\times age + 51.49\).

ที่ค่า y_train ใช้ฟังก์ชัน .values.ravel() เพราะแก้ปัญหาประเภทตัวแปรฮะ (อ้างอิง)

Scikit-Learn with RANSAC

จบจาก Theil-Sen ก็มาใช้ RANSAC กันฮะ ด้วย RANSACRegressor()

ทำแบบเดิมเลย เราได้สมการเป็น \(fare=-10.86\times Pclass + 0.02\times age + 40.80\).

Scikit-Learn with Huber

คราวนี้เป็น Huber เราก็ใช้ HuberRegressor()

ได้สมการ \(fare=-21.23\times Pclass - 0.25\times age + 79.99\).

เปรียบเทียบผล

เราเก็บค่าการคาดการณ์เอาไว้แล้ว ก็เอามา plot ให้แกน x ของกราฟเป็นค่า y ก้อน test หรือก็คือ fare ที่มีขนาด 10% นั่นแหละ ส่วนแกน y ของกราฟเป็นค่า predict ของทั้งสามวิธีที่คาดการณ์จากค่า x ก้อน test ฮะ

จากกราฟ จะเห็นว่า Huber ค่อนข้างคาดการณ์ได้ใกล้เคียงกว่าสองตัวที่เหลือนะฮะ แต่แค่ตาดูอาจยังไม่แม่น เราคงต้องใช้ตัวช่วยฮะ

Metrics

เรามี sklearn.metrics เพื่อช่วยประเมินค่าความถูกต้องของผลลัพท์ฮะ เราจะเอามาใช้สามตัว ได้แก่

  • r2_score()
    \(r^2\) แปลตรงตัวคือ สัมประสิทธิ์การตัดสินใจ มันเป็นค่าวัดผลการคาดการณ์เทียบกับค่าที่เกิดขึ้นจริง ยิ่งมากยิ่งดี เพราะมันแปลว่าการคาดการณ์ค่อนข้างแม่นยำมากขึ้น (วิกิพีเดีย)
  • median_absolute_error()
    \(MedAE\) แปลตรงตัวว่ามัธยฐานของส่วนต่างความผิดพลาด ได้มาจากการหาความต่างระหว่างค่าคาดการณ์กับค่าจริง จากนั้นหาค่ามัธยฐาน (median) ค่าที่ได้จะบอกว่า สมการนี้ให้ผลลัพท์ผิดพลาดเป็นค่ากลางเท่าใด ยิ่งน้อยยิ่งดี (O’Reilly)
  • mean_absolute_error()
    \(MAE\) หรือค่าเฉลี่ยของส่วนต่างความผิดพลาด ได้จากการหาความต่างระหว่างค่าคาดการณ์กับค่าจริง เอามาหาค่าเฉลี่ย (mean) ค่าที่ได้บอกว่า โดยเฉลี่ยแล้วสมการนี้ให้ผลลัพท์ผิดพลาดไปเท่าใด ยิ่งน้อยยิ่งดีฮะ (วิกิพีเดีย)

จากรูปข้างบน จะเห็นได้เลยว่า Huber ให้ผลลัพท์แม่นยำกว่าฮะ


จู่ๆ ก็โจมตีด้วยสมการคณิตศาสตร์รัวๆ แบบไม่ทันตั้งตัว ผมเองยังมึนเองเหมือนกันฮะ

แล้วรอบหน้าจะมาเล่าต่อฮะ

บาย

ตอนต่อไป: บันทึก training data science EP 5: Logistic Regression & Dummy Classifier – Regressor ที่ไม่ใช่ Regressor

Show Comments