AI學習筆記 — 機器學習演算法:線性迴歸-1

Sean Yeh
Python Everywhere -from Beginner to Advanced
14 min readJan 13, 2023

--

Gotemba City, Japan, photo by Sean Yeh

簡單來說,AI人工智慧就是一連串電腦程式碼的組合,讓電腦可以像人一樣思考理解並且做出決策解決特定問題。例如可以讓電腦識別圖片中的東西,或者協助醫生診斷疾病。

為什麼這些程式碼可以達到這樣的成果?因為它們會藉由對大量數據的學習,形成一個演算法的模型,透過這個模型進行決策判斷,以下要討論的「線性迴歸」即是機器學習演算法模型的一種。

線性迴歸簡介

線性迴歸(Linear Regression)是一種機器學習的模型,可以用來預測兩個連續變量之間的關係。這些變量可能是溫度與銷售量之間的關係,也可能是年收入與房屋價格的關係等等。

在分析的時候,我們會先搜集變量的各種數據,透過對這些數據的分析,可以找到一條能夠用來描述這兩個變量之間關係的最佳「直線」。這條直線就是「線性迴歸」。藉由這條直線可以幫助我們預測變量未來的值,非常有用。

賣屋的例子

photo generated by Midjourney

若以賣屋為例來說明線性迴歸。首先我們假設你想要出售自己的房子,然而正在為到底該開價多少而煩惱時,恰巧發現住家附近的兩位鄰居也在去年把他們的房子給賣了。當然,鄰居的這兩棟房子與你住的房子還是有點不同的。於是你經過努力轉輾得到鄰居兩棟房子的大小與售價資訊,內容大致如下:

從上面的資訊看,你的房子(1,80 平方米)大小介於A屋與B屋兩者之間。基於上述鄰居賣屋的資訊,你會將房子的賣價訂為多少?

實際上,決定賣價最簡單的方式就是先將A屋與B屋兩者的資訊標在座標圖上。座標圖的橫軸(x)為房屋大小,而縱軸(y)為售價。

然後,再將A屋與B屋位於圖上的兩個座標點,連成一條直線,並求出該直線的一次線性方程式。

Y = Bx+a

以本例子來說,這條直線的一次方程式為:

Y = 250000x+7500000

如果依照這個一次方程式來預估你的房子出價,答案應該是$52,500,000元(250000 * 180 + 7500000)。然而,你是否會懷疑單靠這兩個點的資料,就決定自己的房子該出價多少錢,是否過於草率?或許你的鄰居去年因為急需現金而降價拋售該不動產呢!

於是,你開始向各方打聽消息,從房仲業者以及地政機構取得了多筆資料,並將這些資料依照前面的方式描繪入圖中。

當圖形描繪完畢後,我們可以看到這些資料點產生的圖並不是一個很完美的線性關係。有的點靠得很近、有些又離得很遠。於是,我們就開始思考下面的問題:「是否有一條線,可以用來代表房屋價格與房子大小之間關係的變化趨勢?」也就是「是否有一條線性方程式,可以用來表達上面這些資料點的關係?」

就像是下面圖片中繪出的那條紅線,雖然並不是所有的點都在這條線上,但是這條線已經包含了「夠多」的點了。

為了得到上面那條紅線所代表的方程式,我們可以從已知的資料中求出這條線的斜率(slop)與截距(y-intercept)。

換句話說,我們要透過向房仲業者以及地政機構取得多筆資料(上圖中的藍點),求出這條線的斜率(slop)與截距(y-intercept),進而得到「最適合」代表這些資料的方程式 Y = Bx+a。

也就是找出一條直線(紅線),讓該直線與大部分資料點間距離是最短的。也就是找到「最擬合資料點」。

「最擬合資料點」,也就是直線與資料的誤差總和最小的地方。要計算出誤差值,若採用直接相加的方式處理的話,會因為誤差之間的正負值相互抵銷而無法取得。因此,在這裏會以誤差的平方和作為損失函式(Cost function),最小化誤差平方和的方法亦稱作最小平方法。

我們透過上述的誤差最小化程序,來判斷什麼是最佳的模型。並透過損失函式,來求得答案。因此,該函式會將預測值與理想值之間的差額取平方值,以此作為誤差,然後利用最小平方法,找出能夠讓模型誤差最小化的係數。

