【火爐煉AI】機器學習003-簡單線性迴歸器的創建,測試,模型保存和加載

【火爐煉AI】機器學習003-簡單線性迴歸器的創建,測試,模型保存和加載

【本文所使用的Python庫和版本號】: Python 3.5, Numpy 1.14, scikit-learn 0.19

 

迴歸分析是一種基於現有數據集,從現有數據集中尋找數據規律的一種建模技術,主要研究的是因變量(輸出y,或標記,或目標,它的別名比較多)和自變量(輸入x,或特徵,或預測器)之間的關係。通常用於預測分析,從現有數據集中找到數據規律,用該數據規律來預測未來的,或新輸入的自變量,從而計算出因變量的過程。

 

簡單線性迴歸是最基本,最簡單的一種迴歸分析模型,也是最被人熟知,最被人首選的迴歸模型。簡單線性迴歸模型的因變量y是連續的,自變量X可以是連續的也可以是離散的,其基本假設是因變量與自變量之間成直線的變化關係,可以通過一條簡單的擬合直線(y=ax+b)來表示兩者之間的關係。所以線性迴歸模型的訓練目標就是獲取這兩直線的斜率a和截距b。如下圖所示爲簡單的線性迴歸器的模型得到的線性圖。

  1. 使用簡單線性迴歸器擬合得到的直線圖

 

剩下的問題就是,怎麼從數據集中得迴歸直線y=ax+b中的a和b,答案是最小二乘法。最小二乘法是擬合直線最常用的方法,其本質是通過最小化每個數據點到直線的垂直偏差的平方和來計算最佳擬合直線。最小二乘法的計算公式爲:

  1. 最小二乘法計算公式

 

下面使用線性迴歸來擬合數據集,得到線性方程。

 

1. 準備數據集

對於機器學習而言,第一部分往往是準備數據集。一般的,數據集是存放在txt,或csv,或excel,或圖片文件中,但此處我們沒有這些數據集,故而我自己用隨機數生成x,y組成數據集。如下代碼:

# ***************使用隨機數據來構建簡單線性迴歸器**********************************  
import numpy as np  
import matplotlib.pyplot as plt  
# %matplotlib inline  
np.random.seed(37) # 使得每次運行得到的隨機數都一樣  
  
# 第一部分:準備數據集  
# 一般的,數據集可以放置在一個專門的txt,或csv文件中,此處我自己創造一些數據  
x=np.arange(10,110)   
x_shift=np.random.normal(size=x.shape)  
x=x+x_shift # 構建的x含有100個數,通過在整數點引入偏差得到  
print('x first 5: {},\nx last 5: {}'.format(x[:5],x[-5:]))  
  
error=np.random.normal(size=x.shape)*15 # 構建誤差作爲噪音,*15是擴大噪音的影響  
y=1.8*x+5.9+error  
# plt.scatter(x,y) # 可以查看生成的數據集的分佈情況  
  
# 要從這100個隨機選擇80個點來train,剩下的20個點來test  
# 最簡單的方法是調用下面的train_test_split函數  
dataset=[(i,j) for i,j in zip(x,y)]  
from sklearn.model_selection import train_test_split  
train_set,test_set=train_test_split(dataset,test_size=0.2,random_state=37)  
print('train set first 3: {}, last 3: {}'.format(train_set[:3],train_set[-3:]))  
print('test set first 3: {}, last 3: {}'.format(test_set[:3],test_set[-3:]))  
  
# 第二種方法:也可以自己先shuffle,再隨機選取  
# np.random.shuffle(dataset) # 亂序排列  
# train_set,test_set=dataset[:80],dataset[80:]   
# print('train set first 3: {}, last 3: {}'.format(train_set[:3],train_set[-3:]))  
# print('test set first 3: {}, last 3: {}'.format(test_set[:3],test_set[-3:]))  
  
X_train=np.array([i for (i,j) in train_set]).reshape(-1,1) # 後面的fit需要先reshape  
y_train=np.array([j for (i,j) in train_set]).reshape(-1,1)  
X_test= np.array([i for (i,j) in test_set]).reshape(-1,1)  
y_test= np.array([j for (i,j) in test_set]).reshape(-1,1)  
print('X_train first 3: {}'.format(X_train[:3]))  
print('y_train first 3: {}'.format(y_train[:3]))  

 

