機器學習:最小二乘法實際應用的一個完整例子

整個過程分七步,爲了方便喜歡直接copy代碼看結果的同窗,每步都放上了完整的代碼。

實驗數據:html

          

 第一步:準備樣本數據並繪製散點圖python

       1)代碼及其說明算法

複製代碼

import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from scipy.optimize import leastsq

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171]) #身高
Yi=np.array([58,63,57,65,62,66,58,59,62])#體重

#畫樣本點
plt.figure(figsize=(8,6)) ##指定圖像比例: 8:6
plt.scatter(Xi,Yi,color="green",label="樣本數據",linewidth=1) 
plt.show()

複製代碼

        2)結果圖api

          3)分析數組

              從散點圖能夠看出,樣本點基本是圍繞箭頭所示的直線分佈的。因此先以直線模型對數據進行擬合app

 第二步: 使用最小二乘法算法求擬合直線機器學習

          1)代碼及其說明函數

複製代碼

import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from scipy.optimize import leastsq

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171])
Yi=np.array([58,63,57,65,62,66,58,59,62])

##須要擬合的函數func :指定函數的形狀 k= 0.42116973935 b= -8.28830260655
def func(p,x):
    k,b=p
    return k*x+b

##誤差函數:x,y都是列表:這裏的x,y更上面的Xi,Yi中是一一對應的
def error(p,x,y):
    return func(p,x)-y

#k,b的初始值,能夠任意設定,通過幾回試驗,發現p0的值會影響cost的值:Para[1]
p0=[1,20]

#把error函數中除了p0之外的參數打包到args中(使用要求)
Para=leastsq(error,p0,args=(Xi,Yi))

#讀取結果
k,b=Para[0]
print("k=",k,"b=",b)


#畫樣本點
plt.figure(figsize=(8,6)) ##指定圖像比例: 8:6
plt.scatter(Xi,Yi,color="green",label="樣本數據",linewidth=2) 

#畫擬合直線
x=np.linspace(150,190,100) ##在150-190直接畫100個連續點
y=k*x+b ##函數式
plt.plot(x,y,color="red",label="擬合直線",linewidth=2) 
plt.legend() #繪製圖例
plt.show()

複製代碼

        2)結果圖學習

         3)分析spa

             從圖上看,擬合效果仍是不錯的。樣本點基本均勻的分佈在迴歸線兩邊,沒有出現數據點嚴重偏離迴歸線的狀況。

 第三步:  驗證迴歸線的擬合程度—殘差分佈圖

         1)代碼及其說明

複製代碼

import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.graphics.api import qqplot

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171])
Yi=np.array([58,63,57,65,62,66,58,59,62])
xy_res=[]

##計算殘差
def residual(x,y):
    res=y-(0.42116973935*x-8.28830260655)
    return res

##讀取殘差
for d in range(0,len(Xi)):
    res=residual(Xi[d],Yi[d])
    xy_res.append(res)
##print(xy_res)

##計算殘差平方和:22.8833439288 -->越小擬合狀況越好
xy_res_sum=np.dot(xy_res,xy_res)
#print(xy_res_sum) 

##若是數據擬合模型效果好,殘差應該聽從正態分佈(0,d*d:這裏d表示殘差)
#畫樣本點
fig=plt.figure(figsize=(8,6)) ##指定圖像比例: 8:6
ax=fig.add_subplot(111)
fig=qqplot(np.array(xy_res),line='q',ax=ax)
plt.show()

複製代碼

       2)結果圖

         3)分析

             上圖爲Q-Q圖,原理:若是兩個分佈類似,則該Q-Q圖趨近於落在y=x線上。若是兩分佈線性相關,則點在Q-Q圖上趨近於落在一條直線上,但不必定在y=x線上。Q-Q圖能夠用來可在分佈的位置-尺度範疇上可視化的評估參數。

              從圖上能夠看出,迴歸效果比較理想,但不是最理想的

        4)如下代碼能夠一樣實現上述圖示:

複製代碼

import numpy as np
import scipy.stats as stats
import pylab

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171])
Yi=np.array([58,63,57,65,62,66,58,59,62])
xy_res=[]

##計算殘差
def residual(x,y):
    res=y-(0.42116973935*x-8.28830260655)
    return res