經過一連串的數學計算,(在此不做說明與推導…)即可求得方程式Y = Bx+a 最佳的B與a。若要透過python來求取B與a,則可以使用下面程式碼:

import numpy as np

def get_B(x,y):
# 分子
numerator = np.sum(np.multiply(x,y)-(np.mean(y)*x))
# 分母
denominator = np.sum((x**2) - (np.mean(x)*x))
return numerator/denominator

def get_a(x,y):
return np.mean(y) - get_b(x,y)*np.mean(x)

以上程式碼透過Numpy的array來實現,在使用時需要匯入numpy套件。將前面的例子帶入方程式,一樣可以得到y = 250000.0x + 7500000.0的結果

x =np.array([150,250])
y= np.array([45000000,70000000])
B = get_B(x,y)
a = get_a(x,y)
print(f"y = {B}x + {a}")

簡單線性迴歸實作:股價預測

photo generated by Midjourney

為了說明線性迴歸模型,以下假設對股價進行模型預測。並且虛擬了一組股價的data set。當然現實生活中應該不會有這麼簡單的預測模型。主要是為了說明整個機器學習的訓練過程。

匯入套件

首先匯入套件。我們會使用到sklearn中linear_model裡面的LinearRegression與train_test_split等。以及Pandas、NumPy套件來處理資料。最後,還需要匯入Matplotlib來進行後續的資料視覺化。

# 套件匯入
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

讀入資料檔案

匯入套件之後,就可以讀入要訓練的資料檔案,在這個例子中我們使用的是外部檔,csv檔案。需要透過pandas來讀取檔案的內容

df = pd.read_csv('Stock+and+day.csv')
df.head(5)

使用head(5)可以呈現出資料前五行的樣子。

head(5)

定義x,y

匯入套件並且讀入csv資料檔後,我們就需要定義這些資料哪個欄位是輸入值(x)?哪個欄位是輸出值(y)?

由於我們想要預測的是股票的價格,因此Price欄位及是輸出值(y)。反之,Day就是輸入值(x)。將x,y定義完畢之後,我們可以先透過matplotlib來將讀入的資料繪製成二維的圖形。在進行繪圖前,先確定是否已經匯入matplotlib套件(import matplotlib.pyplot as plt)。

我們使用plt.scatter並將x與y值帶入,來繪製散布圖 (Scatter Chart)。matplotlib繪圖的詳細方式可以參考先前撰寫的這一篇文章

# x = Day
# Y = Price
# 繪製成2D圖表
plt.title("Day and Stock Price")
plt.xlabel("Day")
plt.ylabel("Stock Price")
plt.scatter(df.Day,df.Price, color="red", marker="+")
plt.show()

執行上面的程式碼,即可以繪製出下面的圖形。可以看到x與y之前大致上呈現的是線性關係。

分割數據

在前面的步驟已經確定了x與y分別代表的欄位。接下來要將這兩個欄位指定給x與y變數。在這裏要注意的點是,我們需要將輸入的資料x以二維(2D array)的方式表示。因此,程式碼要寫成下面的樣子:

# 分割數據
x = df.iloc[:,:-1].values
y = df.iloc[:,1].values

放入x後的資料呈現如下,是個2D array:

接著,我們要將讀入的資料分成兩個部分,一部分拿來進行模型的訓練,另一部分拿來測試驗證。也就是要將全部的資料分割為訓練資料與測試資料。分割訓練集資料與測試集資料的比例,在這裏使用70%的訓練資料,與30%的測試資料,因此在test_size參數的地方要輸入0.3(test_size=0.3)。