x first 5: [ 9.94553639 11.67430807 12.34664703 11.69965383 15.51851188],

x last 5: [104.96860647 105.5657788  107.39973957 109.13188006 107.11399729]

train set first 3: [(87.14423520405674, 167.36573263695115), (55.67781082162659, 99.22823777086437), (66.59394694856373, 132.76688712312875)], last 3: [(101.17645506359409, 192.5625947080063), (84.26081861492051, 140.24466883845), (25.045565547096164, 30.8008361424697)]

test set first 3: [(70.59406981304555, 119.31318224915739), (57.91939805734182, 92.13834259220599), (96.47990086803438, 179.5012882066724)], last 3: [(102.0058216600241, 201.04210881463908), (18.172421360793678, 47.04372291312748), (104.96860647152728, 222.13041948920244)]

X_train first 3: [[87.1442352 ]

 [55.67781082]

 [66.59394695]]

y_train first 3: [[167.36573264]

 [ 99.22823777]

 [132.76688712]]

  1. 隨機生成的原始數據集,共有100個數據點。

小結:

1,數據集的準備通常需要對數據進行處理,比如,異常點,缺失值的處理等。

2,從數據集中劃分一部分作爲train set,一部分作爲test set是很有必要的,也是機器學習中經常做的一部分工作,可以採用sklearn的train_test_split函數來實現,簡單有效。也可以自己寫函數先shuffle,再取一部分數據。

3,爲了配合後面的線性迴歸器進行fit,需要對向量數據進行reshape,轉變爲M行N列的形式(此處只有一個特徵向量,即X,故而N=1)

 

2. 構建,訓練線性迴歸器模型

使用sklearn可以非常簡單的創建和訓練迴歸器模型,只需一兩行代碼就搞定,如下代碼:

# 第二部分:使用train set進行模型訓練  
from sklearn import linear_model  
  
linear_regressor=linear_model.LinearRegression() # 創建線性迴歸器對象  
linear_regressor.fit(X_train,y_train) # 使用訓練數據集訓練該回歸器對象  
  
# 查看擬合結果  
y_predict=linear_regressor.predict(X_train) # 使用訓練後的迴歸器對象來擬合訓練數據  
plt.figure()  
plt.scatter(X_train,y_train)  
plt.plot(X_train,y_predict,'-b',linewidth=3)  

 

  1. 使用線性迴歸模型擬合訓練集得到的直線

通過上圖,可以看出該線性迴歸模型貌似能夠很好地擬合這些數據點,但是這是將模型用於預測訓練集得到的結果,如果用該模型預測它從來沒見過的測試集,會得到什麼結果了?

# 用訓練好的模型計算測試集的數據,看是否能得到準確值  
y_predict_test=linear_regressor.predict(X_test)  
plt.figure()  
plt.scatter(X_test,y_test)  
plt.plot(X_test,y_predict_test,'-b',linewidth=3)  
plt.scatter(X_test,y_predict_test,color='black',marker='x')  

 

  1. 使用線性迴歸模型擬合測試集得到的直線

小結:

1,sklearn模塊種類的linear_model包中有很多線性模型,其中的LinearRegression 專門用於線性迴歸模型。

2,這個線性迴歸模型的訓練很簡單,fit()函數一下子搞定。

3,一旦模型訓練好,可以用predict()函數來預測新的沒有見過的X數據。

 

3. 評價模型的準確性

雖然上面我們把模型擬合後的直線繪製出來,從肉眼看上去,貌似這個線性迴歸模型可以得到比較好的擬合結果,但是怎麼樣通過定量的數值來評價這個模型的好壞了?à評價指標。

有很多評價指標可以用來衡量回歸器的擬合效果,最常用的是:均方誤差(Mean Squared Error, MSE)。

均方誤差MSE是應用的最廣泛的一個評價指標,其定義爲:給定數據集的所有點的誤差的平方的平均值,是衡量模型的預測值和真實值之間誤差的常用指標。這個值越小,表明模型越好。計算公式爲:

  1. 均方誤差MSE計算公式