##讀取殘差
for d in range(0,len(Xi)):
    res=residual(Xi[d],Yi[d])
    xy_res.append(res)
##print(xy_res)

##計算殘差平方和:22.8833439288 -->越小擬合狀況越好
xy_res_sum=np.dot(xy_res,xy_res)
#print(xy_res_sum) 

##若是數據擬合模型效果好,殘差應該聽從正態分佈(0,d*d:這裏d表示殘差)
#畫樣本點
stats.probplot(np.array(xy_res),dist="norm",plot=pylab)
pylab.show()

複製代碼

 

 第四步: 驗證迴歸線的擬合程度—標準化殘差

         1)代碼及其說明

複製代碼

import numpy as np
import matplotlib.pyplot as plt

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171])
Yi=np.array([58,63,57,65,62,66,58,59,62])
xy_res=[]

##計算殘差
def residual(x,y):
    res=y-(0.42116973935*x-8.28830260655)
    return res

##讀取殘差
for d in range(0,len(Xi)):
    res=residual(Xi[d],Yi[d])
    xy_res.append(res)
##print(xy_res)

##計算殘差平方和:22.8833439288 -->越小擬合狀況越好
xy_res_sum=np.dot(xy_res,xy_res)

'''
      標準殘差:  (殘差-殘差平均值)/殘差的標準差
'''

'''
      標準殘差圖:
    1.標準殘差是以擬合模型的自變量爲橫座標,以標準殘差爲縱座標造成的平面座標圖像
    2.試驗點的標準殘差落在殘差圖的(-2,2)區間之外的機率<=0.05.若某一點落在區間外,可判爲異常點
    3.有效標準殘差點圍繞y=0的直線上下徹底隨機分佈,說明擬合狀況良好
    4.若是擬合方程本來是非線性模型,但擬合時卻採用了線性模型,標準化殘差圖就會表現出曲線形狀,產生
      系統性誤差
'''

##計算殘差平均值
xy_res_avg=0
for d in range(0,len(xy_res)):
    xy_res_avg+=xy_res[d]
    
xy_res_avg/=len(xy_res)

#殘差的標準差
xy_res_sd=np.sqrt(xy_res_sum/len(Xi))
##標準化殘差 
xy_res_sds=[]

for d in range(0,len(Xi)):
    res=(xy_res[d]-xy_res_avg)/xy_res_sd
    xy_res_sds.append(res)

#print(xy_res_sds)
    
#標準化殘差分佈
plt.figure(figsize=(8,6)) ##指定圖像比例: 8:6
plt.scatter(Xi,xy_res_sds) 
plt.show()

'''
  1.絕大部分數據分佈在(-2,+2)的水平帶狀區間內,所以模型擬合較充分
  2.數據點分佈稍均勻,但沒有達到隨機均勻分佈的狀態。此外,部分數據點還呈現某種曲線波動形狀,
    有少量系統性誤差。所以可能採用非線性擬合效果會更好
'''

複製代碼

         2)結果圖

          3)分析

               數據點分佈仍是存在必定的變化趨勢的。

  第五步:使用曲線模型擬合數據

         1)代碼及其說明

複製代碼

import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from scipy.optimize import leastsq

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171])
Yi=np.array([58,63,57,65,62,66,58,59,62])

##須要擬合的函數func :指定函數的形狀 k= 0.860357336936 b= -19.6659389666
def func(p,x):
    k,b=p
    return x**k+b

##誤差函數:x,y都是列表:這裏的x,y更上面的Xi,Yi中是一一對應的
def error(p,x,y):
    return func(p,x)-y

#k,b的初始值,能夠任意設定,通過幾回試驗,發現p0的值會影響cost的值:Para[1]
p0=[1,20]

#把error函數中除了p0之外的參數打包到args中(使用要求)
Para=leastsq(error,p0,args=(Xi,Yi))

#讀取結果
k,b=Para[0]
print("k=",k,"b=",b)


#畫樣本點
plt.figure(figsize=(8,6)) ##指定圖像比例: 8:6
plt.scatter(Xi,Yi,color="green",label="樣本數據",linewidth=2) 

#畫擬合直線
x=np.linspace(150,190,100) ##在150-190直接畫100個連續點
y=x**k+b ##函數式
plt.plot(x,y,color="red",label="擬合直線",linewidth=2) 
plt.legend() #繪製圖例
plt.show()

