👥

ตอนที่ 2 : Features เต็มไปหมด

จากตอนที่แล้วที่แล้วผู้เขียนได้กล่าวถึง Linear Regression (Univariate) โดยมีเพียง feature (xx) เดียวโดยมี model เป็น f(x)=wx+bf(x) = wx+b ในตอนนี้เราจะกล่าวถึงกรณีที่มีหลาย features กัน

แล้วถ้าต้องใช้หลาย features ตัว Linear Regression model จะมีหน้าตาเป็นยังไงล่ะ?

Linear Regression Model (with variate)

fw,b(x)=w1x1+w2x2+...+wnxn+bf_{w,b}(x) = w_1x_1+w_2x_2+...+w_nx_n+b

หรือ

fw,b=j=1nwjxj+b\begin{equation} f_{w,b} = \sum _{j=1} ^n w_jx_j+b \end{equation}

แค่นี้?

ใช่แค่นี้จริงๆ

เราสามารถเขียนให้อยู่ในรูปแบบของ vector (Vectorization)ได้ดังนี้

w=[w1,w2,w3,...,wn]x=[x1,x2,x3,...,xn]\begin{aligned} \vec {w} &= [w_1,w_2,w_3,...,w_n]\\ \vec {x} &= [x_1,x_2,x_3,...,x_n] \end{aligned}
fw,b=wx+b\begin{equation} f_{\vec{w},b} = \vec{w}\cdot\vec{x} + b\\ \end{equation}

ในการ implement code การ implement โดยใช้ฟังก์ชัน dot product ของ NumPy จะใช้เวลาน้อยกว่าเนื่องจาก NumPy ได้ implement dot product ให้มีการคำนวณแบบขนาน

💡
Playground ข้างล่างเป็นตัวอย่างcodeที่เปรียบเทียบการใช้เวลาในการทำ dot product ที่เรา implement เองกับ method ของ NumPy
import numpy as np
import time

def loop_dot(a, b): 
	"""
	implement ตามสมการที่ 1
	  a :  input vector 
	  b :  input vector ที่มี dimension เท่า a
	
	Returns:
	  x : ผลลัพธ์สุดท้าย    
	"""
	x=0
	for i in range(a.shape[0]):
	    x = x + a[i] * b[i]
	return x

# สร้าง narray แบบสุ่มขนาด 10000000 ตัว
np.random.seed(1)
a = np.random.rand(10000000) 
b = np.random.rand(10000000)

start = time.time()
c = np.dot(a, b)
end = time.time()

print(f"np.dot(a, b) =  {c:.4f}")
print(f"Vectorized version duration: {1000*(start-end):.4f} ms ")

start = time.time()
c = loop_dot(a,b)
end = time.time()

print(f"loop_dot(a, b) =  {c:.4f}")
print(f"loop version duration: {1000*(start-end):.4f} ms ")

เราได้เห็นถึงประโยชน์ของการทำ Vectorization ไปแล้วนอกจากจะทำให้การคำนวณเร็วขึ้นแล้วผู้เขียนเองยังมองว่าเมื่อเขียนเป็นสมการในรูปแบบของ vector แล้วทำให้อ่านได้สบายตากว่าด้วย(?) ต่อไปเรามาเปลี่ยนสมการที่อยู่ในตอนที่ 1 ให้อยู๋ในรูปแบบ vectorized กัน

ก่อน VectorizeVectorized
Parametersw1,,wnbw_1,…,w_n \\ bw=[w1,,wn]b\vec {w} = [w_1,…,w_n] \\ b
Model (Linear)fw,b(x)=w1x1+...+wnxn+bf_{w,b}(x) = w_1x_1+...+w_nx_n+bfw,b(x)=wx+bf_{\vec{w},b} (\vec x) = \vec{w}\cdot\vec{x} + b
Cost functionJ(w1,,wn,b)J(w_1,…,w_n,b)J(w,b)J(\vec w,b)
Gradient DescentRepeat{wnew=woldαwJ(w1,,wn,b)bnew=boldαbJ(w1,,wn,b)}Repeat\{\\ w_{new} = w_{old}-\alpha \frac{\partial}{\partial w}J(w_1,…,w_n,b) \\ b_{new} = b_{old}-\alpha \frac{\partial}{\partial b}J(w_1,…,w_n,b)\\\}  Repeat{wnewj=woldjαwJ(w,b)bnew=boldαbJ(w,b)}Repeat\{\\ w_{new_j} = w_{old_j}-\alpha \frac{\partial}{\partial w}J(\vec w,b) \\ b_{new} = b_{old}-\alpha \frac{\partial}{\partial b}J(\vec w,b)\\\}

