Decision Tree ใครเป็นเบาหวานอธิบายง๊ายง่าย : Machine Learning 101

Mr.P L
mmp-li
Published in
4 min readDec 3, 2018

หลังจากที่ผ่านมาหลายบล็อกแล้ว มีคณิตศาสตร์ยุ่งยาก ใช้ศัพท์ยุ่งยาก ทำอะไรยากๆ วันนี้เรามาทำอะไรง่ายๆกัน โดย Machine Learning model ตัวนี้เรียกว่า Decision Tree มันง่ายยังไง ? ตัว DT มีสิ่งหนึ่งที่เรียกว่า graphviz ที่จะช่วยทำให้โมเดล Decision tree เนี่ยสามารถ export ออกมาเป็น tree สวยๆงามๆพร้อมเหตุผลในการตัดสินใจให้เราดูได้อีกด้วย

Decision Tree คือ ?

Machine Learning Model Classification ตัวหนึ่งที่สามารถอธิบายได้ว่าทำไมถึงแบ่งเป็นคลาสนี้ ทำไมต้องเป็นคลาสนี้ สามารถอธิบายได้ด้วยรูปแบบของ “TREE”

นั้นคือมี Node พ่อเป็นคนตั้งคำถามว่าใช่หรือไม่ Node ลูกตัวแรกอาจจะเป็นใช่ อีกตัวจะเป็นไม่ โดยปัจจัยสำคัญในการสร้างโมเดลี้คือ “ความลึกของต้นไม้”

ยิ่งต้นไม้ลึก (มีจำนวนชั้นที่มาก) ก็จะถามได้ละเอียดมากยิ่งครับ แต่ก็จะยิ่ง overfit มากขึ้น แต่ถ้าจำนวนชั้นที่น้อยไป ก็จะไม่แม่นยำพอจะใช้งาน

Graphviz ?

เป็น tool ตัวหนึ่งในการวาดกราฟเหมือนรูปข้างบนขึ้นมา โดยถ้าเราใช้กับ Decision tree เราไม่ต้องเขียนเงื่อนไข ไม่ต้องเขียนคำตอบเอง แค่ใส่ข้อมูลกับเฉลยเข้าไปแล้ว export เป็น graphviz เท่านี้ก็จะได้กราฟทรีออกมาแล้ว

ลงมือทดลอง

ที่ผ่านมาเราได้ลอง GridsearchCV, train_test_split แล้วแต่ยังเหลืออีกกระบวนการที่เรายังไม่ได้ทำคือการ normalization dataset ทำให้ค่า dataset กลายเป็น mean 0 variance 1 (เดียวจะอธิบายจากการลงมือทดลอง)

ขั้นตอนแรกโหลด Dataset จาก github มาก่อน

ขั้นต่อไปทำการเปิด jupyter notebook แล้วสร้างไฟล์ python พร้อมกับเปิดไฟล์ csv ได้เลย

import pandas as pddata = pd.read_csv(‘pima-indians-diabetes.csv’)
data.head()

ทีนี้ลองสังเกตุค่าต่างๆใน dataset ของเรา

data.describe()

จะพบว่าค่า min ของบาง feature มีค่าเป็น 0 ซึ่งตามหลักความเป็นจริงไม่ควรจะมีเพราะ BMI มีใครมีค่า = 0 บางละ ? เราจึงตีค่า 0 เป็น outlier นั้นเอง

เราต้องทำการแก้ค่า 0 เป็นค่าอย่างอื่นก่อน ขั้นแรกปรับค่า 0 ทั้งหมดเป็นค่า NaN

import numpy as np
data[[“Glucose_concentration”,’Blood_pressure’,’Triceps’,’Insulin’,’BMI’,’Pedigree’]] = data[[“Glucose_concentration”,’Blood_pressure’,’Triceps’,’Insulin’,’BMI’,’Pedigree’]].replace(0,np.NaN)

ทีนี้ลองเช็คค่า NaN ใน dataset ของเราดู

data.isnull().sum()

