จากภาคทฤษฎี เราทราบขั้นตอนและวิธีคิดการทำ classification ด้วย maximum likelihood แล้ว [1] เป้าหมายคือการประมาณค่าความน่าจะเป็นด้วยสมการ
\[
\begin{align*}
P(y_i \mid \vec{x}_i ) &= P(y_i) \cdot P(x_i^1 \mid y_i) \cdot P(x^2_i \mid y_i) \cdot P(x^3_i \mid y_i) \cdots P(x^j_i \mid y_i) \tag{1.0} \\
\end{align*}
\]
เมื่อ \( \vec{x}_i = (x^1_i,x^2_i,x^3_i,...,x^j_i) \)
มาตอนนี้จะว่ากันถึงตัวอย่างการใช้งานกัน โดยจะใช้ในการแบ่งกลุ่ม Iris dataset
ในทางปฏิบัติข้อมูลที่ได้มาจากการวัดคุณลักษณะที่ปรากฎออกมาของสิ่งมีชีวิต ตามธรรมชาติมีลักษณะเป็นข้อมูลแบบต่อเนื่อง เป็นไปได้ว่าในข้อมูลธรรมชาติอาจไม่ปรากฏในตัวอย่างที่จัดเก็บมา เมื่อลองทำเอาข้อมูลมาทำ histogram ดูก็จะพบว่ามีลักษณะการแจกแจงที่พอจะอนุมานว่าเป็น normal distribution [2]
โดยค่าความน่าจะเป็นของแต่ละ features x_i จะหาได้จากสมการ
\[ p(x) = \frac{ e^{ \frac{-1}{2} \sqrt{\frac{x-\mu}{\sigma}} }} {\sigma\sqrt{2\pi}} \tag{1.1} \]
เมื่อ \( \mu \) ค่ากลาง (mean,mode, media) และ \( \sigma \) คือ standard deviation
จัดเตรียมข้อมูล
import numpy as np
import pandas as pd
from scipy.stats import norm
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
load dataset
#load data
iris_data = load_iris()
# preview
print(iris_data.data) # Names of the columns
print(iris_data.feature_names) # Target variable
print(iris_data.target) # Target names
print(iris_data.target_names) # name of target variable
create dataframe
# convert to pandas dataframe
iris_df = pd.DataFrame(iris_data.data,
columns=iris_data.feature_names)
# there would be smarter way, but this is easier
cls = {'class':[]}
for i in range(150):
if i < 50 :
cls['class'].append('setosa')
elif i < 100 :
cls['class'].append('versicolor')
else :
cls['class'].append('verginica')
iris_df['class'] = cls['class']
print(iris_df) # prints labeled data
shuffle data และ split data
# shuffle data
iris_df = iris_df.sample(frac=1).reset_index(drop=True)
t = int(0.8 * len(iris_df))
train_data = iris_df.loc[:t,:]
test_data = iris_df.loc[t:,:]
# preview
print(train_data)
describe data
หาค่า \( P(y) \) ของแต่ละ class
# group by class
iris_desc = train_data.groupby("class").describe()
#preview
print(iris_desc)
หาค่า \( P(y) \) ของแต่ละ class
# get sample count
N = iris_desc['sepal length (cm)']['count'].sum()
seto_n = iris_desc['sepal length (cm)']['count']['setosa']
vers_n = iris_desc['sepal length (cm)']['count']['versicolor']
verg_n = iris_desc['sepal length (cm)']['count']['verginica']
#get probability
prob_seto = seto_n/N # P(y1)
prob_vers = vers_n/N # P(y2)
prob_verg = verg_n/N # P(y3)
#preview
print(N,seto_n,vers_n,verg_n)
print(prob_seto,prob_verg,prob_vers)
มาถึงขั้นตอนนี้ เราก็มี parameters พื้นฐานครบในการที่จะเริ่มคำนวณตามสมการที่ (1.6) และ (1.7) แล้ว
ส่วนที่ 2 : ทดสอบด้วย test data
ขั้นตอนการทำงานคือ
1. ข้อมูลจะถูกดึงจาก dataset มาทีละรายการ แต่ละรายการประกอบค่าของ features ทั้ง 4 (\( x_1,x_2,x_3,x_4 \))
2. นำค่า \( x_1,x_2,x_3,x_4 \) ไปหาค่าความน่าจะเป็นด้วยสมการ (1.1) ด้วย parameter ที่ได้จากขั้นตอนแรก
3. หาค่าความน่าจะเป็น \(P(\hat{y}=setosa \mid \vec{x}),P(\hat{y}=versicolor \mid \vec{x}), P(\hat{y}=verginica \mid \vec{x})\) ตามสมการ (1.0)
4. นำค่าที่ได้จากข้อ 3 เปรียบเทียบกัน \( \hat{y} \) ใน class ใดที่ให้ค่าความน่าจะเป็นสูงสุดจะถือเอา class นั้นเป็นค่าพยากรณ์
# define probability density function as (1.1)
def norm_pdf(X,mu,sigma) :
nominator = np.exp( - (X - mu)**2 / (2 * sigma**2) )
denominator = (sigma * np.sqrt(2 * np.pi))
return nominator / denominator
feat_list = ['sepal length (cm)','sepal width (cm)','petal length (cm)','petal width (cm)']
correct = 0
history = []
N = len(test_data)
for i in range(N):
# get target class
label = test_data.iloc[i]['class']
# initial prob
probs = {'setosa':prob_seto,'versicolor':prob_vers,'verginica':prob_verg}
for c,py in probs.items():
p = py
for f in feat_list:
x = test_data.iloc[i][f]
mu = iris_desc[f]['mean'][c]
sigma = iris_desc[f]['std'][c]
p *= norm_pdf(x,mu,sigma)
probs[c] = p
y_hat = max(probs, key=probs.get)
if label == y_hat :
correct += 1
probs['label']=label
history.append(probs)
ค่าของ history
Item : 1 P(y='setosa')=0.000000 P(y='versicolor')=0.101163 P(y='verginica')=0.000002 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 2 P(y='setosa')=0.000000 P(y='versicolor')=0.000095 P(y='verginica')=0.052913 Predict : verginica, Label : verginica, Correct => True ----- Item : 3 P(y='setosa')=0.001799 P(y='versicolor')=0.000000 P(y='verginica')=0.000000 Predict : setosa, Label : setosa, Correct => True ----- Item : 4 P(y='setosa')=1.369032 P(y='versicolor')=0.000000 P(y='verginica')=0.000000 Predict : setosa, Label : setosa, Correct => True ----- Item : 5 P(y='setosa')=0.000000 P(y='versicolor')=0.006312 P(y='verginica')=0.062817 Predict : verginica, Label : verginica, Correct => True ----- Item : 6 P(y='setosa')=0.000000 P(y='versicolor')=0.364024 P(y='verginica')=0.000578 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 7 P(y='setosa')=0.000000 P(y='versicolor')=0.000099 P(y='verginica')=0.044583 Predict : verginica, Label : verginica, Correct => True ----- Item : 8 P(y='setosa')=0.079939 P(y='versicolor')=0.000000 P(y='verginica')=0.000000 Predict : setosa, Label : setosa, Correct => True ----- Item : 9 P(y='setosa')=0.000000 P(y='versicolor')=0.002316 P(y='verginica')=0.047282 Predict : verginica, Label : verginica, Correct => True ----- Item : 10 P(y='setosa')=0.068473 P(y='versicolor')=0.000000 P(y='verginica')=0.000000 Predict : setosa, Label : setosa, Correct => True ----- Item : 11 P(y='setosa')=0.000000 P(y='versicolor')=0.370740 P(y='verginica')=0.000135 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 12 P(y='setosa')=0.000000 P(y='versicolor')=0.000388 P(y='verginica')=0.000000 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 13 P(y='setosa')=0.000000 P(y='versicolor')=0.024761 P(y='verginica')=0.012653 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 14 P(y='setosa')=0.000000 P(y='versicolor')=0.168323 P(y='verginica')=0.002193 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 15 P(y='setosa')=0.000000 P(y='versicolor')=0.000001 P(y='verginica')=0.150882 Predict : verginica, Label : verginica, Correct => True ----- Item : 16 P(y='setosa')=0.000000 P(y='versicolor')=0.348247 P(y='verginica')=0.000188 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 17 P(y='setosa')=0.000000 P(y='versicolor')=0.054217 P(y='verginica')=0.000001 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 18 P(y='setosa')=0.000000 P(y='versicolor')=0.000001 P(y='verginica')=0.132567 Predict : verginica, Label : verginica, Correct => True ----- Item : 19 P(y='setosa')=0.000000 P(y='versicolor')=0.000000 P(y='verginica')=0.050565 Predict : verginica, Label : verginica, Correct => True ----- Item : 20 P(y='setosa')=0.000000 P(y='versicolor')=0.110623 P(y='verginica')=0.000024 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 21 P(y='setosa')=0.000000 P(y='versicolor')=0.105628 P(y='verginica')=0.000004 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 22 P(y='setosa')=0.000000 P(y='versicolor')=0.159142 P(y='verginica')=0.001874 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 23 P(y='setosa')=3.601586 P(y='versicolor')=0.000000 P(y='verginica')=0.000000 Predict : setosa, Label : setosa, Correct => True ----- Item : 24 P(y='setosa')=0.000000 P(y='versicolor')=0.248433 P(y='verginica')=0.003330 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 25 P(y='setosa')=0.000000 P(y='versicolor')=0.017088 P(y='verginica')=0.046130 Predict : verginica, Label : verginica, Correct => True ----- Item : 26 P(y='setosa')=0.000000 P(y='versicolor')=0.287213 P(y='verginica')=0.000667 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 27 P(y='setosa')=0.000000 P(y='versicolor')=0.120046 P(y='verginica')=0.001342 Predict : versicolor, Label : versicolor, Correct => True ----- Item : 28 P(y='setosa')=0.510845 P(y='versicolor')=0.000000 P(y='verginica')=0.000000 Predict : setosa, Label : setosa, Correct => True ----- Item : 29 P(y='setosa')=0.000000 P(y='versicolor')=0.000000 P(y='verginica')=0.112886 Predict : verginica, Label : verginica, Correct => True ----- Item : 30 P(y='setosa')=0.000000 P(y='versicolor')=0.000000 P(y='verginica')=0.168677 Predict : verginica, Label : verginica, Correct => True -----
ผลการทดสอบกับข้อมูลทดสอบจำนวน 30 รายการออกมาพยากรณ์ได้ถูกทุกรายการ น่าสนใจมากนะ
เอกสารอ้างอิง
[1] https://smarter-machine.blogspot.com/2020/11/probability-naive-bayes-classifier_20.html
ความคิดเห็น
แสดงความคิดเห็น