ขอลงลายละเอียดในส่วน loop ของ Gradient Descent สักหน่อย

Repeatuntilconvergence{wjnew=wjoldαwJ(w,b)bnew=boldαbJ(w,b)}\begin{aligned} &Repeat\,until\,convergence\{\\ &w_{j_{new}} = w_{j_{old}}-\alpha \frac{\partial}{\partial w}J(\vec w,b) \\ &b_{new} = b_{old}-\alpha \frac{\partial}{\partial b}J(\vec w,b)\\ &\} \end{aligned}

จากที่เราทำ Partial Derivative Cost function ไปในตอนที่ 1 จะสามารถเขียนให้อยู่ในรูปแบบนี้

Repeatuntilconvergence{wjnew=wjoldα1mi=1m(fw,b(x(i))y(i))x1(i)bnew=boldα1mi=1m(wx(i)+by(i))}\begin{aligned} &Repeat\,until\,convergence\{\\ &w_{j_{new}} = w_{j_{old}}-\alpha\frac{1}{m}\sum_{i=1}^m(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})x_1^{(i)}\\ &b_{new} = b_{old}-\alpha\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})\\ &\} \end{aligned}

wjw_j หมายถึง weight ตัวที่ j ถ้าเกิดว่าชุดข้อมูลมี n features weight ก็จะมี n ตัวด้วย ดังนั้นจะสามารถเขียน Gradient Descent ใหม่ได้เป็น

Repeatuntilconvergence{w1new=w1oldα1mi=1m(fw,b(x(i))y(i))x1(i)...wnnew=wnoldα1mi=1m(fw,b(x(i))y(i))xn(i)bnew=boldα1mi=1m(wx(i)+by(i))}\begin{aligned} &Repeat\,until\,convergence\{\\ &w_{1_{new}} = w_{1_{old}}-\alpha\frac{1}{m}\sum_{i=1}^m(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})x_1^{(i)}\\ .\\.\\.\\ &w_{n_{new}} = w_{n_{old}}-\alpha\frac{1}{m}\sum_{i=1}^m(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})x_n^{(i)}\\ &b_{new} = b_{old}-\alpha\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})\\ &\} \end{aligned}
💡
ทางเลือกอื่นสำหรับ Gradient Descent Normal Equation

ข้อดี

  • ใช้สำหรับ Linear Equation เท่านั้น
  • สามารถหาค่า w, b ได้โดยไม่ต้องมีการทำซ้ำ

ข้อเสีย

  • ไม่ได้ครอบคลุม Learning Algorithm อื่นๆ
  • ถ้า features มีจำนวนมากจะช้า

ใน Library ที่มีการ implement Linear Regression อาจจะมีการใช้วิธีการนี้ใน back-end

มาพูดถึง Feature ที่เป็นตัวเอกของตอนนี้กันดีกว่า

ในกรณีที่มีหลาย features และแต่ละ feature ก็จะมีลักษณะที่แตกต่างกันออกไป เช่น ช่วงของค่าแต่ละ feature อาจมีช่วงที่กว้าง หรือ แคบก็ได้ ฯลฯ และเมื่อนำไปใส่ใน Gradient Descent การก้าวแต่ละก้าวอาจทำให้เกิดผลกระทบที่ใหญ่มากกับ feature บางตัวได้ ตอนนี้อาจจะยังงงๆ เราจะค่อยๆไปกัน

ตัวอย่างการทำนายราคาบ้าน

กำหนดให้

Regression model :

ขนาด (ฟุต2^2) : ช่วง [300-2000]

จำนวนห้องนอน : ช่วง [0-5]

price^=w1x1+w2x2+b\hat {price} = w_1x_1+w_2x_2+b 

x1x_1

x2x_2

