1 多變量線性迴歸應用場景
目前爲止,我們探討了單變量/特徵的迴歸模型,現在我們對房價模型增加更多的特徵,例如房間數樓層等,構成一個含有多個變量的模型.。
1.1 單變量線性迴歸案例
- 模型: hθ(x) = θ0 + θ1x
1.2 多變量線性迴歸案例
- 模型:
- 新的概念
例如:
x(1) = [40, 1, 1, 10]
x(2) = [96, 2, 1, 5]
x(3) = [135, 3, 2, 20]
例如:
x(1)1 = 40
x(1)2 = 1
.......
2 多元梯度下降法
- 模型:
- 參數:
- 損失函數:
- 梯度下降公式(重複執行):
2.1 一元梯度下降n=1, 重複執行,直到收斂
2.2 多元梯度下降n>1
2.3 多元批梯度下降代碼
import numpy as np
# 1). 模擬數據
X1 = 2 * np.random.randn(100, 1)
X2 = 4 * np.random.rand(100, 1)
X3 = 6 * np.random.rand(100, 1)
y = 4 + 3 * X1 + 4 * X2 + 5 * X3 + np.random.randn(100, 1)
# 2). 實現梯度下降算法
# np.c_是將數據組合成向量格式: (n, 1) (n,1) = (n, 2)
X_b = np.c_[np.ones((100, 1)), X1, X2, X3]
# 初始化theta的值, 需要計算四個theta的值;
theta = np.random.randn(4, 1)
# 設置學習率和收斂次數
learning_rate = 0.1
n_iterations = 1000
# 根據公式計算
for iteration in range(n_iterations):
# 梯度下降公式 = 1/樣本數 * (預測值 - 真實值) *Xi
gradients = 1 / 100 * X_b.T.dot(X_b.dot(theta) - y)
# theta = theta - 學習率 * 梯度值
theta = theta - learning_rate * gradients
print(theta)
- 代碼執行結果:
3 梯度下降法實踐一:特徵縮放
3.1 梯度下降法遇到的問題
在我們面對多維特徵問題的時候,我們要保證這些特徵都具有相近的尺度,這將幫助梯度下降算法更快地收斂。而特徵縮放是爲了確保特徵在一個數量級上。
以房價問題爲例,假設我們使用兩個特徵,房屋的尺寸和房間的數量,其中x1 = 房屋面積(0-400 m2), x2 = 臥室數量(1-5), 以兩個參數分別爲橫縱座標,繪製代價函數的等高線圖能,看出圖像會顯得很扁,梯度下降算法需要非常多次的迭代才能收斂。
3.2 解決方法
-
解決方法一:
- 嘗試將所有特徵的尺度都儘量縮放到-1到1之間。比如:
x1 = 房屋面積 / 400
x2 = 臥室數量 / 5
- 解決方法二: 平方均值法
在原來的基礎上把特徵 xi 替換成 xi – μ;
也可以把最大值換成標準差,或者最大值 – 最小值。
4 梯度下降法實踐二: 學習率
4.1 梯度下降法遇到的問題
梯度下降算法收斂所需要的迭代次數根據模型的不同而不同,我們不能提前預知,我們可以繪製迭代次數和代價函數的圖表來觀測算法在何時趨於收斂。
梯度下降算法的每次迭代受到學習率的影響,
- 如果學習率過小,則達到收斂所需的迭代次數會非常高;
- 如果學習率過大,每次迭代可能不會減小代價函數,可能會越過局部最小值導致無法收斂。
4.2 解決方法
- 自動測試是否收斂的方法,例如將代價函數的變化值與某個閥值(例如0.001)進行比較,但通常看上面這樣的圖表更好。
嘗試在如下的數值中選擇α : …, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1,…
5 梯度下降算法補充
5.1 三種梯度下降總結
如何選擇?
- 訓練集比較小: 使用批梯度下降(小於2000個)
- 訓練集比較大:使用Mini-bitch梯度下降 一般的Mini-batch size 是64,128,256, 512,1024, Mini-batch size要適用CPU/GPU的內存
5.2 隨機梯度下降
隨機梯度下降思想:把m個樣本分成m份,每次用1份做梯度下降;也就是說,當有m個樣本時,批梯度下降只能做一次梯度下降,但是隨機梯度下降可以做m次。
- 實現代碼
import numpy as np
import random
X = 2 * np.random.rand(100, 1)
Y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# 每輪epochs處理m個樣本;
n_epochs = 1000
# 學習率
a0 = 0.1
# 定義衰減率
decay_rate = 1
def learning_schedule(epoch_num):
"""
定義一個學習率衰減的函數
"""
return (1.0 / (decay_rate * epoch_num + 1)) * a0
# 初始化theta值
theta = np.random.randn(2, 1)
# 初始化隨機值
num = [i for i in range(100)]
m = 100
for epoch in range(n_epochs):
rand = random.sample(num, 100)
for i in range(m):
random_index = rand[i]
xi = X_b[random_index:random_index + 1]
yi = Y[random_index:random_index + 1]
# 隨機梯度下降值
gradients = xi.T.dot(xi.dot(theta) - yi)
# 學習率
learning_rate = learning_schedule(epoch+1)
theta = theta - learning_rate * gradients
print(theta)
- 執行結果展示:
5.3 Mini-batch梯度算法
隨機梯度下降會喪失向量帶來的加速,所以我們不會太用隨機梯度下降。
- 實現代碼
import numpy as np
import random
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# print(X_b)
n_epochs = 500
a = 0.03
m = 100
num = [i for i in range(100)]
theta = np.random.randn(2, 1)
batch_num = 5
batch_size = m // 5
# epoch 是輪次的意思,意思是用m個樣本做一輪迭代
for epoch in range(n_epochs):
# 生成100個不重複的隨機數
for i in range(batch_num):
start = i*batch_size
end = (i+1)*batch_size
xi = X_b[start:end]
yi = y[start:end]
gradients = 1/batch_size * xi.T.dot(xi.dot(theta)-yi)
print(a)
learning_rate = a
theta = theta - learning_rate * gradients
print(theta)
- 執行結果展示:
5.4 Mini-batch梯度算法優化: 學習率衰減
在做Mini-batch的時候,因爲噪聲的原因,可能訓練結果不是收斂的,而是在最低點周圍晃動,如果我們要解決這個問題,那我們就需要減少學習率,讓他在儘量小的範圍內晃動
1 epoch = 1 次遍歷所有的數據
- 學習率衰減公式:
- 實現代碼
import numpy as np
import random
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# print(X_b)
n_epochs = 500
t0, t1 = 5, 50
m = 100
num = [i for i in range(100)]
def learning_schedule(t):
return float(t0) / (t + t1)
theta = np.random.randn(2, 1)
batch_num = 5
batch_size = m // 5
# epoch 是輪次的意思,意思是用m個樣本做一輪迭代
for epoch in range(n_epochs):
# 生成100個不重複的隨機數
for i in range(batch_num):
start = i*batch_size
end = (i+1)*batch_size
xi = X_b[start:end]
yi = y[start:end]
gradients = 1/batch_size * xi.T.dot(xi.dot(theta)-yi)
learning_rate = learning_schedule(epoch*m + i)
theta = theta - learning_rate * gradients
print(theta)
- 執行結果展示:
6 特徵和多項式迴歸
6.1 過擬合的問題
過擬合的問題出現在變量(θ)過多的時候,這時候我們沒有更多的數據去擬合模型,雖然損失函數的值基本接近於0。
6.2 過擬合的解決方法:
- 減少特徵的數量(一般不用)
1)手動選擇特徵數
2)模型選擇 - 正則化(特徵縮放)
保留所有特徵,但是減少量級或者參數θ_j的大小
6.2 特徵縮放
房價預測時, 假設我們不知道房屋面積,但是知道房屋的長寬。
- 模型設計:
hθ(x) = θ0 + θ1 x 房屋的長度 + θ2 x 房屋的寬度 - 特徵未縮放圖形展示
- 特徵縮放圖形展示
注:如果我們採用多項式迴歸模型,在運行梯度下降算法前,特徵縮放非常有必要。
6.3 正則化
- 如何不想要theta3和theta4?
首先, 我們可以在損失函數中,加入關於theta3和theta4的項, 迫使若損失函數想要最小化, 必須讓theta3和theta4儘可能的小。
然後正則化, 公式如下圖:
6.4 L1 正則和 L2 正則的區別
- L1 會趨向於減少特徵值
- L2 會趨向於保留特徵值
7 正則化算法與代碼實現
7.1 Ridge(嶺)迴歸
7.1.1 算法理解
7.1.2 實現公式
7.1.3 代碼實現
- 兩種實現嶺迴歸的方法:
"""
嶺迴歸
方法一: 嶺迴歸運用了L2正則化
"""
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.linear_model import SGDRegressor
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
# alpha是懲罰項裏的alpha, solver處理數據的方法,auto是根據數據自動選擇,svd是解析解,sag就是隨機梯度下降
ridge_reg = Ridge(alpha=1, solver='auto')
# 學習過程
ridge_reg.fit(X, y)
# 預測
print(ridge_reg.predict([[1.5], [2], [2.5]]))
# 打印截距
print(ridge_reg.intercept_)
# 打印係數
print(ridge_reg.coef_)
"""
方法二: 嶺迴歸和sgd & penalty=2是等價的
"""
sgd_reg = SGDRegressor(penalty='l2')
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict([[1.5], [2], [2.5]]))
# 打印截距
print("W0=", sgd_reg.intercept_)
# 打印係數
print("W1=", sgd_reg.coef_)
7.2 Lasso(拉索)迴歸
7.2.1 算法理解
7.2.2 實現公式
7.2.3 代碼實現
"""
Lasso 迴歸
Lasso用的是l1的正則化
"""
import numpy as np
from sklearn.linear_model import Lasso
from sklearn.linear_model import SGDRegressor
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
lasso_reg = Lasso(alpha=0.15)
lasso_reg.fit(X, y)
print(lasso_reg.predict([[1.5]]))
print(lasso_reg.coef_)
sgd_reg = SGDRegressor(penalty='l1', n_iter=1000)
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict([[1.5]]))
print(sgd_reg.coef_)
7.3 Elastic Net迴歸
7.3.1 算法理解
7.3.2 實現公式
7.3.3 代碼實現
import numpy as np
from sklearn.linear_model import ElasticNet
X = 2 * np.random.rand(100, 1)
Y = 4 + 3 * X + np.random.randn(100, 1)
elastic_reg = ElasticNet(alpha=0.15, l1_ratio=0.5)
elastic_reg.fit(X, Y)
print(elastic_reg.predict([[1.5]]))
print(elastic_reg.coef_)
print(elastic_reg.intercept_)
from sklearn.linear_model import SGDRegressor
elastic_reg = SGDRegressor(penalty='elasticnet')
elastic_reg.fit(X, Y)
print(elastic_reg.predict([[1.5]]))
print(elastic_reg.coef_)
8 正規方程和梯度下降比較
梯度下降:
- 需要選擇合適的α
- 需要多次迭代
- 當n很大時,效果很好
正規方程:
- 不需要選擇學習率a
- 不需要迭代
- 需要計算X的轉置乘X整體的逆
- 當n很大時,計算很慢
總結:根據經驗,當特徵數量到10000的時候,是會換成梯度下降比較好
8.1 多項式迴歸的梯度下降代碼
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
# 1). 數據準備;
# 樣本數
m = 100
X = 6 * np.random.randn(m, 1) - 3
Y = 0.5 * X ** 2 + X + 2 + np.random.randn(m, 1)
# 2). 處理
# 2-1). 將一個高階方程轉化爲一個一階方程;(多元線性迴歸)
# degree:用幾維處理數據;
poly_features = PolynomialFeatures(degree=2, include_bias=False)
# fit_transform === fit() + transform(), 其中transform就是用來做歸一化的;
X_poly = poly_features.fit_transform(X, Y)
# 2-2). 處理一階方程
line_reg = LinearRegression()
line_reg.fit(X_poly, Y)
print(line_reg.coef_)
print(line_reg.intercept_)
8.2 不同維度繪製的圖形
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
# 1). 數據準備;
# 樣本數
m = 100
X = 6 * np.random.randn(m, 1) - 3
Y = 7 * X ** 2 + 5 *X + 2 + np.random.randn(m, 1)
# plt.plot(X, Y, 'b.')
# plt.show()
# 設置圖像維度及線條的字體顯示
d = {1: 'g-', 2: 'r.', 10: 'y*'}
# d = {2: 'g-'}
for i in d:
# 2). 處理
# 2-1). 將一個高階方程轉化爲一個一階方程;(多元線性迴歸)
# degree:用幾維處理數據;
poly_features = PolynomialFeatures(degree=i, include_bias=False)
# fit_transform === fit() + transform(), 其中transform就是用來做歸一化的;
X_poly = poly_features.fit_transform(X)
print(X_poly)
# 2-2). 處理一階方程
line_reg = LinearRegression()
line_reg.fit(X_poly, Y)
print(line_reg.coef_)
print(line_reg.intercept_)
y_predict = line_reg.predict(X_poly)
plt.plot(X_poly[:, 0], y_predict, d[i])
plt.show()