線性回歸的概念
1、線性回歸的原理
2、線性回歸損失函數、代價函數、目标函數
3、優化方法(梯度下降法、牛頓法、拟牛頓法等)
4、線性回歸的評估名額
5、sklearn參數詳解
一、回歸
回歸是一種預測模組化技術,其中被估計的目标變量是連續的。回歸應用的例子包括使用其他經濟學名額預測股市指數,基于高空氣特征流預測一個地區的降水量,根據廣告開銷預測公司的總銷售,按照有機物質中的碳14殘留估計化石的年齡。
1、線性回歸的原理這是一家房産網的資料,可以看到有房價、面積、廳室的資料:

我們可以将價格和面積、廳室數量的關系習得為
,使得
,這就是一個直覺的線性回歸的樣式。
2、線性回歸的一般形式給定由d個屬性描述的執行個體
,其中
是
在第
個屬性上的取值,線性模型(linear model)試圖學得一個通過屬性的線性組合來進行預測的函數
一般用向量的形式寫成
,其中
和
學得之後,模型就得以确定。
3、線性回歸給定資料集
,其中,
,
,其中n表示變量的數量,d表示每個變量的次元。“線性回歸”(linear regression)試圖學得一個現行模型以盡可能準确地預測實值輸出标記。
可以用以下函數來描述y和x之間的關系:
如何來确定 的值,使得 ( )盡可能接近y的值呢?均方誤差是回歸中常用的性能度量,即:
下面我們用極大似然估計,來解釋為什麼要用均方誤差作為性能度量,我們可以把目标值和變量寫成如下等式:
表示我們未觀測到的變量的印象,即随機噪音。我們假定
是獨立同分布,服從高斯分布。(根據中心極限定理)
是以,
我們建立極大似然函數,即描述資料遵從目前樣本分布的機率分布函數。由于樣本的資料集獨立同分布,是以可以寫成
選擇
,使得似然函數最大化,這就是極大似然估計的思想。為了友善計算,我們計算時通常對對數似然函數求最大值:
顯然,最大化
即最小化
。
這一結果即均方誤差,是以用這個值作為代價函數來優化模型在統計學的角度是合理的。
二、線性回歸損失函數、代價函數、目标函數
- 損失函數(Loss Function):度量單樣本預測的錯誤程度,損失函數值越小,模型就越好。
- 代價函數(Cost Function):度量全部樣本集的平均誤差。
- 目标函數(Object Function):代價函數和正則化函數,最終要優化的函數。
常用的損失函數包括:0-1損失函數、平方損失函數、絕對損失函數、對數損失函數等;常用的代價函數包括均方誤差、均方根誤差、平均絕對誤差等。
思考題:既然代價函數已經可以度量樣本集的平均誤差,為什麼還要設定目标函數?
回答:
當模型複雜度增加時,有可能對訓練集可以模拟的很好,但是預測測試集的效果不好,出現過拟合現象,這就出現了所謂的“結構化風險”。結構風險最小化即為了防止過拟合而提出來的政策,定義模型複雜度為
,目标函數可表示為:
例如有以上6個房價和面積關系的資料點,可以看到,當設定
時,可以完美拟合訓練集資料,但是,真實情況下房價和面積不可能是這樣的關系,出現了過拟合現象。當訓練集本身存在噪聲時,拟合曲線對未知影響因素的拟合往往不是最好的。 通常,随着模型複雜度的增加,訓練誤差會減少;但測試誤差會先增加後減小。我們的最終目的時試測試誤差達到最小,這就是我們為什麼需要選取适合的目标函數的原因。
三、
線性回歸的優化方法 3.1 最小二乘法 現在問題轉換成了求解讓⾸首先我們對上圖的資料進⾏行行拟合,可得到:
令
其中,
由于
可以寫作
對于向量來說,有
是以可以把損失函數寫作
為最小化
,對
求導可得:
中間兩項互為轉置,由于求得的值是個标量,矩陣與轉置相同,是以可以寫成
令偏導數等于零,由于最後一項和
無關,偏導數為0。
是以,
利用矩陣求導性質,
和
令導數等于零,
設定初始參數
,不斷疊代,使得
最小化:
即:
注:下标j表示第j個參數,上标i表示第i個資料點。
将所有的參數以向量形式表示,可得:
由于這個方法中,參數在每一個資料點上同時進行了移動,是以稱為批梯度下降法,對應的,我們可以每一次讓參數隻針對一個資料點進行移動,即:
這個算法成為随機梯度下降法,随機梯度下降法的好處是,當資料點很多時,運作效率更高;缺點是,因為每次隻針對一個樣本更新參數,未必找到最快路徑達到最優值,甚至有時候會出現參數在最小值附近徘徊而不是立即收斂。但當資料量很大的時候,随機梯度下降法經常優于批梯度下降法。
當J為凸函數時,梯度下降法相當于讓參數 θ不斷向J的最小值位置移動,梯度下降法的缺陷:如果函數為非凸函數,有可能找到的并非全局最優值,而是局部最優值。
3.3 牛頓法通過圖例可知(參考吳恩達CS229),
可求得,
重複疊代,可以讓逼近取到
的最小值
當我們對損失函數
進行優化的時候,實際上是想要取到
的最小值,是以疊代公式為:
當
是向量值的時候,
其中,
是
對
的偏導數,
是
的海森矩陣,
Answer:将
用泰勒公式展開到第二階,
對上式求導,并令導數等于0,求得x值
可以求得,
牛頓法的收斂速度非常快,但海森矩陣的計算較為複雜,尤其當參數的次元很多時,會耗費大量計算成本。我們可以用其他矩陣替代海森矩陣,用拟牛頓法進行估計。
3.4 拟牛頓法拟牛頓法的思路是用一個矩陣替代計算複雜的海森矩陣H,是以要找到符合H性質的矩陣。
要求得海森矩陣符合的條件,同樣對泰勒公式求導
令
,即疊代後的值,代入可得:
更一般的,
為第k個疊代值
即找到矩陣G,使得它符合上式。 常用的拟牛頓法的算法包括DFP,BFGS等,作為選學内容,有興趣者可自行查詢材料學習。
四、線性回歸的評估名額
均方誤差(MSE):
均方根誤差(RMSE):
平均絕對誤差(MAE):
但以上評價名額都無法消除量綱不一緻而導緻的誤內插補點差别大的問題,最常用的名額是
,可以避免量綱不一緻問題
我們可以把
了解為,回歸模型可以成功解釋的資料方差部分在資料固有方差中所占的比例,
越接近1,表示可解釋力度越大,模型拟合的效果越好。
五、sklearn.linear_model參數詳解:
fit_intercept : 預設為True,是否計算該模型的截距。如果使用中心化的資料,可以考慮設定為False,不考慮截距。注意這裡是考慮,一般還是要考慮截距
normalize: 預設為false. 當fit_intercept設定為false的時候,這個參數會被自動忽略。如果為True,回歸器會标準化輸入參數:減去平均值,并且除以相應的二範數。當然啦,在這裡還是建議将标準化的工作放在訓練模型之前。通過設定sklearn.preprocessing.StandardScaler來實作,而在此處設定為false
copy_X : 預設為True, 否則X會被改寫
n_jobs: int 預設為1. 當-1時預設使用全部CPUs ??(這個參數有待嘗試)
可用屬性:
coef_:訓練後的輸入端模型系數,如果label有兩個,即y值有兩列。那麼是一個2D的array
intercept_: 截距
可用的methods:
fit(X,y,sample_weight=None): X: array, 稀疏矩陣 [n_samples,n_features] y: array [n_samples, n_targets] sample_weight: 權重 array [n_samples] 在版本0.17後添加了sample_weight
get_params(deep=True): 傳回對regressor 的設定值
predict(X): 預測 基于 R^2值
score: 評估
參考:
API詳解:sklearn.linear_model.LinearRegression_人工智能_Sehr Gut-CSDN部落格
六、代碼實作
6.1 生成資料
#生成資料
import numpy as np
#生成随機數
np.random.seed(1234)
x = np.random.rand(500,3)
#建構映射關系,模拟真實的資料待預測值,映射關系為y = 4.2 + 5.7*x1 + 10.8*x2,可自行設定值進行嘗試
y = x.dot(np.array([4.2,5.7,10.8]))
1、先嘗試調用sklearn的線性回歸模型訓練資料
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
%matplotlib inline
# 調用模型
lr = LinearRegression(fit_intercept=True)
# 訓練模型
lr.fit(x,y)
print("估計的參數值為:%s" %(lr.coef_))
# 計算R平方
print('R2:%s' %(lr.score(x,y)))
# 任意設定變量,預測目标值
x_test = np.array([2,4,5]).reshape(1,-1)
y_hat = lr.predict(x_test)
print("預測值為: %s" %(y_hat))
估計的參數值為:[ 4.2 5.7 10.8]
R2:1.0
預測值為: [85.2]
2、最小二乘法的矩陣求解
class LR_LS():
def __init__(self):
self.w = None
def fit(self, X, y):
# 最小二乘法矩陣求解
#============================= show me your code =======================
self.w = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
#============================= show me your code =======================
def predict(self, X):
# 用已經拟合的參數值預測新自變量
#============================= show me your code =======================
y_pred = X.dot(self.w)
#============================= show me your code =======================
return y_pred
if __name__ == "__main__":
lr_ls = LR_LS()
lr_ls.fit(x,y)
print("估計的參數值:%s" %(lr_ls.w))
x_test = np.array([2,4,5]).reshape(1,-1)
print("預測值為: %s" %(lr_ls.predict(x_test)))
估計的參數值:[ 4.2 5.7 10.8]
預測值為: [85.2]
3、梯度下降法
class LR_GD():
def __init__(self):
self.w = None
def fit(self,X,y,alpha=0.02,loss = 1e-10): # 設定步長為0.002,判斷是否收斂的條件為1e-10
y = y.reshape(-1,1) #重塑y值的次元以便矩陣運算
[m,d] = np.shape(X) #自變量的次元
self.w = np.zeros((d)) #将參數的初始值定為0
tol = 1e5
#============================= show me your code =======================
while tol > loss:
h_f = X.dot(self.w).reshape(-1,1)
theta = self.w + alpha*np.mean(X*(y - h_f),axis=0) #計算疊代的參數值
tol = np.sum(np.abs(theta - self.w))
self.w = theta
#============================= show me your code =======================
def predict(self, X):
# 用已經拟合的參數值預測新自變量
y_pred = X.dot(self.w)
return y_pred
if __name__ == "__main__":
lr_gd = LR_GD()
lr_gd.fit(x,y)
print("估計的參數值為:%s" %(lr_gd.w))
x_test = np.array([2,4,5]).reshape(1,-1)
print("預測值為:%s" %(lr_gd.predict(x_test)))
估計的參數值為:[ 4.20000001 5.70000003 10.79999997]
預測值為:[85.19999995]
6.2 房屋資料集
# 加利福尼亞資料集
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing as fch
housevalue = fch()
X = pd.DataFrame(housevalue.data)
X.head()
y = housevalue.target
y
array([4.526, 3.585, 3.521, ..., 0.923, 0.847, 0.894])
['MedInc',
'HouseAge',
'AveRooms',
'AveBedrms',
'Population',
'AveOccup',
'Latitude',
'Longitude']
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
reg = LinearRegression().fit(Xtrain,Ytrain)
reg.score(Xtest,Ytest)
0.6043668160178817
rid = Ridge(alpha=1).fit(Xtrain,Ytrain)
rid.score(Xtest,Ytest)
0.6043610352312279
las = Lasso(alpha=0.1).fit(Xtrain,Ytrain)
las.score(Xtest,Ytest)
0.5368702511716803
# 交叉驗證,對比線性回歸和嶺回歸結果的變化
alpharange = np.arange(1,1001,100)
ridge=[]
lr = []
for i in alpharange:
reg = Ridge(alpha=i)
l = LinearRegression()
regs = cross_val_score(reg,X,y,cv=5,scoring='r2').mean()
ls = cross_val_score(l,X,y,cv=5,scoring='r2').mean()
ridge.append(regs)
lr.append(ls)
plt.plot(alpharange,ridge,color='red',label='Ridge')
plt.plot(alpharange,lr,color='orange',label='LR')
plt.title('Mean')
plt.legend()
plt.show()
alpharange = np.arange(1,201,10)
ridge=[]
lr = []
for i in alpharange:
reg = Ridge(alpha=i)
l = LinearRegression()
regs = cross_val_score(reg,X,y,cv=5,scoring='r2').mean()
ls = cross_val_score(l,X,y,cv=5,scoring='r2').mean()
ridge.append(regs)
lr.append(ls)
plt.plot(alpharange,ridge,color='red',label='Ridge')
plt.plot(alpharange,lr,color='orange',label='LR')
plt.title('Mean')
plt.legend()
plt.show()
alpharange = np.arange(1,1001,100)
ridge=[]
lr = []
for i in alpharange:
reg = Ridge(alpha=i)
l = LinearRegression()
regs = cross_val_score(reg,X,y,cv=5,scoring='r2').var()
ls = cross_val_score(l,X,y,cv=5,scoring='r2').var()
ridge.append(regs)
lr.append(ls)
plt.plot(alpharange,ridge,color='red',label='Ridge')
plt.plot(alpharange,lr,color='orange',label='LR')
plt.title('ValueError')
plt.legend()
plt.show()
from sklearn.datasets import load_boston
X = load_boston().data
y = load_boston().target
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
alpharange = np.arange(1,1001,100)
ridge=[]
lr = []
for i in alpharange:
reg = Ridge(alpha=i)
l = LinearRegression()
regs = cross_val_score(reg,X,y,cv=5,scoring='r2').mean()
ls = cross_val_score(l,X,y,cv=5,scoring='r2').mean()
ridge.append(regs)
lr.append(ls)
plt.plot(alpharange,ridge,color='red',label='Ridge')
plt.plot(alpharange,lr,color='orange',label='LR')
plt.title('Mean')
plt.legend()
plt.show()
alpharange = np.arange(1,1001,100)
ridge=[]
lr = []
for i in alpharange:
reg = Ridge(alpha=i)
l = LinearRegression()
regs = cross_val_score(reg,X,y,cv=5,scoring='r2').var()
ls = cross_val_score(l,X,y,cv=5,scoring='r2').var()
ridge.append(regs)
lr.append(ls)
plt.plot(alpharange,ridge,color='red',label='Ridge')
plt.plot(alpharange,lr,color='orange',label='LR')
plt.title('ValueError')
plt.legend()
plt.show()
局部權重限線性回歸
核可以自由選擇,最常用的高斯核,高斯核對應的權重:
- xi距離x距離越小,w越大,k決定群衆的大小
- k越大,權重的差距越小;k越小,權重的差距越大
ex0 = pd.read_csv('ex0.txt',sep='\t',header=None)
ex0.head()
xMat = np.mat(ex0.iloc[:,:-1].values)
yMat = np.mat(ex0.iloc[:,-1].values).T
plt.scatter(xMat.A[:,1],yMat.A,c='b',s=5)
plt.show()
standRegres(ex0)
matrix([[3.00774324],
[1.69532264]])
plt.scatter(xMat.A[:,1],yMat.A,c='b',s=5)
ws = standRegres(ex0)
yhat = xMat*ws
plt.plot(xMat[:,1],yhat,c='r')
plt.show()
def LWLR(testMat,xMat,yMat,k=1.0):
n = testMat.shape[0]
m = xMat.shape[0]
weights = np.mat(np.eye(m))
yhat = np.zeros(n)
for i in range(n):
for j in range(m):
diffMat = testMat[i]-xMat[j]
weights[j,j] = np.exp(diffMat*diffMat.T/(-2*k**2))
xTx = xMat.T*(weights*xMat)
if np.linalg.det(xTx)==0:
print('矩陣為奇異矩陣,不能求逆')
return
ws = xTx.I*(xMat.T*(weights*yMat))
yhat[i]=testMat[i]*ws
return ws,yhat
# 将資料點排列,傳回索引
srt = xMat[:,1].argsort(0)
srt
matrix([[151],
.......
[ 2]], dtype=int64)
xSort = xMat[srt][:,0]
# 不同取值下的yhat
ws1,yhat1 = LWLR(xMat,xMat,yMat,k=1.0)
ws2,yhat2 = LWLR(xMat,xMat,yMat,k=0.01)
ws3,yhat3 = LWLR(xMat,xMat,yMat,k=0.003)
fig = plt.figure(figsize=(6,8),dpi=100)
# 子圖1(欠拟合)
fig1 = fig.add_subplot(311)
plt.scatter(xMat[:,1].A,yMat.A,c='b',s=2)
plt.plot(xSort[:,1],yhat1[srt],color='r')
# 子圖2(拟合的較好)
fig2 = fig.add_subplot(312)
plt.scatter(xMat[:,1].A,yMat.A,c='b',s=2)
plt.plot(xSort[:,1],yhat2[srt],color='r')
# 子圖3(過拟合)
fig3 = fig.add_subplot(313)
plt.scatter(xMat[:,1].A,yMat.A,c='b',s=2)
plt.plot(xSort[:,1],yhat3[srt],color='r')
參考
吳恩達 CS229課程
周志華 《機器學習》
李航 《統計學習方法》
通路驗證-安居客 ws:2019298239 機器學習-極大似然估計 深入了解機器學習中的:目标函數,損失函數和代價函數_人工智能_qq_28448117的部落格-CSDN部落格 API詳解:sklearn.linear_model.LinearRegression_人工智能_Sehr Gut-CSDN部落格