บ้านขนาด 2000 ตารางฟุต มีห้องนอน 5 ห้อง ราคา 500k

กรณี 1

ถ้าเรากำหนดให้ w1=50,w2=0.1,b=50w_1 = 50,w_2 = 0.1, b = 50

price^=(50)(2000)+(0.1)(5)+50price^=100,050.5k\begin{aligned} \hat {price} &= (50)(2000) + (0.1)(5) + 50 \\ \hat {price} &= 100,050.5k \end{aligned}

กรณี 2

ถ้าเรากำหนดให้ w1=0.1,w2=50,b=50w_1 = 0.1,w_2 = 50, b = 50

price^=(0.1)(2000)+(50)(5)+50price^=500k\begin{aligned} \hat {price} &= (0.1)(2000) + (50)(5) + 50 \\ \hat {price} &= 500k\end{aligned}

ในกรณีที่ 2 ราคาบ้านที่ได้ออกมามีความสมเหตุสมผลมากว่ากรณีที่ 1 จากทั้ง 2 กรณีจะสังเกตได้ว่าถ้าหากช่วง(range)ของ feature มีขนาดกว้างจะส่งผลดีกว่าถ้าเลือก weight ที่มีขนาดเล็ก และถ้ามีขนาดแคบจะส่งผลดีกว่าถ้าเลือก weight ที่มีขนาดใหญ่

แล้วมันเกี่ยวอะไรกับ Gradient Descent ล่ะ?

ตารางแสดงการเปรียบเทียบระหว่างขนาดของ Features และ Parameters

ขนาดของ feature xjx_jขนาดของ parameter wjw_j
ขนาดบ้าน (ตร.ฟุต)←—————→←—→
จำนวนห้องนอน←—→←—————→
รูปซ้ายมือคือ scatter plot ของชุดข้อมูล รูปขวามือคือ กราฟ cost function ระหว่าง w1,w2w1,w2 ที่พลอตแบบ contour map

สังเกตดูว่า Contour plot จะมีรูปร่างที่ผอม เมื่อเรานำไปใส่ Gradient Descent อาจใช้เวลานานในการหาจุดต่ำสุด(เส้นสีฟ้้า) ดังรูปข้างล่าง

สามารถแก้ไขปัญหาข้างต้นได้โดยการทำ rescale

จากรูปเป็นการ rescaled x1,x2x_1,x_2 ให้อยู่ในช่วง [0,1] แล้วจะทำให้ได้ กราฟ Cost Function ดั่งรูปขวาแล้วเมื่อนำไปใส่ใน Gradient Descent ก็จะใช้เวลาน้อยลง

วิธีที่กล่าวไปข้างต้นเรียกว่า Feature Engineering แบบ Feature Scaling

Feature Scaling

วิธีการทำคือ หารค่าทั้งหมดของแต่ละ Feature ด้วยค่ามากสุดเช่น

300x12000x1,scaled=x120000.15x1,scaled1300 \leq x_1 \leq 2000 \\ x_{1,scaled} = \frac {x_1}{2000}\\ 0.15 \leq x_{1,scaled} \leq 1
0x25x2,scaled=x250x2,scaled10 \leq x_2 \leq 5 \\ x_{2,scaled} = \frac {x_2}{5}\\ 0 \leq x_{2,scaled} \leq 1

Mean Normalization

วิธีการทำคือ นำแต่ละค่าใน Feature มาลบด้วยค่าเฉลี่ยของ Feature และ หารด้วยค่า max - min ของ Feature

300x12000x1,scaled=x1μ120003000.18x1,scaled0.822300 \leq x_1 \leq 2000 \\ x_{1,scaled} = \frac {x_1 - \mu_{1}}{2000-300}\\ -0.18 \leq x_{1,scaled} \leq 0.822
0x25x2,scaled=x2μ2500.46x2,scaled0.540 \leq x_2 \leq 5 \\ x_{2,scaled} = \frac {x_2-\mu_2}{5-0}\\ -0.46 \leq x_{2,scaled} \leq 0.54

Z-score Normalization

วิธีการทำคือ นำแต่ละค่าใน Feature มาลบด้วยค่าเฉลี่ยของ Feature และ หารด้วยค่า SD ของ Feature

