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

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

รู้หรือไม่ ว่าข้อมูลที่ทุกท่านได้กรอกตอนสมัครสมาชิกสามารถเอามาใช้ประโยชน์ได้ !

มาถึงบทสรุปสุดท้ายของ Machine Learning กันแล้ว อัลกอริทึมตัวนี้จะเป็นตัวสุดท้ายแล้วสำหรับบทความสุดยาวอันนี้จากนั้นก็จะขึ้นเรื่อง Neural Network แล้วก็ NLP จากนั้น….ก็แล้วแต่อารมณ์

บทความนี้มาจากการที่ผมได้ไปสอบใบ Cert ของ edX มา

สาธุก่อนรันโค้ด

แล้วเขาก็ให้โจทย์มาว่า ช่วยจัดการข้อมูลให้หน่อยว่ากลุ่มลูกค้าของร้านจักรยานนี้อยู่ในกลุ่มคนประเภทไหนบ้าง (ช่วงอายุ/ครอบครัว/สถานะ) จากนั้นก็ทำนายว่าถ้ามีลูกค้าข้อมูลประมาณนี้ ลูกค้าคนนี้จะชื้อจักรยานจากร้านนี้หรือไม่ ?

ในบทความหลังๆผมก็เริ่มจะเอ๋ยถึงการ Visualization ไปบ้างแล้วแต่วันนี้เราจะมาทำกันแบบจริงๆจังๆ แล้วก็จะนำมาประยุกต์กับชีวิตจริงกันบ้าง อาจจะทำให้หลายๆท่านได้เห็นถึงความสำคัญของข้อมูลเวลาที่ลูกค้าสมัครสมาชิกกับเรา และนำไปใช้ประโยชน์ได้

Random Forest คืออะไร ?

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

เอาผลลัพธ์มารวมกันแล้วหาร 4 จะได้คำตอบของการทำนาย

ทำงานยังไง ?

การรวมตัวกันของต้นไม้ 3 ต้น

ตัวอย่างในรูปคือมีต้นไม้ 3 ต้น จากนั้นแต่ละต้นก็ทำนายผลลัพธ์ออกมา ระบบจะเปิดโหวต ว่าคำตอบสุดท้ายควรจะออกมาเป็นคลาสไหน (สำหรับ Classification) แต่สำหรับ Regression จะเป็นการ average ค่าของต้นไม้ทุกๆต้น

เริ่มทดสอบ

โหลด Data set แล้วมาทดสอบไปพร้อมๆกันได้เลย

ขั้นตอนแรก ทำการเปิดไฟล์ .csv ทั้ง 2 ไฟล์ ไฟล์แรกคือ AdvWorksCusts จะเป็นข้อมูลของลูกค้า อีกไฟล์คือ AW_BikeBuyer จะเป็นตัวที่บอกลูกค้าคนนั้นชื้อหรือไม่

import pandas as pd
f_detail = pd.read_csv(‘AdvWorksCusts.csv’)
f_status = pd.read_csv(‘AW_BikeBuyer.csv’)

แต่ผมจะเอาทั้ง 2 รวมกันเพราะ 2 อันนี้มันเรียงลูกค้ามาให้แล้ว (ที่จริงไม่รวมก็ได้ จะแยก x,y ตรงนี้เลยก็ได้) แต่พอดีผมเอาไว้เผื่อทำ Analysis ข้อมูลด้วย

data = pd.concat([f_detail, f_status[‘BikeBuyer’]], axis=1)

จากนั้นก็ลองเปิดดู

ทีนี้มาถึงขั้นตอนการอธิบายว่าเราควรจะเลือก column ไหนบ้าง

import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
def plot_box(data, cols, col_x = 'BikeBuyer'):
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 = ['Gender','MaritalStatus','Occupation', 'HomeOwnerFlag',
'NumberCarsOwned',
'NumberChildrenAtHome',
'TotalChildren',
'YearlyIncome']
plot_box(data, num_cols)

