มาหา Feature Importance ใน Machine Leaning Model เพื่ออธิบายให้ได้แบบเซียนกันเถอะ !
Feature Importance คืออะไร ?
ในการทำงานด้านสาย Machine Learning นะครับ สิ่งที่เราต้องทำก็คือ การทำให้โมเดลของเรามีประสิทธิภาพที่ดี มี accuracy ที่สูง เพื่อให้โมเดลเราทำนายได้อย่างแม่นยำ แต่สิ่งที่สำคัญไม่น้อยกว่านั้นก็คือ การหา Feature Importance หรือก็คือการที่เราต้องอธิบายโมเดลของเราให้ได้ว่า ทำไมค่าถึงออกมาเป็นแบบนี้ ? ตัวแปรไหนบ้างที่ส่งผลเชิงบวกหรือเชิงลบต่อค่าการทำนาย และตัวแปรไหนมีความสำคัญอย่างมีนัยยะสำคัญต่อประสิทธิภาพในการทำนาย
Feature Importance สำคัญอย่างไร?
สมมติว่าหากเราต้องการใช้โมเดลเพื่อ predict ว่า ธนาคารควรปล่อยสินเชื่อเงินกู้ให้ลูกค้ารายนี้หรือไม่ หากเรามีแค่ผลการทำนายที่บอกว่า แม่นยำ 90% และทำนายออกมาว่า ไม่ควรปล่อย ซึ่งหากเราฟังดูแค่นี้ หากคุณเป็นฝ่าย business มันก็ดูอาจจะยังไม่น่าเชื่อถือใช่ไหมครับ เราอาจจะตอบว่า model ทำนายออกมาให้เราแบบนี้ แต่เราไม่มีเหตุผลในการรองรับเลย แต่ในทางกลับกัน หากเราหา Feature Importance ออกมา เราก็จะสามารถอธิบายได้ว่า ที่โมเดลไม่ปล่อยสินเชื่อให้นายคนนี้ เพราะ มี Feature A และ Feature C ที่ส่งผลต่อโมเดลดังนี้ บลา ๆ ก็จะเพิ่มความน่าเชื่อถือให้โมเดลเราเพิ่มอีกเยอะเลยใช่ไหมละครับ !?
โดยสรุปแล้วความสำคัญของการหา feature importance มีคร่าว ๆ ดังนี้
- ทำให้มีความเข้าใจ logic ของ model มากขึ้น ว่ามีการคำนวณมาจากอะไร และมี feature ไหนที่ส่งผลต่อการทำนายมากน้อยเพียงใด
- จากข้อ 1 เมื่อทราบแล้วว่า feature ไหนสำคัญหรือไม่มีความสำคัญเลย จะทำให้เราสามารถทำ feature selection ได้ โดยการนำ feature ที่ไม่สำคัญออก เพื่ออาจจะสามารถเพิ่มประสิทธิภาพในการทำนาย และเป็นการลด dimension ของ feature อีกด้วย
- ในบาง business นอกจากการทำให้ได้ประสิทธิภาพในการทำนายที่ดีแล้ว การอธิบายโมเดลก็ยังมีความสำคัญอีกด้วย ดังตัวอย่างข้างบนที่ได้กล่าวถึง เราอาจจะต้องให้เหตุผลธนาคารว่าทำไมถึงไม่ปล่อยสินเชื่อให้ลูกค้ารายนี้ เพื่อให้ธนาคารสามารถอธิบายให้ลูกค้ารายนี้ได้ต่อไป
โดยประเภทของ feature importance อาจแบ่งได้เป็น 2 ประเภทหลัก ๆ ดังนี้
1. Overall feature importances (global interpretation)
โดยคำว่า overall หรือ global ในที่นี้หมายถึง การหา feature importance ที่ model level หรือพูดให้ง่ายกว่านั้นก็คือ feature ที่เราสนใจมีความสำคัญอย่างไรต่อประสิทธิภาพโดยรวมของทั้งโมเดล ไม่ได้จำเพาะเจาะจงต่อผลแต่ละ observation หรือแต่ละเคสตัวอย่างเลย
โดยการหา overall feature importances ก็สามารถทำได้หลายวิธี โดยจะขอยกตัวอย่างวิธีดังนี้
1.1 Default Scikit-Learn’s Feature Importances (.feature_importances_)
โดยทั่วไปหากเราใช้โมเดลที่เป็นโครงสร้าง tree based model นั้น ทาง Scikit-Learn จะมีคำสั่งให้เรียกใช้อยู่แล้วคือ .feature_importances_
โดยหลักการทำงานของมันในกรณีของ โจทย์ classification ก็จะเป็นดูว่า features ที่ใช้แยกในแต่ละ node นั้นสามารถแยกแล้วให้ค่า Gini impurity / Information gain (entropy) มากน้อยเพียงใด และในกรณีของ โจทย์ Regression นั้นก็จะเป็นเรื่องของ variance นั่นเอง
โดยในที่นี้จะขอยกตัวอย่างข้อมูลของ wind quality dataset ซึ่งก็คือเป็นคุณสมบัติต่าง ๆ ของ wine เช่น ปริมาณ residual sugar, alcohol และอื่น ๆ เพื่อมาทำนายว่า quality ของ wine อยู่ใน class ไหนนั่นเอง
ข้อมูล wine dataset สามารถ download ได้จาก : https://www.kaggle.com/sgus1318/winedata
โดยข้อมูล wine dataset ของเรามีหน้าตาเป็นดังนี้
ซึ่งเราสมารถใช้คำสั่งหา .feature_importances_
เพื่อหาความสำคัญของแต่ละ feature ใน model level ได้ดังนี้ครับ
โดยจะเห็นว่า feature ที่ส่งผลต่อการทำนาย quality ไวน์มากที่สุด 3 ลำดับแรก คือ Alcohol, Sulphates และ volatile acidity
โดยวิธีหา feature importances จาก gini impurity ก็จะมีข้อดีข้อเสียดังนี้
ข้อดี : คำนวณได้ไว และ ง่ายต่อการทำ ใช้ code เรียกเพียงแค่คำสั่งเดียว
ข้อเสีย : วิธีนี้อาจจะเรียกได้ว่าเป็น bias approach เพราะว่าในกรณีที่ feature ของเรา เป็น continuous features หรือ high-cardinality categorical variable (ตัวแปร categorical ที่มี class เยอะ ๆ เช่น feature A มี ข้อมูลประกอบด้วย 30 class เป็นต้น) จะส่งผลให้มีการคิด feature importance ที่ผิดเพี้ยนออกมา เพราะว่า feature importance ในกรณีนี้คำนวณมาจาก information gain หรือก็คือใช้ feature นี้ split แล้วทำให้ class pure ได้มากขึ้นเท่าไหร่ ดังนั้นยิ่ง feature มี class เยอะ กลุ่มตัวอย่างต่อ class ก็ยิ่งมีน้อยและเฉพาะเจาะจง ทำให้แยกแล้วมีความ pure มาก เป็นที่มาของการ bias นั่นเอง
1.2 Feature Importances for XGBoost (.get_booster().get_score())
วิธีนี้ก็จะคล้ายกันกับวิธีแรก แต่จะเป็นวิธีที่เรียกใช้สำหรับ XGBoost model โดยเฉพาะนั่นเอง โดยใช้คำสั่ง .get_booster().get_score(importance_type = 'gain')
แต่วิธีนี้จะมีความพิเศษตรงที่เราสามารถเลือกได้ว่า feature importances ที่หามานั้นจะให้คำนวณจาก basis อะไร เช่น gain , weight, coverage เป็นต้น โดยรายละเอียดของแต่ละวิธีมีดังนี้
Gain : ใช้ค่า information gain ในการหาความสำคัญของ features หาก features ไหนใช้แล้วทำให้แยกได้ pure มาก ก็จะมีความสำคัญมาก
Coverage : คือจำนวนของ observation ทั้งหมดที่ถูกแยกได้ด้วย feature นั้น
เช่น หากเรามีจำนวน row = 100 หรือ 100 observations, 5 features และ 3 trees โดยสมมติ จำนวน observation ที่ถูกแยกได้ด้วย feature 1 มีค่าเท่ากับ 8, 4, 2 สำหรับ tree1, tree2 และ tree3 ตามลำดับ ดังนั้นค่า count cover = 8+4+2 = 12 observations นั่นเอง โดยค่า cover จะแสดงอยู่ในรูปแบบ % โดยจากตัวอย่างนี้ค่า cover = 12 % นั่นเอง หรือก็คือ feature 1 สามารถแยก observation ได้ 12 observations จากทั้งหมด 100 observations นั่นเอง
Weight : ใช้จำนวนครั้งที่ feature นั้นถูกใช้เพื่อ split data ใน trees ทั้งหมด
เช่น จากตัวอย่างในข้อ coverage ถ้า feature 1 ถูกใช้ในการ split ของ trees เป็นจำนวนดังนี้ 2 splits, 1 split และ 3 splits ใน tree1, tree2 และ tree3 ตามลำดับ ดังนั้น weight ของ feature 1 = 2 + 1 +3 = 6 นั่นเอง
โดยหากเราลองรัน code ดูเพื่อหา feature importance จากตัวอย่าง wine ด้านบนจะได้ดังนี้
จะเห็นว่าจากการหา feature importances โดยการให้ importance_type หรือ basis การคำนวณต่างกัน ก็จะได้ลำดับความสำคัญของ feature ต่างกันด้วย เช่น
- ใช้ basis เป็น ‘gain’ จะได้ features ที่สำคัญ 3 ลำดับแรกคือ alcohol, sulphates, volatile acidity
- ใช้ basis เป็น ‘cover’ จะได้ features ที่สำคัญ 3 ลำดับแรกคือ alcohol,volatile acidity, sulphates
- ใช้ basis เป็น ‘weight’ จะได้ features ที่สำคัญ 3 ลำดับแรกคือ sulphates, citric acid, free sulfur dioxide
จะเห็นว่าแค่การเลือก basis ของ feature importance ก็ทำให้ได้ผลลัพธ์ที่ต่างกันพอสมควร ถึงแม้ว่าโมเดลจะเหมือนกันทุกประการ ดังนั้นเราจึงควรเลือกให้เหมาะสมนั่นเอง โดยขอยกตัวอย่าง study cases ต่อไปนี้
สมมติว่า เรามี binary feature เช่น gender ที่มี correlation กับ target variable สูงมาก และเราลองทดลองโดยการ drop feature นี้ทิ้ง พบว่าประสิทธิภาพโมเดลตกลงอย่างมีนัยยะสำคัญ ดังนั้นหากเราใช้คำสั่งหา feature importance เราก็คาดหวังว่าจะเห็น gender สำคัญเป็นลำดับแรก ๆ ใช่ไหมครับ แต่บางทีมันอาจจะไม่เป็นอย่างงั้นเสมอไป !!
โดยสาเหตุที่พบพบว่า เราเรียกใช้คำสั่ง feature importances โดยให้ basis คำนวณมาจาก weight ซึ่งหากเราลองพิจารณา feature ที่มี class น้อย ๆ เช่น gender มี แค่ 2 class คือชายกับหญิง (โดยทั่วไป) จะพบว่า feature จะถูกใช้มากสุดแค่ 1 ครั้ง ในแต่ละ tree แต่ถ้าเทียบกันกับพวก high-cardinality categorical variable หรือพวกที่มีหลาย class แล้ว อาจจะถูกใช้ได้มากกว่าเยอะ ซึ่งสิ่งเหล่านี้ส่งผลให้ gender ของเรามีความสำคัญน้อยนั่นเอง แต่หากเราลองเปลี่ยน importance_type เป็น gini เราอาจจะได้ว่า ความสำคัญของ gender อาจจะพุ่งขึ้นมาทีเดียวหละ !!
1.3 Permutation feature importance
วิธีนี้จะเป็นการหาความสำคัญของ feature โดยการ สุ่มและสลับ (random re-shuffling) ของแต่ละ features เพื่อดูว่าหากไม่มี feature นี้ จะส่งผลต่อ model performance อย่างไรนั่นเอง
ข้อดี : ใช้ได้กับทุกโมเดล, ผลน่าเชื่อได้เพราะมาจากประสิทธิภาพของโมเดล
ข้อเสีย : ใช้ computational power เยอะกว่าแบบแรก เนื่องจากต้องหาทุก combination ของ features
โดยตัวอย่างของ code ในข้อนี้จะขอนำเสนอในบทความ XXXX
2. Observation level feature importances (local interpretation)
Observation level ในที่นี้หมายถึงว่า feature ที่เราสนใจมีผลเฉพาะเจาะจงแต่ละ observation อย่างไร เช่น หากเราสนใจว่าใน row แรกของ test set ทำไมโมเดลถึงทำนาย class 1 feature แต่ละ feature ส่งผลต่อค่าการทำนายของ “row 1” อย่างไร จะเห็นได้ว่าเป็นการหา feature importance ที่ specific มากขึ้นนั่นเอง
โดยเพื่อไม่ให้บทความยาวเกินไป เนื้อหาในส่วนนี้ผมขอใส่ไว้ในอีก part ซึ่งสามารถอ่านต่อได้จาก มาเปิด Black Box : Machine Learning Model เพื่อความเข้าใจโมเดล ด้วย LIME, ELI 5 และ SHAP กันเถอะ [1]
บทความนี้ได้รับการสนับสนุนจากบริษัท Knowledge Discovery Co., Ltd.