จะพบว่า outlier ก็มีจำนวนมากพอตัว โดยในบทความที่ผ่านมาเราได้ใช้ imputer ในการปรับค่า NaN เป็นค่าอื่น แต่ความจริงแล้วในตัว pandas ก็สามารถทำได้เช่นกันเพียงแค่จะยุ่งยากกว่านั้นคือ fillna() โดยให้เลือกค่ามาใส่แทนที่ค่า NaN ได้เหมือนกับ Imputer เลย

data[‘Glucose_concentration’].fillna(data[‘Glucose_concentration’].mean(), inplace = True)
data[‘Blood_pressure’].fillna(data[‘Blood_pressure’].mean(), inplace = True)
data[‘Triceps’].fillna(data[‘Triceps’].median(), inplace = True)
data[‘Insulin’].fillna(data[‘Insulin’].median(), inplace = True)
data[‘BMI’].fillna(data[‘BMI’].median(), inplace = True)
data[‘Pedigree’].fillna(data[‘Pedigree’].median(), inplace = True)
ทีนี้ค่า NaN ทั้งหมดก็จะหายไป

ขั้นต่อไปมาตรวจดูความสัมพันธ์ของข้อมูลว่ามี feature ไหนบ้างที่ส่งผลกระทบต่อโมเดลนั้นเอง

def plot_box(data, cols, col_x = ‘Class’):
for col in cols:
sns.set_style(“whitegrid”)
sns.boxplot(col_x, col, data=data)
plt.xlabel(col_x) # Set text for the x axis
plt.ylabel(col)# Set text for y axis
plt.show()
num_cols = [‘Number_pregnant’, ‘Glucose_concentration’, ‘Blood_pressure’, ‘Triceps’,
‘Insulin’, ‘BMI’, ‘Pedigree’, ‘Age’]
plot_box(data, num_cols)

จะได้ผลลัพธ์ดังนี้

ขั้นตอนนี้จะยุ่งยากนิดหน่อยคือ Feature Selection นั้นคือเลือกปัจจัยที่จะส่งผลต่อโมเดลของเราโดย “เจ้ากล่อง 2 สีมันคือกลุ่มข้อมูลที่ส่วนมาก จะรวมตัวกันที่ไหน” ส่วนเส้นที่อยู่กลางๆกล่องคือ mean ของข้อมูลนั้นๆ เราจะเลือกข้อมูลที่มันเห็นได้ชัดว่าต่างกันจริงๆ

หรืออีกวิธีที่ได้ไปเรียนจากคอร์สของ Microsoft

  1. Greedy Algorithm นั้นคือเลือกที่ละ 1 feature นำไปทดสอบค่าความแม่นยำแล้วก็เลือกเพิ่มอีก 1 feature จากนั้นก็ทำเหมือนเดิม จนกว่าค่าความแม่นยำของเราจะนิ่งแล้ว
  2. Backward Algorithm ตอนแรกให้เลือกทุก feature เอาไปทดสอบความแม่นยำ จากนั้นค่อยๆเอาออกทีละ feature แล้วก็เทสอย่างนี้ไปเรื่อยๆจนกว่าความแม่นยำของเราจะตกลงมาก แล้วก็หยุดเอาออกทันที

แต่วันนี้เราจะโยนทั้งหมดเข้าไปก่อน เพราะขั้นตอนนี้เราจะนำไปใช้กับบทความหน้า (Neural net) เพราะจะเห็นผลได้ชัดเจนกว่า

ทีนี้เราก็แบ่งข้อมูลเป็น X,y โดยเราเลือกทุก Feature มาใช้กับโมเดลของเรา

X=data[num_cols]
y=data[‘Class’]

และทำการ Scale ข้อมูลในตัวแปร X ทั้งหมด

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()
X = scale.fit_transform(X)

จากนั้นจึงค่อยนำข้อมูลไปแยกเป็นชุดฝึกและชุดทดสอบ

from sklearn import preprocessing
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

จากนั้นทำการหา hyper parameter และ parameter ที่เหมาสมกับ dataset ของเรา