จะได้ผลลัพธ์ประมาณนี้

แกน X คือ 0 = ไม่ชื้อ , 1 = ชื้อ แกน y จะเปลี่ยนไปเรื่อยๆตามหัวข้อที่เราสนใจ

ยิ่งบาร์ 0,1 ความสูง ความต่ำ เส้นตรงกลางห่างกันมากยิ่งส่งผลต่อคำตอบ เช่น

อันแรก เพศ จะเห็นได้ว่าจะชายหรือหญิง ก็ชื้อรถของเราพอๆกัน ไม่ส่งผลอะไรมาก

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

แต่

มันยังมีทริคเล็กๆน้อยอีกว่า ข้อมูลชนิดนั้นๆถ้าคู่กับสิ่งอื่นอาจจะมีค่าขึ้นมา เช่นถ้าผมเอาเพศไปเช็คว่าคนที่ชื้อมีกี่คน จะเห็นได้ว่าชายกับหญิงห่างกัน 1 พันคน

ผมก็ยิ่งชั่งใจไปอีกเลยลองเอาเพศมาคู่กับเงินเดือน แล้วเช็คค่าเฉลี่ย ปรากฏว่าผู้เงินเดือนเยอะกว่า แต่ชื้อน้อยกว่า ยิ่งทำให้มั่นใจว่า ถ้าเป็นผู้ชายแล้วจะมีโอกาสที่จะชื้อรถจักรยานมากกว่าผู้หญิงแน่นอน !!

ทำให้เราเห็นได้ว่า

หัวข้อที่ส่งผลต่อเราได้แก่ เพศ,อาชีพ,สถานะคู่ครอง,จำนวนรถ,จำนวนเด็กที่มีในครอบครัวและรายได้ หากต้องการทำโฆษณาก็ควรจะเจาะกลุ่มให้ถูกจุด เช่น กลุ่มคนโสด หรือ กลุ่มที่มีรายได้ประมาณ 60k-125k ต่อปี เป็นต้น

ทีนี้เราก็รู้แล้วว่าจะเลือกอะไรบ้างโดยการตัดสินใจจากการดูกราฟที่เราพล็อตออกมาขั้นตอนถัดไปคือแปลงตัวอักษรให้กลายเป็นตัวเลขด้วย concat

data = pd.concat([data,pd.get_dummies(data[‘Occupation’], prefix=’Occupation’,
dummy_na=True)],axis=1).drop([‘Occupation’],axis=1)
data = pd.concat([data,pd.get_dummies(data[‘Gender’], prefix=’Gender’,
dummy_na=True)],axis=1).drop([‘Gender’],axis=1)
data = pd.concat([data,pd.get_dummies(data[‘MaritalStatus’], prefix=’MaritalStatus’,
dummy_na=True)],axis=1).drop([‘MaritalStatus’],axis=1)
data.head()
จะใช้ 1 hot แทนก็ได้
X=data[[‘Occupation_Clerical’,’Occupation_Management’,
‘Occupation_Manual’,’Occupation_Professional’,
‘Occupation_Skilled Manual’,’Occupation_nan’,
‘Gender_F’,’Gender_M’,
‘Gender_nan’,’MaritalStatus_M’,
‘MaritalStatus_S’,’MaritalStatus_nan’,’NumberCarsOwned’,’NumberChildrenAtHome’,’YearlyIncome’]]
y=data[‘BikeBuyer’]
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
X_train.shape
ลองเช็คดูก่อน train

ก่อนทำการเทรนให้เราลองทำการจูนโมเดลของเราก่อน

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import numpy as np
rfc=RandomForestClassifier(random_state=42)

โดยที่เราจะปรับค่าดังนี้

n_estimators = จำนวนต้นไม้ใน Random Forest,

max_features = วิธีการโหวต

max_depth = ความลึกของต้นไม้แต่ละต้น

criterion = วิธีการตัดสินใจของต้นไม้แต่ละต้น