複製代碼

         2)結果圖

         3)分析

              因爲標準化殘差的分佈圖,部分數據的趨勢與冪函數在第一象限的圖像相似, 因此採用了y=xa  +b的函數形式,截距b是爲了圖像能夠在Y軸上下移動

 第六步:驗證迴歸線的擬合程度—殘差分佈圖

        1)代碼及其說明

複製代碼

import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.graphics.api import qqplot

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171])
Yi=np.array([58,63,57,65,62,66,58,59,62])
xy_res=[]

##計算殘差
def residual(x,y):
    res=y-(x**0.860357336936-19.6659389666)
    return res

##讀取殘差
for d in range(0,len(Xi)):
    res=residual(Xi[d],Yi[d])
    xy_res.append(res)
##print(xy_res)

##計算殘差平方和:22.8833439288 -->越小擬合狀況越好
xy_res_sum=np.dot(xy_res,xy_res)
#print(xy_res_sum) 

##若是數據擬合模型效果好,殘差應該聽從正態分佈(0,d*d:這裏d表示殘差)
#畫樣本點
fig=plt.figure(figsize=(8,6)) ##指定圖像比例: 8:6
ax=fig.add_subplot(111)
fig=qqplot(np.array(xy_res),line='q',ax=ax)
plt.show()

複製代碼

        2)結果圖

         3)分析

                   從圖上能夠看出,迴歸效果也比較理想

 第七步:驗證迴歸線的擬合程度—標準化殘差

         1)代碼及其說明

複製代碼

import numpy as np
import matplotlib.pyplot as plt

##樣本數據(Xi,Yi),須要轉換成數組(列表)形式
Xi=np.array([160,165,158,172,159,176,160,162,171])
Yi=np.array([58,63,57,65,62,66,58,59,62])
xy_res=[]

##計算殘差
def residual(x,y):
    res=y-(x**0.860357336936-19.6659389666)
    return res

##讀取殘差
for d in range(0,len(Xi)):
    res=residual(Xi[d],Yi[d])
    xy_res.append(res)
##print(xy_res)
##計算殘差平方和:22.881076636 -->越小擬合狀況越好
xy_res_sum=np.dot(xy_res,xy_res)
#print(xy_res_sum)

'''
      標準殘差:  (殘差-殘差平均值)/殘差的標準差
'''
##計算殘差平均值
xy_res_avg=0
for d in range(0,len(xy_res)):
    xy_res_avg+=xy_res[d]
    
xy_res_avg/=len(xy_res)

#殘差的標準差
xy_res_sd=np.sqrt(xy_res_sum/len(Xi))

##標準化殘差 
xy_res_sds=[]

for d in range(0,len(Xi)):
    res=(xy_res[d]-xy_res_avg)/xy_res_sd
    xy_res_sds.append(res)

print(xy_res_sds)
    
#標準化殘差分佈
plt.figure(figsize=(8,6)) ##指定圖像比例: 8:6
plt.scatter(Xi,xy_res_sds) 
plt.show()

'''
  1.絕大部分數據分佈在(-2,+2)的水平帶狀區間內,所以模型擬合較充分
  2.數據點分佈稍均勻,但沒有達到隨機均勻分佈的狀態。此外,部分數據點還呈現某種曲線波動形狀,
    有少量系統性誤差。所以可能採用非線性擬合效果會更好
'''

複製代碼

        2)結果圖

          3)分析

               數據點分佈趨和直線迴歸方程基本同樣

 

補充說明:

       其實整個實驗過程並無達到預期效果。

       1)若是對實驗過程的5-7步使用R語言從新實驗(R語言提供了全部相關函數),第7步的效果以下:

 

 

也就說全部的標準化殘差都是落在(-2,+2)區間內的,即曲線方程纔是最佳擬合方程。

      2)標準化殘差沒有找到具體的定義,網上對這個定義有多種解釋

      3)標準化殘差的計算方式沒有找到相應的python包,只能按照其中某一個定義本身寫代碼計算(估計是浮點數計算產生的偏差)

分類: Python,機器學習

標籤: 機器學習Python最小二乘法

相關文章
相關標籤/搜索