โดย Decision tree จะมีสิ่งที่จะต้องปรับหลักๆคือ max_depth จำนวนชั้นของต้นไม้ ถ้า max_depth เป็น 3 ชั้นความลึกของต้นไม้เราจะไม่เกิน 3 นั้นเองเราจะทำการลองกับค่า max_depth 1–10 ว่าค่าไหนจะดีที่สุด

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
import numpy as np
param_grid = {‘max_depth’: np.arange(1, 10),
‘criterion’:[‘entropy’,’gini’]}
tree = GridSearchCV(DecisionTreeClassifier(), param_grid)
tree.fit(X_train, y_train)
tree.best_estimator_

ก็จะได้ว่า max_depth = 2, criterion = gini

จากนั้นก็นำโมเดลไปทดสอบกับข้อมูลชุด test ต่อได้เลย

y_pred = tree.predict(X_test)
from sklearn.metrics import accuracy_score,classification_report
print(accuracy_score(y_test, y_pred))
print(classification_report(y_test, y_pred))

แต่ถ้าเราไม่เชื่อ gridsearchCV เราอยากทดสอบเองว่าค่าอื่นไม่ดีเท่าค่า 2 ผมก็จะลองกับค่าอื่นๆดู

ค่า max_depth = 10,1,3

ก็จะพบว่าค่า 2 นี้เหละดีที่สุดแล้วสำหรับ dataset ชุดนี้

ทีนี้เราก็จะทำ decision tree ให้ออกมาเป็นรูปภาพเพื่ออธิบายว่าทำไมถึงตัดสินใจว่าข้อมูลนั้น เป็นเบาหวานหรือไม่เป็นเบาหวานด้วย export_graphviz

from sklearn.tree import export_graphviz

จากนั้นให้เราใส่ tree ที่ทำการเทรนลงไปใน export_graphviz โดยใส่ feature_name กับ class_names จากนั้นก็ปริ้น tree ออกมาได้เลย


tree_dot = export_graphviz(
tree,
out_file=None, # or out_file=”iris_tree.dot”
feature_names=num_cols,
class_names=’Class’,
rounded=True,
filled=True
)
print(tree_dot)

จะได้ข้อความเยอะๆแบบนี้

ให้เราก็อปข้อความทั้งหมดไปลงที่เว็บ http://www.webgraphviz.com/

แล้วก็กด generate graphviz จะได้รูปประมาณนี้

เราก็จะสามารถอธิบายได้ว่าทำไมโมเดลนี้ถึงตัดสินใจว่าใครเป็นเบาหวานหรือไม่เป็นเบาหวานนั้นเอง

โดยเงื่อนไขคือบรรทัดแรกในกล่องสี่เหลี่ยมนั้นเอง ถ้าใช่ก็จะไปทางด้านซ้ายจนสุดท้ายก็จะได้ว่าเป็นคลาสอะไรนั้นเอง

สรุปการทดลอง

จากบทความที่ผ่านมาเราจะอธิบายได้ยากนิดหน่อยว่าทำไมโมเดลเราถึงตัดสินใจเป็นคลาสนี้ หรือไม่เป็นคลาสนี้ แต่ Decision tree จะสามารถอธิบายได้ง่ายด้วยการทำ Tree และยังสามารถเอา tree แบบนี้ไปใช้กับงานนำเสนอได้ด้วยเพราะอธิบายได้ง่ายนั้นเอง

บทความถัดไป :

Random Forest ทำนายว่าจักรยานจะขายได้ก็ต่อเมื่อ….

Github : https://github.com/peeratpop/Machine_Learning_101

Medium : https://medium.com/@pingloaf

Linkedin : https://www.linkedin.com/in/peerat-limkonchotiwat/

บทความนี้เป็นส่วนหนึ่งของบทความ

เริ่มเรียน Machine/Deep Learning 0–100 (Introduction)

--

--

Mr.P L
mmp-li
Editor for

Lifestyle of Programmer & IoT (Node-RED|Blynk) & Data Science (ML,DL,NLP) and Whatever I want to do | cat can coding too | Ph.D. -> VISTEC -> IST