(แปลไทยเป็นไทยในแต่ละอันโครตยาก 5555)

param_grid = { 
‘n_estimators’: [100,200,300,400,500,600],
‘max_features’: [‘auto’, ‘sqrt’, ‘log2’],
‘max_depth’ : [2,3,4,5,6,7,8,9,10],
‘criterion’ :[‘gini’, ‘entropy’]
}

จะได้ประมาณนี้

CV_rfc = GridSearchCV(estimator=rfc, param_grid=param_grid, cv= 5)
CV_rfc.fit(X_train, y_train)

จากนั้นเช็คค่าว่าอันไหนดีที่สุดโดยการ

CV_rfc.best_params_

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

rfc1=RandomForestClassifier(random_state=42, max_features=’auto’, n_estimators= 300, max_depth=7, criterion=’gini’)
rfc1.fit(X_train, y_train)

จากนั้นก็ลองเอามาทดสอบกับชุด test

pred=rfc1.predict(X_test)
print(“Accuracy for Random Forest on CV data: “,accuracy_score(y_test,pred))

จะได้ความแม่นยำประมาณ 78% ซึ่งถ้าเอาไปสอบ Cert คุณจะได้คะแนนมาประมาณ 19.4/20

แต่มีอีกหนึ่งเทคนิคหนึ่งที่เราก็สนใจแต่ยังไม่เคยพูดถึงเลยคือการจัดการพวก hyper parameter โดยใช้ randomsearchCV คล้ายๆ gridsearchCV แต่มาดูความต่างกัน

from sklearn.model_selection import RandomizedSearchCV
random_search = RandomizedSearchCV(estimator=rfc, param_distributions=param_grid, cv=5)
random_search.fit(X_train, y_train)
random_search.best_estimator_

ก็จะได้ว่า

ซึ่งไวกว่า gridSearch เพราะมันคือการ random ข้อมูลของเราโดยจะสุ่มข้อมูลและปรับไปเรื่อยๆ ช่วยลดในเรื่องของ Over fitting และช่วยประหยัดเวลาของเราอีกด้วย

ลองวัดความแม่นยำดู เพราะต่างกันแค่ n_estimators (300 กับ 200) และ max_features (sqrt กับ auto)

ต่างกันแค่ 0.0002 แต่ประหยัดเวลาไปโครตเยอะ

ถ้าใครต้องการเซฟเวลาก็อยากให้ลองหันไปใช้ randomsearchCV ดูเพราะประหยัดเวลามากกว่า แต่ถ้าใครมีเวลาเหลือๆ ต้องการความแม่นยำจริงๆก็ใช้ gridsearchCV ได้เลย

ทีนี้เราก็มีระบบทำนายและจัดกลุ่มลูกค้าแล้ว เราก็สามารถเอาลูกค้าในอนาคตมาตัดสินใจได้ หรือทำระบบ Real time ไปเลยโดยการให้พนักงานขายเดินไปหาลูกค้าแล้วลองถามข้อมูลเบื้องต้นเช่น รายได้ประจำปี / จำนวนเด็ก ฯลฯ แล้วก็ทำนายได้เลย

บทสรุปส่งท้าย

นี้ก็เป็นวิธีในการนำข้อมูลที่เรามีอยู่แล้วมาใช้ให้เกิดประโยชน์สูงสุด เช่น ทำโฆษณาร้านของเราโดยการมุ่งไปที่กลุ่มลูกค้าที่ชื้อกับเรามากที่สุด อย่างเช่น เพศชาย + โสด และนี้ก็เป็นบทความสุดท้ายก่อนที่จะเข้าสู่เรื่อง NLP แล้วก็จะเขียนบทความอันใหม่คือ Deep Learning เลย

3 layer หลักของ Neural Network

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

NLP(Natural Language Processing) ศาสตร์(ไม่)ใหม่ ศาสตร์แห่งเจได: แยกประเภทอีเมลล์ด้วยพลังฟอร์ซ

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