機器學習3- 一元線性回歸+Python實現

  • 2020 年 3 月 31 日
  • 筆記

1. 線性模型

給定 (d) 個屬性描述的示例 (boldsymbol{x} = (x_1; x_2; …; x_d)),其中 (x_i)(boldsymbol{x}) 在第 (i) 個屬性上的取值,線性模型linear model)試圖學得一個通過屬性的線性組合來進行預測的函數,即:

[f(boldsymbol{x}) = w_1x_1 + w_2x_2 + … + w_dx_d +b tag{1.1} ]

使用向量形式為:

[f(boldsymbol{x}) = boldsymbol{w}^Tboldsymbol{x}+b tag{1.2} ]

其中 (boldsymbol{w} = (w_1;w_2;…;w_d)),表達了各屬性在預測中的重要性。

2. 線性回歸

給定數據集 (D = lbrace(boldsymbol{x}_1,{y}_1), (boldsymbol{x}_2,{y}_2), …, (boldsymbol{x}_m,{y}_m)rbrace),其中 (boldsymbol{x}_i = (x_{i1}; x_{i2}; …; x_{id}))(y_i in mathbb{R})線性回歸linear regression)試圖學得一個能儘可能準確地預測真實輸出標記的線性模型,即:

[f(boldsymbol{x}_i) = boldsymbol{w}^Tboldsymbol{x}_i+b text{,使得} f(boldsymbol{x}_i) simeq y_itag{1.3} ]

2.1 一元線性回歸

先只考慮輸入屬性只有一個的情況,(D = lbrace({x}_1,{y}_1), ({x}_2,{y}_2), …, ({x}_m,{y}_m)rbrace)(x_i in mathbb{R})。對離散屬性,若屬性值存在order)關係,可通過連續化將其轉化為連續值。

如」高度「屬性的取值「高」、「中」、「低」,可轉化為({1.0, 0.5, 0.0})

若不存在序關係,則假定有 (k) 種可能的屬性值,將其轉化為 (k) 維向量。

如「瓜類」屬性的取值有「冬瓜」、「西瓜」、「南瓜」,可轉化為 ((0,0,1),(0,1,0),(1,0,0))

線性回歸試圖學得:

[f(x_i) = wx_i+btext{,使得}f(x_i)simeq y_i tag{1.4} ]

為使 (f(x_i)simeq y_i),即:使 (f(x))(y) 之間的差別最小化。
考慮回歸問題的常用性能度量——均方誤差(亦稱平方損失(square loss)),即讓均方誤差最小化:

[begin{aligned} (w^*,b^*) = underset{(w,b)}{arg min}sum_{i=1}^m(f(x_i)-y_i)^2 \ = underset{(w,b)}{arg min}sum_{i=1}^m(y_i-wx_i-b)^2 end{aligned} tag{1.5} ]

(w^*,b^*) 表示 (w)(b) 的解。
均方誤差對應了歐幾里得距離,簡稱歐氏距離(Euclidean distance)。
基於均方誤差最小化來進行模型求解的方法稱為最小二乘法least square method)。在線性回歸中,就是試圖找到一條直線,使得所有樣本到直線上的歐氏距離之和最小。

下面需要求解 (w)(b) 使得 (E_{(w,b)} = sumlimits_{i=1}^m(y_i-wx_i-b)^2) 最小化,該求解過程稱為線性回歸模型的最小二乘參數估計parameter estimation)。

(E_{(w,b)}) 為關於 (w)(b) 的凸函數,當它關於 (w)(b) 的導數均為 (0) 時,得到 (w)(b) 的最優解。將 (E_{(w,b)}) 分別對 (w)(b) 求導數得:

[frac{partial{E_{(w,b)}}}{partial(w)} = 2Big(wsum_{i=1}^m x_i^2 – sum_{i=1}^m (y_i-b)x_iBig) tag{1.6} ]

[frac{partial{E_{(w,b)}}}{partial(b)} = 2Big(mb – sum_{i=1}^m (y_i-wx_i)Big) tag{1.7} ]

令式子 (1.6) 和 (1.7) 為 (0) 得到 (w)(b) 的最優解的閉式(closed-form)解:

[w = frac{sum_limits{i=1}^m y_i(x_i-overline{x})}{sumlimits_{i=1}^m x_i^2 – frac{1}{m}Big(sumlimits_{i=1}^m x_iBig)^2} tag{1.8} ]

[b = frac{1}{m}sum_{i=1}^m (y_i-wx_i) tag{1.9} ]

其中 (overline{x} = frac{1}{m}sumlimits_{i=1}^m x_i)(x) 的均值。

3. 一元線性回歸的Python實現

現有如下訓練數據,我們希望通過分析披薩的直徑與價格的線性關係,來預測任一直徑的披薩的價格。

其中 Diameter 為披薩直徑,單位為「英寸」;Price 為披薩價格,單位為「美元」。

3.1 使用 stikit-learn

3.1.1 導入必要模組

import matplotlib.pyplot as plt  import numpy as np  import pandas as pd  from sklearn.linear_model import LinearRegression  

3.1.2 使用 Pandas 載入數據

pizza = pd.read_csv("pizza.csv", index_col='Id')  pizza.head()  # 查看數據集的前5行  

