本主題講述線性回歸的欠擬合問題:
- 怎么評估擬合效果
一. 回歸中的問題
??回歸一詞來自一種任務背景,測試孩子與父母身高的關系逻恐,如果父母身高比較高像吻,孩子身高也會比較高,但沒有父母的平均身高高复隆,更加趨向于人類平均身高拨匆,這就是身高回歸平均身高的一種現(xiàn)象,稱為回歸挽拂。
1. 擬合性問題
線性回歸中惭每,怎么判定訓練的模型的好壞呢?因為數(shù)據(jù)集本身的影響亏栈,一般會產(chǎn)生如下兩種情況:
??|-(1)欠擬合
??|-(2)過擬合
??
我們使用下面兩個數(shù)據(jù)集來建立直觀判定台腥,哪一種數(shù)據(jù)集會產(chǎn)生更好的擬合?
??|- 擬合好壞的判別標準绒北。
1.1. 數(shù)據(jù)集1
% matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x_dat=np.loadtxt('ex2x.dat')
y_dat=np.loadtxt('ex2y.dat')
figure=plt.figure('數(shù)據(jù)集可視化',figsize=(6,4))
ax=figure.add_axes([0.1,0.1,0.8,0.8],xlabel='年齡',ylabel='身高')
ax.set_xlim(0,10)
ax.set_ylim(0,1.5)
ax.scatter(x_dat,y_dat,label='年齡身高數(shù)據(jù)集',marker='.',color=(0,0,1,1))
plt.show()
1.2. 數(shù)據(jù)集2
% matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# 第一列用來做偏置項1的黎侈,真正的數(shù)據(jù)是第2列與第3列
data=np.loadtxt('ex0.txt')
figure=plt.figure('數(shù)據(jù)集可視化',figsize=(6,4))
ax=figure.add_axes([0.1,0.1,0.8,0.8],xlabel='年齡',ylabel='身高')
ax.set_xlim(-0.2,1.2)
ax.set_ylim(1,5.5)
ax.scatter(data[:,1],data[:,2],label='不知名數(shù)據(jù)集',marker='.',color=(1,0,0,1))
plt.show()
1.3. 相關系數(shù)
在數(shù)學上提供了一個專門的概念來描述這種數(shù)據(jù)集的擬合性:相關系數(shù)。
??|-相關系數(shù):用來度量兩個向量相關程度的量闷游。
??
相關系數(shù)的公式定義:
??|-
??其中表示
的樣本協(xié)方差(無偏):
??其中表示向量
的樣本方差(無偏方差):
????|-其中表示樣本均值:
1.4. 練習作業(yè)
- 實現(xiàn)協(xié)方差峻汉,方差與均值贴汪;
- 調用numpy中協(xié)方差,方差與均值函數(shù)休吠;
- 對比自己實現(xiàn)的計算結果與numpy的計算結果扳埂;
- 理解總體方差(有偏)與樣本方差(無偏)的區(qū)別
1.5. 數(shù)據(jù)集相關性評估
下面對上面兩個數(shù)據(jù)集,計算他們的相關系數(shù)瘤礁。
??|- 計算預測輸出值與真實值之間的相關系數(shù)阳懂,從而可以判定數(shù)據(jù)集的擬合性好壞。
- 數(shù)據(jù)集1的相關系數(shù)計算(sklearn實現(xiàn))
% matplotlib inline
import matplotlib.pyplot as plt
from sklearn.linear_model import *
import numpy as np
X_DATA = np.loadtxt('ex2x.dat')
Y_DATA = np.loadtxt('ex2y.dat')
regression=LinearRegression()
X_DATA=X_DATA.reshape(-1, 1)
Y_DATA=Y_DATA.reshape(-1, 1)
regression.fit(X_DATA, Y_DATA)
# 預測輸出
Y=regression.predict(X_DATA)
#print(Y)
print(Y.shape)
print(Y_DATA.shape)
# 判定Y_DATA與Y的相關程度
# 必須確保是行向量
cor=np.corrcoef(Y.T,Y_DATA.T)
print(cor)
# 可視化
figure=plt.figure('數(shù)據(jù)集可視化',figsize=(6,4))
ax=figure.add_axes([0.1,0.1,0.8,0.8],xlabel='年齡',ylabel='身高')
ax.set_xlim(0,10)
ax.set_ylim(0,1.5)
ax.scatter(X_DATA,Y_DATA,label='年齡身高數(shù)據(jù)集',marker='.',color=(0,0,1,1))
ax.plot(X_DATA,Y,label='線性擬合',color='r',linewidth=3)
ax.legend()
plt.show()
(50, 1)
(50, 1)
[[1. 0.92631702]
[0.92631702 1. ]]
??上面的相關系數(shù)的說明:
????|-在對角線上是自己與自己的關聯(lián)系數(shù)希太;
??????|-對角線上第一個1是與自己的相關系數(shù);
??????|-對角線第二個1是與自己的相關系數(shù)酝蜒;
????|-反對角線上的兩個數(shù)是與
、
與
的相關性系數(shù)矾湃。
??
??自己與自己的相關系數(shù)是最好的亡脑,就是1。完全不相關的的就是0邀跃,等于協(xié)方差完全無關霉咨。
- 數(shù)據(jù)集2的相關系數(shù)計算(sklearn實現(xiàn))
% matplotlib inline
import matplotlib.pyplot as plt
from sklearn.linear_model import *
import numpy as np
data=np.loadtxt('ex0.txt')
X_DATA=data[:,1]
Y_DATA=data[:,2]
regression=LinearRegression()
X_DATA=X_DATA.reshape(-1, 1)
Y_DATA=Y_DATA.reshape(-1, 1)
regression.fit(X_DATA, Y_DATA)
# 預測輸出
Y=regression.predict(X_DATA)
#print(Y)
print(Y.shape)
print(Y_DATA.shape)
# 判定Y_DATA與Y的相關程度
# 必須確保是行向量
cor=np.corrcoef(Y.T,Y_DATA.T)
print(cor)
# 可視化
figure=plt.figure('數(shù)據(jù)集可視化',figsize=(6,4))
ax=figure.add_axes([0.1,0.1,0.8,0.8],xlabel='年齡',ylabel='身高')
ax.set_xlim(-0.2,1.2)
ax.set_ylim(1,5.5)
ax.scatter(data[:,1],data[:,2],label='不知名數(shù)據(jù)集',marker='.',color=(1,0,0,1))
ax.plot(X_DATA,Y,label='線性擬合',color='b',linewidth=3)
ax.legend()
plt.show()
(200, 1)
(200, 1)
[[1. 0.98647356]
[0.98647356 1. ]]
??從上面兩個數(shù)據(jù)集的直觀視覺與相關系數(shù)都看得出來,數(shù)據(jù)集2明顯具有較好的擬合效果拍屑。
??更好的擬合性表現(xiàn)在數(shù)據(jù)集樣本點盡可能在回歸(擬合)直線上途戒。
-
問題
??能否有好的方式提高數(shù)據(jù)的擬合性?這就可以解決樣本欠擬合的問題僵驰。
二喷斋、局部加權回歸算法
??局部加權回歸(Locally Weighted Linear Regression:LWLR)
??局部加權回歸是解決線性回歸欠擬合問題二提出的。
??解決問題的出發(fā)點是:線性回歸的最終核心是使均方差函數(shù)最兴廛睢(最小均方誤差)星爪,局部加權是引入加權的方式,降低均方誤差粉私,使得擬合性的度量結果更好顽腾。
??因為線性擬合中的均方差是無偏的,適當引入一些偏差诺核,可以有效降低均方差抄肖。
1. 局部加權模型
??
??其中就是局部加權系數(shù)。
??
??其中加權系數(shù)的確定是一個麻煩的事情窖杀,該系數(shù)必須確保漓摩,預測樣本點離已知樣本越遠加權系數(shù)越小,預測樣本點離已知樣本越近加權系數(shù)越大陈瘦。如果大家還記得正態(tài)分布(高斯分布)函數(shù)的性質幌甘,如果在0點取值1潮售,在接近無窮遠點,取值0锅风。我們就利用正態(tài)分布這個特性酥诽,可以取,其其他位置的元素都為0皱埠,對角線上的值為:
??
??矩陣形式是:
??
??下面使用圖示的方式肮帐,來理解該系數(shù)在回歸訓練中控制訓練樣本參與訓練的作用與價值。
% matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# 圖形數(shù)據(jù)
sigma=1
x_0=0
x=np.linspace(-1,1,101,dtype=np.float32)
y_1=np.exp((x_0-x)**2/(-2.0*sigma*sigma))
sigma=0.5
y_05=np.exp((x_0-x)**2/(-2.0*sigma*sigma))
sigma=0.1
y_001=np.exp((x_0-x)**2/(-2.0*sigma*sigma))
# 坐標軸
figure=plt.figure('機器學習-回歸優(yōu)化',figsize=(6,4))
ax=figure.add_axes([0.1,0.1,0.8,0.8],label='高斯分布系數(shù)權重關系')
ax.set_xlim(-1,1)
ax.set_ylim(0,1)
# 圖形繪制
ax.plot(x,y_1,color=(1,0,0,1),label='$\sigma=1$')
ax.plot(x,y_05,color=(0,1,0,1),label='$\sigma=0.5$')
ax.plot(x,y_001,color=(0,0,1,1),label='$\sigma=0.01$')
ax.legend()
plt.show()
2. 局部加權實現(xiàn)
??因為是總體擬合性考慮边器,所以每個測試樣本對總體訓練樣本都有一個加權矩陣训枢,該測試樣本根據(jù)加權矩陣計算出對應的預測值。這樣預測值總體的擬合性就會更好點忘巧。
- 結構設計
import matplotlib.pyplot as plt
import numpy as np
# 求一個樣本的局部權重預測值(下面函數(shù)按照多維模式恒界,但只考慮1維情況)
class LWLinearRegression:
def __init__(self, sample_x, label_y, sigma=1.0):
self.X=sample_x
self.Y=label_y
def train_one_sample(self, data):
# data 測試樣本
# 數(shù)據(jù)加權預測值
# 數(shù)據(jù)格式化
# 1. 計算局部加權矩陣
# 2. 計算線性回歸系數(shù)矩陣
# 3.計算預測值
return [0.0]
def train(self, datasets):
Y=np.zeros(shape=(datasets.shape[0],1), dtype=np.float)
# 循環(huán)計算預測值
for idx in range(datasets.shape[0]):
Y[idx]=self.train_one_sample(datasets[idx])
return Y
# 數(shù)據(jù)初始化
data=np.loadtxt('ex0.txt')
X_DATA=data[:,1]
Y_DATA=data[:,2]
# 數(shù)據(jù)格式化
X=np.zeros(shape=(X_DATA.shape[0], 2), dtype=np.float) # 考慮偏置項,在測試特征加一維
Y=Y_DATA.reshape(Y_DATA.shape[0], 1)
X[:, 0]=X_DATA
X[:, 1]=1
lwlr=LWLinearRegression(X, Y)
predict=lwlr.train(X)
#print(predict)
- 實現(xiàn)
import matplotlib.pyplot as plt
import numpy as np
# 求一個樣本的局部權重預測值(下面函數(shù)按照多維模式砚嘴,但只考慮1維情況)
class LWLinearRegression:
def __init__(self, sample_x, label_y, sigma=1.0):
self.X=sample_x
self.Y=label_y
self.sigma=sigma
def train_one_sample(self, data):
# data 測試樣本
# 數(shù)據(jù)加權預測值
# 數(shù)據(jù)格式化
# 1. 計算局部加權矩陣
local_weight=np.zeros(shape=(self.X.shape[0],self.X.shape[0]),dtype=np.float32)
for idx in range(local_weight.shape[0]):
# 求差
diff=data-self.X[idx,:]
# 求平方,然后除以sigma
sqrt=np.matmul(diff,diff.T)/(-2.0*(self.sigma**2))
# 計算局部加權矩陣的對角線
local_weight[idx,idx]=np.exp(sqrt)
# 2. 計算線性回歸系數(shù)矩陣
# 這里應該先做一個奇異值判定(我們暫時不去判定十酣,等系統(tǒng)處理發(fā)生的異常)
W=np.matmul(
np.matmul(
np.matmul(
np.linalg.inv(
np.matmul(
np.matmul(
self.X.T,
local_weight
),
self.X
)
),
self.X.T
),
local_weight
),
self.Y
)
# 3.計算預測值
out_value=np.matmul(data,W)
return out_value
def train(self, datasets):
Y=np.zeros(shape=(datasets.shape[0],1), dtype=np.float)
# 循環(huán)計算預測值
for idx in range(datasets.shape[0]):
Y[idx]=self.train_one_sample(datasets[idx])
return Y
# 數(shù)據(jù)初始化
data=np.loadtxt('ex0.txt')
X_DATA=data[:,1]
Y_DATA=data[:,2]
# 數(shù)據(jù)格式化
X=np.zeros(shape=(X_DATA.shape[0], 2), dtype=np.float) # 考慮偏置項,在測試特征加一維
Y=Y_DATA.reshape(Y_DATA.shape[0], 1)
X[:, 0]=X_DATA
X[:, 1]=1
lwlr=LWLinearRegression(X, Y)
# 使用訓練集作為測試集
predict=lwlr.train(X)
#print(predict)
- 擬合可視化
??通過可視化來觀察擬合效果际长;為了保證代碼的完整性耸采,我們把計算于可視化代碼放在一起。
import matplotlib.pyplot as plt
import numpy as np
# 求一個樣本的局部權重預測值(下面函數(shù)按照多維模式工育,但只考慮1維情況)
class LWLinearRegression:
def __init__(self, sample_x, label_y, sigma=1.0):
self.X=sample_x
self.Y=label_y
self.sigma=sigma
def train_one_sample(self, data):
# data 測試樣本
# 數(shù)據(jù)加權預測值
# 數(shù)據(jù)格式化
# 1. 計算局部加權矩陣
local_weight=np.zeros(shape=(self.X.shape[0],self.X.shape[0]),dtype=np.float32)
for idx in range(local_weight.shape[0]):
# 求差
diff=data-self.X[idx,:]
# 求平方,然后除以sigma
sqrt=np.matmul(diff,diff.T)/(-2.0*(self.sigma**2))
# 計算局部加權矩陣的對角線
local_weight[idx,idx]=np.exp(sqrt)
# 2. 計算線性回歸系數(shù)矩陣
# 這里應該先做一個奇異值判定(我們暫時不去判定虾宇,等系統(tǒng)處理發(fā)生的異常)
W=np.matmul(
np.matmul(
np.matmul(
np.linalg.inv(
np.matmul(
np.matmul(
self.X.T,
local_weight
),
self.X
)
),
self.X.T
),
local_weight
),
self.Y
)
# 3.計算預測值
out_value=np.matmul(data,W)
return out_value
def train(self, datasets):
Y=np.zeros(shape=(datasets.shape[0],1), dtype=np.float)
# 循環(huán)計算預測值
for idx in range(datasets.shape[0]):
Y[idx]=self.train_one_sample(datasets[idx])
return Y
# 數(shù)據(jù)初始化
data=np.loadtxt('ex0.txt')
X_DATA=data[:,1]
Y_DATA=data[:,2]
# 數(shù)據(jù)格式化
X=np.zeros(shape=(X_DATA.shape[0], 2), dtype=np.float) # 考慮偏置項,在測試特征加一維
Y=Y_DATA.reshape(Y_DATA.shape[0], 1)
X[:, 0]=X_DATA
X[:, 1]=1
sigma=0.003
lwlr=LWLinearRegression(X, Y,sigma)
# 使用訓練集作為測試集
predict=lwlr.train(X)
#print(predict)
# 可視化
# 可視化
figure=plt.figure('數(shù)據(jù)集可視化',figsize=(6,4))
ax=figure.add_axes([0.1,0.1,0.8,0.8],xlabel='年齡',ylabel='身高')
ax.set_xlim(-0.2,1.2)
ax.set_ylim(1,5.5)
ax.scatter(X_DATA,Y_DATA,label='不知名數(shù)據(jù)集',marker='.',color=(1,0,0,1))
# 排序顯示
# 得到排序索引
sort_idx=X_DATA.argsort(0)
# 得到排序的結果
X_SORT=X_DATA[sort_idx]
Y_SORT=predict[sort_idx]
ax.plot(X_SORT,Y_SORT,label='線性擬合',color='b',linewidth=3)
ax.legend()
plt.show()
- 擬合度量計算
??通過相關系數(shù)嘱朽,來判定擬合的效果;
import matplotlib.pyplot as plt
import numpy as np
# 求一個樣本的局部權重預測值(下面函數(shù)按照多維模式竭沫,但只考慮1維情況)
class LWLinearRegression:
def __init__(self, sample_x, label_y, sigma=1.0):
self.X=sample_x
self.Y=label_y
self.sigma=sigma
def train_one_sample(self, data):
# data 測試樣本
# 數(shù)據(jù)加權預測值
# 數(shù)據(jù)格式化
# 1. 計算局部加權矩陣
local_weight=np.zeros(shape=(self.X.shape[0],self.X.shape[0]),dtype=np.float32)
for idx in range(local_weight.shape[0]):
# 求差
diff=data-self.X[idx,:]
# 求平方,然后除以sigma
sqrt=np.matmul(diff,diff.T)/(-2.0*(self.sigma**2))
# 計算局部加權矩陣的對角線
local_weight[idx,idx]=np.exp(sqrt)
# 2. 計算線性回歸系數(shù)矩陣
# 這里應該先做一個奇異值判定(我們暫時不去判定燥翅,等系統(tǒng)處理發(fā)生的異常)
W=np.matmul(
np.matmul(
np.matmul(
np.linalg.inv(
np.matmul(
np.matmul(
self.X.T,
local_weight
),
self.X
)
),
self.X.T
),
local_weight
),
self.Y
)
# 3.計算預測值
out_value=np.matmul(data,W)
return out_value
def train(self, datasets):
Y=np.zeros(shape=(datasets.shape[0],1), dtype=np.float)
# 循環(huán)計算預測值
for idx in range(datasets.shape[0]):
Y[idx]=self.train_one_sample(datasets[idx])
return Y
# 數(shù)據(jù)初始化
data=np.loadtxt('ex0.txt')
X_DATA=data[:,1]
Y_DATA=data[:,2]
# 數(shù)據(jù)格式化
X=np.zeros(shape=(X_DATA.shape[0], 2), dtype=np.float) # 考慮偏置項,在測試特征加一維
Y=Y_DATA.reshape(Y_DATA.shape[0], 1)
X[:, 0]=X_DATA
X[:, 1]=1
sigma=0.003
lwlr=LWLinearRegression(X, Y,sigma)
# 使用訓練集作為測試集
predict=lwlr.train(X)
#print(predict)
cor=np.corrcoef(predict.T,Y.T)
print(cor)
[[1. 0.99931945]
[0.99931945 1. ]]
??從相關系數(shù)來看蜕提,擬合的效果應該是非常的好了森书!
??但是該代碼中,還是可能存在矩陣奇異問題谎势。當取其中sigma參數(shù)為很小的時候凛膏,由于參與訓練的樣本減少,矩陣出現(xiàn)奇異的可能性非常大脏榆。
??奇異值問題的解決留待下一個主題講解猖毫。
??本主題中故意采用了ndarray的向量形式。如果使用標準的矩陣運算须喂,則在格式化上面會簡單很多吁断,因為矩陣(np.matrix)支持*這樣的內積運算符號趁蕊。就不用使用matmul這樣的函數(shù)運算。