sklearn.model_selection中的train_test_split可以將資料分割成訓練集(x_train 與 y_train)與測試集(x_test與y_test)(在進行資料分割前,請先確定是否已經匯入sklearn套件from sklearn.model_selection import train_test_split

# 將資料分割成訓練集與測試集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3,random_state=1)

定義模型

接下來要定義機器學習的模型,在此我們會使用線性迴歸模型。因此我們將模型定義如下:

# 定義模型
model = LinearRegression()

在定義模型前須確認是否已經匯入sklearn相關套件(from sklearn.linear_model import LinearRegression

訓練模型

定義完模型,就可以使用LinearRegression()函式中的fit()方法來訓練模型。fit()有兩個參數:訓練資料的輸入特徵x,以及這些輸入資料的理想輸出y,藉此找出最適合的一條線。訓練出來的結果會指定給變數model。

# 訓練模型
model.fit(x_train,y_train)

預測股價

訓練完畢之後,就可以預測結果,在此使用model.predict()來進行預測。

例如,若要預測第23天的股價是多少的話,可以使用model.predict([[23])來進行預測。

# 使用模型預測
model.predict([[23]])

繪出線條

到此為止,我們已經可以將訓練好的模型拿來進行預測了。大家是否會好奇,這一條線到底長什麼樣子?我們可以再次透過matplotlib來將這條預測的線畫出來。在進行繪圖前,先確定是否已經匯入matplotlib相關套件(import matplotlib.pyplot as plt)。

我們用下面的程式碼將測試的資料(x_train, y_train)與線條畫出來。

# 將預測的線y與實際值畫出來
plt.title("Day and Stock Price(Training Set)")
plt.xlabel("Day")
plt.ylabel("Stock Price")
plt.scatter(x_train,y_train,color="red",marker="+")
plt.plot(x_train,model.predict(x_train),color="blue")

結果如下:

驗證

透過下面方式我們就可以求出曲線的線性方程式。如果方程式為y= Bx+a的話,B為 model.coef_,而a為model.intercept_

# y= Bx+a
# B
B = model.coef_
# a
a = model.intercept_

我們也可以將測試資料的值(x_test,y_test),與我們預測的線畫在一張圖,來看看它們之間的關係。

# 將測試的線y與實際值畫出來
plt.title("Day and Stock Price(Testing Set)")
plt.xlabel("Day")
plt.ylabel("Stock Price")
plt.scatter(x_test,y_test,color="red",marker="+")
plt.plot(x_test,model.predict(x_test),color="blue")

結果,測試資料的值,幾乎都跟我們模型預測的線具備相關性。

全部程式碼

全部的程式碼如下:

# 套件匯入
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

# 讀入資料檔
df = pd.read_csv('Stock+and+day.csv')
df.head(5)

# 定義x,y
# x = Day
# Y = Price
# 繪製成2D圖表
plt.title("Day and Stock Price")
plt.xlabel("Day")
plt.ylabel("Stock Price")
plt.scatter(df.Day,df.Price, color="red", marker="+")
plt.show()

# 分割數據
x = df.iloc[:,:-1].values
y = df.iloc[:,1].values

# 將資料分割成訓練集與測試集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3,random_state=1)


# 定義模型
model = LinearRegression()

# 訓練模型
model.fit(x_train,y_train)

# 使用模型預測
model.predict([[23]])

# 將預測的線y與實際值畫出來
plt.title("Day and Stock Price(Training Set)")
plt.xlabel("Day")
plt.ylabel("Stock Price")
plt.scatter(x_train,y_train,color="red",marker="+")
plt.plot(x_train,model.predict(x_train),color="blue")

# 驗證
# y= Bx+a
B = model.coef_
a = model.intercept_

# 將測試的線y與實際值畫出來
plt.title("Day and Stock Price(Testing Set)")
plt.xlabel("Day")
plt.ylabel("Stock Price")
plt.scatter(x_test,y_test,color="red",marker="+")
plt.plot(x_test,model.predict(x_test),color="blue")

結論

綜上所述,簡單線性迴歸是以直線來表達原因與結果的關係,一個原因,對應一個結果。我們會假定輸入值(x)與輸出值(y)之間呈現線性的關係。而迴歸的目標是要把誤差變小。

迴歸模型的訓練學習中,通常會將資料分成訓練集(training set)與測試集(testing set),而一般來說訓練資料會比測試資料多。

此外,若要讓線性迴歸模型運作順利的話,就需要有足夠的資料。若因資料不足,導致資料點太少,而畫出來的線圖,就不具有代表性。

以上是簡單線性迴歸的說明,線性迴歸中還有其他的迴歸模型,包括嶺迴歸、套索迴歸、邏輯迴歸等,之後有機會再撰文說明。

--

--

Sean Yeh
Python Everywhere -from Beginner to Advanced

# Taipei, Internet Digital Advertising,透過寫作讓我們回想過去、理解現在並思考未來。並樂於分享,這才是最大贏家。