機器學習(四)-多變量線性迴歸

1 多變量線性迴歸應用場景

目前爲止,咱們探討了單變量/特徵的迴歸模型,如今咱們對房價模型增長更多的特徵,例如房間數樓層等,構成一個含有多個變量的模型.。python

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]

在這裏插入圖片描述例如:dom

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 梯度降低法遇到的問題

梯度降低算法收斂所須要的迭代次數根據模型的不一樣而不一樣,咱們不能提早預知,咱們能夠繪製迭代次數和代價函數的圖表來觀測算法在什麼時候趨於收斂。
在這裏插入圖片描述
梯度降低算法的每次迭代受到學習率的影響,spa

  • 若是學習率太小,則達到收斂所需的迭代次數會很是高;
  • 若是學習率過大,每次迭代可能不會減少代價函數,可能會越過局部最小值致使沒法收斂。

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()