300x12000x1,scaled=x1μ1σ10.67x1,scaled0.31300 \leq x_1 \leq 2000 \\ x_{1,scaled} = \frac {x_1 - \mu_{1}}{\sigma_1}\\ -0.67 \leq x_{1,scaled} \leq 0.31
0x25x2,scaled=x2μ2σ21.6x2,scaled1.90 \leq x_2 \leq 5 \\ x_{2,scaled} = \frac {x_2-\mu_2}{\sigma_2}\\ -1.6\leq x_{2,scaled} \leq 1.9

แล้วเราต้องทำ Feature Scaling ตอนไหนบ้างล่ะ?

ควรใช้ตอนที่ช่วง(range)ของ feature นั้นๆมีความกว้างเกินไปหรือแคบเกินไป ตัวอย่างเช่น

100x100-100 ≤ x ≤ 100

แต่ถ้าช่วง(range)อยู่ในช่วงที่ยอมรับได้ไม่จำเป็นต้องทำ เช่น

1x13x30.3x0.30x32x0.5\begin{aligned} -1&≤x≤1\\ -3&≤x≤3\\ -0.3&≤x≤0.3\\ 0&≤x≤3\\ -2&≤x≤0.5\\ \end{aligned}

Feature Engineering

ในบางครั้ง(จริงๆก็เกือบทุกครั้งนะ)การเลือก feature จะส่งผลกับความสามารถในการทำนายของ model ทั้งในทางที่ดีและไม่ดีและในบางครั้งเราก็ต้องมีการเล่นท่ายากกับ feature ที่มีอยู่เพื่อให้ได้มาซึ่ง feature ใหม่

เช่น การทำนายราคาบ้านโดยข้อมูลที่มีคือ

width:x1height:x2\begin{aligned} width &: x_1\\ height &: x_2\\ \end{aligned}

จะได้ Model เป็น

f(x)=w1x1+w2x2+bf(x) = w_1x_1 + w_2x_2 +b

ด้วย feature เท่านี้อาจจะสามารถทำให้ Model สามารถทำนายราคาบ้านได้ดีในระดับนึงแล้วแต่เราสามารถทำให้มัน(อาจจะ)ดีขึ้นได้โดยการทำ Feature Engineering

จาก feature ที่มีอยู่ตอนนี้เราสามารถสร้้าง feature ใหม่ได้อีกตัวนั่นคือ

area(width×height):x3area (width \times height): x_3

และเราจะได้ Model ใหม่คือ

f(x)=w1x1+w2x2+w3x3+bf(x) = w_1x_1 + w_2x_2+w_3x_3 +b
💡
การจะทำ Feature Engineering ได้จะต้องมีความรู้ความเข้าใจในชุดข้อมูลนั้นๆ

จาก Feature Engineering ที่กล่าวไปข้างต้นในบางครั้งอาจจะทำให้ Model ของเราจากที่เป็น Linear Regression กลายเป็น

Polynomial Regression

ในบางที่ข้อมูลของเราจะเมื่อนำไปทำ scatter plot แล้วจะมีแน้วโน้มที่ไม่ได้เป็น Linear การนำ Polynomial Regression มาใช้จะทำให้ Model เราสามารถ fit กับข้อมูลได้มากกว่า

ตัวอย่าง scatter plot ของข้อมูลที่ไม่ได้มีแนวโน้มเป็นแบบ Linear

ตัวอย่างเช่น ขนาดของบ้าน และ ราคาบ้าน สมมติว่าบ้านเป็นลูกบากศ์

ถ้าเราใช้ Model เป็น Linear Regression โดย ใช้แค่ความกว้าง

width:x1\begin{aligned} width &: x_1\\ \end{aligned}

Model ของเราจะเป็น

f(x)=wx+bf(x) = wx +b

แต่ถ้าเราเพิ่ม พื้นที่ และ ปริมาตรเข้าไปด้วยจะทำให้ Model ของเรากลายเป็น Polynomial Regression จะได้ Model ใหม่เป็น

f(x)=w1x+w2x2+w3x3+bf(x) = w_1x + w_2x^2+w_3x^3 +b

ซึ่ง(อาจ)จะสามารถ fit กับข้อมูลได้มากกว่าแบบแรก

Coming Soon …