(本文所使用的Python庫和版本號: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )git
迴歸分析是一種基於現有數據集,從現有數據集中尋找數據規律的一種建模技術,主要研究的是因變量(輸出y,或標記,或目標,它的別名比較多)和自變量(輸入x,或特徵,或預測器)之間的關係。一般用於預測分析,從現有數據集中找到數據規律,用該數據規律來預測將來的,或新輸入的自變量,從而計算出因變量的過程。github
簡單線性迴歸是最基本,最簡單的一種迴歸分析模型,也是最被人熟知,最被人首選的迴歸模型。簡單線性迴歸模型的因變量y是連續的,自變量X能夠是連續的也能夠是離散的,其基本假設是因變量與自變量之間成直線的變化關係,能夠經過一條簡單的擬合直線(y=ax+b)來表示二者之間的關係。因此線性迴歸模型的訓練目標就是獲取這兩直線的斜率a和截距b。以下圖所示爲簡單的線性迴歸器的模型獲得的線性圖。dom
剩下的問題就是,怎麼從數據集中得迴歸直線y=ax+b中的a和b,答案是最小二乘法。最小二乘法是擬合直線最經常使用的方法,其本質是經過最小化每一個數據點到直線的垂直誤差的平方和來計算最佳擬合直線。最小二乘法的計算公式爲:機器學習
下面使用線性迴歸來擬合數據集,獲得線性方程。函數
對於機器學習而言,第一部分每每是準備數據集。通常的,數據集是存放在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]]spa
--------------------------------------------完-------------------------------------excel
########################小**********結###############################code
1,數據集的準備一般須要對數據進行處理,好比,異常點,缺失值的處理等。
2,從數據集中劃分一部分做爲train set,一部分做爲test set是頗有必要的,也是機器學習中常常作的一部分工做,能夠採用sklearn的train_test_split函數來實現,簡單有效。也能夠本身寫函數先shuffle,再取一部分數據。
3,爲了配合後面的線性迴歸器進行fit,須要對向量數據進行reshape,轉變爲M行N列的形式(此處只有一個特徵向量,即X,故而N=1)。
#################################################################
使用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)
複製代碼
經過上圖,能夠看出該線性迴歸模型貌似可以很好地擬合這些數據點,可是這是將模型用於預測訓練集獲得的結果,若是用該模型預測它歷來沒見過的測試集,會獲得什麼結果了?
# 用訓練好的模型計算測試集的數據,看是否能獲得準確值
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,sklearn模塊種類的linear_model包中有不少線性模型,其中的LinearRegression 專門用於線性迴歸模型。
2,這個線性迴歸模型的訓練很簡單,fit()函數一會兒搞定。
3,一旦模型訓練好,能夠用predict()函數來預測新的沒有見過的X數據。
#################################################################
雖然上面咱們把模型擬合後的直線繪製出來,從肉眼看上去,貌似這個線性迴歸模型能夠獲得比較好的擬合結果,可是怎麼樣經過定量的數值來評價這個模型的好壞了?評價指標。
有不少評價指標能夠用來衡量回歸器的擬合效果,最經常使用的是:均方偏差(Mean Squared Error, MSE)。
均方偏差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,本模型的均方偏差比較大的緣由,可能在於準備數據集時引入的偏差太大,致使了數據太過度散,獲得的模型擬合的直線與隨機點的偏差較大。
#################################################################
模型通常得來不易,有時候須要耗費幾個小時,乃至幾個月的訓練才能獲得,故而在訓練過程當中,或者訓練結束後保存模型是很是有必要的,這樣的預測新數據時只需簡單加載模型就能夠直接使用。
關於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)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊傑,陳小莉譯