3.1.3 快速查看數據

我們可以使用 matplotlib 畫出數據的散點圖,x 軸表示披薩直徑,y 軸表示披薩價格。

def runplt():      plt.figure()      plt.title("Pizza price plotted against diameter")      plt.xlabel('Diameter')      plt.ylabel('Price')      plt.grid(True)      plt.xlim(0, 25)      plt.ylim(0, 25)      return plt    dia = pizza.loc[:,'Diameter'].values  price = pizza.loc[:,'Price'].values  print(dia)  print(price)  plt = runplt()  plt.plot(dia, price, 'k.')  plt.show()  
[ 6  8 10 14 18]  [ 7.   9.  13.  17.5 18. ]  

3.1.4 使用 stlearn 創建模型

model = LinearRegression()  # 創建模型  X = dia.reshape((-1,1))  y = price  model.fit(X, y)  # 擬合    X2 = [[0], [25]] # 取兩個預測值  y2 = model.predict(X2)  # 進行預測  print(y2)  # 查看預測值    plt = runplt()  plt.plot(dia, price, 'k.')  plt.plot(X2, y2, 'g-')  # 畫出擬合曲線  plt.show()  
[ 1.96551724 26.37284483]  

這裡 fit()方法學得了一元線性回歸模型 (f(x) = wx+b),這裡 (x) 指披薩的直徑,(f(x)) 為預測的披薩的價格。

fit() 的第一個參數 X 為 shape(樣本個數,屬性個數) 的數組或矩陣類型的參數,代表輸入空間;
第二個參數 y 為 shape(樣本個數,) 的數組類型的參數,代表輸出空間。

3.1.5 模型評估

成本函數(cost function)也叫損失函數(lost function),用來定義模型與觀測值的誤差。

模型預測的價格和訓練集數據的差異稱為訓練誤差training error)也稱殘差residuals)。

plt = runplt()  plt.plot(dia, price, 'k.')  plt.plot(X2, y2, 'g-')    # 畫出殘差  yr = model.predict(X)  for index, x in enumerate(X):      plt.plot([x, x], [y[index], yr[index]], 'r-')    plt.show()  

根據最小二乘法,要得到更高的性能,就是讓均方誤差最小化,而均方誤差就是殘差平方和的平均值。

print("均方誤差為: %.2f" % np.mean((model.predict(X)-y) ** 2))  
均方誤差為: 1.75  

3.2 手動實現

3.2.1 計算 w 和 b

(w)(b) 的最優解的閉式(closed-form)解為:

[w = frac{sum_limits{i=1}^m y_i(x_i-overline{x})}{sumlimits_{i=1}^m x_i^2 – frac{1}{m}Big(sumlimits_{i=1}^m x_iBig)^2} tag{1.8} ]

[b = frac{1}{m}sum_{i=1}^m (y_i-wx_i) tag{1.9} ]

其中 (overline{x} = frac{1}{m}sumlimits_{i=1}^m x_i)(x) 的均值。

下面使用 Python 計算 (w)(b) 的值:

w = np.sum(price * (dia - np.mean(dia))) / (np.sum(dia**2) - (1/dia.size) * (np.sum(dia))**2)  b = (1 / dia.size) * np.sum(price - w * dia)  print("w = %fnb = %f" % (w, b))    y_pred = w * dia + b    plt = runplt()  plt.plot(dia, price, 'k.')  # 樣本點  plt.plot(dia, y_pred, 'b-')  # 手動求出的線性回歸模型  plt.plot(X2, y2, 'g-.')  # 使用LinearRegression.fit()求出的模型  plt.show()  
w = 0.976293  b = 1.965517  

可以看到兩條直線重合,我們求出的回歸模型與使用庫求出的回歸模型相同。

3.2.2 功能封裝

將上述程式碼封裝成類:

class LinearRegression:      """      擬合一元線性回歸模型        Parameters      ----------      x : shape 為(樣本個數,)的 numpy.array          只有一個屬性的數據集        y : shape 為(樣本個數,)的 numpy.array          標記空間        Returns      -------      self : 返回 self 的實例.      """      def __init__(self):          self.w = None          self.b = None        def fit(self, x, y):          self.w = np.sum(y * (x - np.mean(x))) / (np.sum(x**2) - (1/x.size) * (np.sum(x))**2)          self.b = (1 / x.size) * np.sum(y - self.w * x)          return self        def predict(self, x):          """          使用該線性模型進行預測            Parameters          ----------          x : 數值 或 shape 為(樣本個數,)的 numpy.array              屬性值            Returns          -------          C : 返回預測值          """          return self.w * x + self.b  

使用:

# 創建並擬合模型  model = LinearRegression()  model.fit(dia, price)    x2 = np.array([0, 25])  # 取兩個預測值  y2 = model.predict(x2)  # 進行預測  print(y2)  # 查看預測值    runplt()  plt.plot(dia, price, 'b.')  plt.plot(x2, y2, 'y-')  # 畫出擬合  plt.show()  
[ 1.96551724 26.37284483]  


此文原創禁止轉載,轉載文章請聯繫部落客並註明來源和出處,謝謝!
作者: Raina_RLN https://www.cnblogs.com/raina/