還有一些其他的評價指標,比如中位數絕對誤差,解釋方差分,R方得分等。如下是本模型的評價指標結果。

# 使用評價指標來評估模型的好壞  
import sklearn.metrics as metrics  
print('平均絕對誤差:{}'.format(  
    round(metrics.mean_absolute_error(y_predict_test,y_test),2)))  
print('均方誤差MSE:{}'.format(  
    round(metrics.mean_squared_error(y_predict_test,y_test),2)))  
print('中位數絕對誤差:{}'.format(  
    round(metrics.median_absolute_error(y_predict_test,y_test),2)))  
print('解釋方差分:{}'.format(  
    round(metrics.explained_variance_score(y_predict_test,y_test),2)))  
print('R方得分:{}'.format(  
    round(metrics.r2_score(y_predict_test,y_test),2)))  

 

平均絕對誤差:11.98

均方誤差MSE:211.52

中位數絕對誤差:12.35

解釋方差分:0.93

R方得分:0.92

 

小結:

1,對一個模型的評價指標非常多,而對線性迴歸模型,可以只看均方誤差和解釋方差分,均方誤差越小越好,而解釋方差分越大越好。

2,本模型的均方誤差比較大的原因,可能在於準備數據集時引入的誤差太大,導致了數據太過分散,得到的模型擬合的直線與隨機點的誤差較大。

 

 4. 模型的保存和加載

模型一般得來不易,有時候需要耗費幾個小時,乃至幾個月的訓練才能得到,故而在訓練過程中,或者訓練結束後保存模型是非常有必要的,這樣的預測新數據時只需簡單加載模型就可以直接使用。

關於sklearn模型的保存和加載,sklearn官網給出了兩種建議的方式,第一種是使用pickle,第二種使用joblib,但我建議使用joblib,因爲簡單好用。

# 迴歸模型的保存和加載  
  
# 在保存之前先看一下模型的內部參數,主要爲兩項,截距和係數  
print('直線的截距: {}'.format(linear_regressor.intercept_)) #這是截距  
print('直線的係數(斜率): {}'.format(linear_regressor.coef_)) #這係數,對應於本項目的直線斜率  
y_value=linear_regressor.predict([[120]])  
print('用線性模型計算的值:{}'  
      .format(y_value)) # 這兩個print的結果應該是一樣的  
print('直線方程計算的值:{}'  
      .format(linear_regressor.coef_*120+linear_regressor.intercept_))   
  
save_path='d:/Models/LinearRegressor_v1.txt'  
  
# 第一種方法,pickle  
import pickle  
s=pickle.dumps(linear_regressor) # 模型保存  
loaded_classifier=pickle.loads(s) # 模型加載  
y_value=loaded_classifier.predict([[120]])  
print('pickle加載後的模型計算結果:{}'.format(y_value))  
  
# 第二種方法:joblib  
from sklearn.externals import joblib  
joblib.dump(linear_regressor,save_path) # 模型保存到文件中  
loaded_classifier2=joblib.load(save_path)  
y_value=loaded_classifier2.predict([[120]])  
print('joblib加載後的模型計算結果:{}'.format(y_value))  

 

直線的截距: [9.50824666]

直線的係數(斜率): [[1.71905515]]

用線性模型計算的值:[[215.79486427]]

直線方程計算的值:[[215.79486427]]

pickle加載後的模型計算結果:[[215.79486427]]

joblib加載後的模型計算結果:[[215.79486427]]

 

小結:

1,對sklearn模型的保存和加載有兩種方式,通過pickle和joblib兩種方式,但joblib是sklearn自帶的模型保存函數,而且可以很明確的指定保存到哪一個文件中,故而推薦用這種方式。

2,雖然保存的方式不一樣,但是都可以正常的保存和加載,得到的計算結果也一樣。

3,模型得到的直線方程是y=1.719x+9.508,和最開始的y數據產生時所用的直線方程y=1.8x+5.9+error有很大偏差,這是因爲error噪音數據太大所導致的,故而模型得到的均方誤差也比較大一些。

 

注:本部分代碼已經全部上傳到(我的github)上,如有任何問題,請聯繫我。

 

參考:Python機器學習經典實例,Prateek Joshi著,陶俊傑,陳小莉譯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章