補充:特征歸一化,意義、方法、使用場景
一:單變量線性回歸
(一)導入需要使用的包
import numpy as np import pandas as pd import matplotlib.pyplot as plt
(二)導入數據集
注意:一定要將數據文件放在和程序同一個文件夾中,否則要使用絕對路徑訪問文件。
將csv文件讀入並轉化為數據框DataFrame形式,需要知道路徑,指定哪一行作為表頭,默認為0,即甚至第一行作為表頭,若沒有表頭,則設置參數header=None,並主動指定列的名稱,用列表表示,來添加列名。
6.1101,17.592 5.5277,9.1302 8.5186,13.662 7.0032,11.854 5.8598,6.8233 8.3829,11.886 7.4764,4.3483 8.5781,12 6.4862,6.5987 5.0546,3.8166 5.7107,3.2522 14.164,15.505 5.734,3.1551 8.4084,7.2258 5.6407,0.71618 5.3794,3.5129 6.3654,5.3048 5.1301,0.56077 6.4296,3.6518 7.0708,5.3893 6.1891,3.1386 20.27,21.767 5.4901,4.263 6.3261,5.1875 5.5649,3.0825 18.945,22.638 12.828,13.501 10.957,7.0467 13.176,14.692 22.203,24.147 5.2524,-1.22 6.5894,5.9966 9.2482,12.134 5.8918,1.8495 8.2111,6.5426 7.9334,4.5623 8.0959,4.1164 5.6063,3.3928 12.836,10.117 6.3534,5.4974 5.4069,0.55657 6.8825,3.9115 11.708,5.3854 5.7737,2.4406 7.8247,6.7318 7.0931,1.0463 5.0702,5.1337 5.8014,1.844 11.7,8.0043 5.5416,1.0179 7.5402,6.7504 5.3077,1.8396 7.4239,4.2885 7.6031,4.9981 6.3328,1.4233 6.3589,-1.4211 6.2742,2.4756 5.6397,4.6042 9.3102,3.9624 9.4536,5.4141 8.8254,5.1694 5.1793,-0.74279 21.279,17.929 14.908,12.054 18.959,17.054 7.2182,4.8852 8.2951,5.7442 10.236,7.7754 5.4994,1.0173 20.341,20.992 10.136,6.6799 7.3345,4.0259 6.0062,1.2784 7.2259,3.3411 5.0269,-2.6807 6.5479,0.29678 7.5386,3.8845 5.0365,5.7014 10.274,6.7526 5.1077,2.0576 5.7292,0.47953 5.1884,0.20421 6.3557,0.67861 9.7687,7.5435 6.5159,5.3436 8.5172,4.2415 9.1802,6.7981 6.002,0.92695 5.5204,0.152 5.0594,2.8214 5.7077,1.8451 7.6366,4.2959 5.8707,7.2029 5.3054,1.9869 8.2934,0.14454 13.394,9.0551 5.4369,0.61705
path = 'ex1data1.txt' data = pd.read_csv(path,header=None,names=['Population','Profit']) data.head() #數據預覽

data.describe() #查看數據描述,包括計數,平均值,標准差,最大最小值,分位數...

(三)數據可視化
data.plot(kind='scatter',x='Population',y="Profit",figsize=(12,8)) plt.show()

由圖可知,數據集存在一定的線性關系。
(四)創建代價函數
首先,我們將創建一個以參數θ為特征函數的代價函數

![]()
def computeCost(X,y,theta): #輸入X是列向量,y也是列向量,theta是行向量 inner = np.power(((X*theta.T)-y),2) #X乘以theta的轉置就是假設函數 return np.sum(inner)/(2*len(X)) #求得代價函數
舉例:


補充:numpy中關於*和dot的區別
對於上面的X*theta.T,我們使用了“*”運算符,進行了矩陣乘法操作。但是我們如果將*當作矩陣乘法,那么我們必須保證兩邊操作數類型是matrix矩陣類型。另外dot也可以實現矩陣乘法,但是它要求傳參是ndarray類型,並且兩個數組保持第一個矩陣列數等於第二個矩陣行數。
舉例:
X_3 = np.array([[1,2],[3,4],[5,6]]) tt = np.array([[2,3]]) print(X_3.dot(tt.T)) print(np.matrix(X_3)*np.matrix(tt).T)
(五)雖說我們是單變量線性回歸,但是我們還是存在一個x_0,全為1,使得我們存在一個常數θ_0
因此,我們需要在訓練集中添加一列x_0,以便我們可以使用向量化的解決方案來計算代價和梯度。在訓練集左側插入一列全為1的列,以便計算。
即設置x_0=1,loc=0,name=ones,values=1.
data.insert(0,'Ones',1)

(六)進行變量初始化
cols = data.shape[1] #獲取列數 shape[0]是行數 X = data.iloc[:,0:cols-1] #獲取數據集 y = data.iloc[:,cols-1:cols] #獲取標簽值---目標變量
觀察X訓練集和y目標變量是否正確:
原始數據data: X數據集: y目標變量:

(七)代價函數中傳參X,y應該是numpy矩陣,才可以直接計算
由(六)中獲取的數據類型是DataFrame類型,因此,我們需要進行類型轉換。同時還需要初始化theta,即把theta所有元素都設置為0
X = np.matrix(X.values) y = np.matrix(y.values) theta = np.matrix(np.array([0,0])) #theta是一個(1,2)矩陣

代價函數測試:
computeCost(X,y,theta)
![]()
(八)批量梯度下降


當x_0=1時,兩個式子可以合並
def gradientDescennt(X,y,theta,alpha,iters): #iters是迭代次數 alpha是步長 temp = np.matrix(np.zeros(theta.shape)) #構建零值矩陣,暫存theta parameters = int(theta.ravel().shape[1]) #ravel計算需要求解的參數個數 功能將多維數組降至一維 cost = np.zeros(iters) #構建iters個0的數組 for i in range(iters): #進行迭代 error = (X*theta.T)-y #獲取差值 for j in range(parameters): #更新theta_j term = np.multiply(error,X[:,j]) #乘以x_i 因為x_0等於1,所以這個式包含theta_0,theta_1 temp[0,j] = theta[0,j] - (alpha/len(X))*np.sum(term) #更新theta_j theta = temp #更新全部theta值 cost[i] = computeCost(X,y,theta) #更新代價值 return theta, cost
這里設置:步長alpha = 0.01 迭代次數iters = 1000
g,cost = gradientDescennt(X,y,theta,alpha,iters) #獲取迭代后的theta值,和代價最小值 print(g,cost[-1]) #cost[-1]就是我們最后的最小代價值

(九)可以用我們擬合過的theta值---g,計算訓練模型的代價參數(可以省略)
computeCost(X,y,g)

(十)繪制線性模型以及數據,觀察擬合程度
#進行繪圖 x = np.linspace(data.Population.min(),data.Population.max(),100) #抽取100個樣本 f = g[0,0]+(g[0,1]*x) #線性函數,利用x抽取的等距樣本繪制線性直線 fig, ax = plt.subplots(figsize=(12,8)) #返回圖表以及圖表相關的區域,為空代表繪制區域為111--->一行一列圖表,選中第一個 ax.plot(x,f,'r',label="Prediction") #繪制直線 ax.scatter(data.Population,data.Profit,label='Training Data') #繪制散點圖 ax.legend(loc=4) #顯示標簽位置 給圖加上圖例 'lower right' : 4, ax.set_xlabel("Population") ax.set_ylabel("Profit") ax.set_title("Predicted Profit vs Population Size") plt.show()

繪制代價圖---代價總是降低的:
fig, ax = plt.subplots() #返回圖表以及圖表相關的區域,為空代表繪制區域為111--->一行一列圖表,選中第一個 ax.plot(np.arange(iters),cost,'r') ax.set_xlabel('Iterations') ax.set_ylabel('Cost') ax.set_title("Error vs. Training Epoch") plt.show()

(十一)全部代碼
import numpy as np import pandas as pd import matplotlib.pyplot as plt def computeCost(X,y,theta): #輸入X是列向量,y也是列向量,theta是行向量 inner = np.power(((X*theta.T)-y),2) #X乘以theta的轉置就是假設函數 return np.sum(inner)/(2*len(X)) #求得代價函數 def gradientDescennt(X,y,theta,alpha,iters): #iters是迭代次數 temp = np.matrix(np.zeros(theta.shape)) #構建零值矩陣,暫存theta parameters = int(theta.ravel().shape[1]) #ravel計算需要求解的參數個數 功能將多維數組降至一維 cost = np.zeros(iters) #構建iters個0的數組 for i in range(iters): #進行迭代 error = (X*theta.T)-y #獲取差值 for j in range(parameters): #更新theta_j term = np.multiply(error,X[:,j]) #乘以x_i 因為x_0等於1,所以這個式包含theta_0,theta_1 temp[0,j] = theta[0,j] - (alpha/len(X))*np.sum(term) #更新theta_j theta = temp #更新全部theta值 cost[i] = computeCost(X,y,theta) #更新代價值 return theta, cost path = 'E:\Python\MachineLearning\ex1data1.txt' data = pd.read_csv(path,header=None,names=['Population','Profit']) data.insert(0,'Ones',1) cols = data.shape[1] #獲取列數 shape[0]是行數 X = data.iloc[:,0:cols-1] #獲取數據集 y = data.iloc[:,cols-1:cols] #獲取標簽值---目標變量 X = np.matrix(X.values) y = np.matrix(y.values) theta = np.matrix(np.array([0,0])) alpha = 0.01 iters = 1000 g,cost = gradientDescennt(X,y,theta,alpha,iters) #獲取迭代后的theta值,和代價最小值 #進行繪圖 fig, ax = plt.subplots() #返回圖表以及圖表相關的區域,為空代表繪制區域為111--->一行一列圖表,選中第一個 ax.plot(np.arange(iters),cost,'r') ax.set_xlabel('Iterations') ax.set_ylabel('Cost') ax.set_title("Error vs. Training Epoch") plt.show() # x = np.linspace(data.Population.min(),data.Population.max(),100) #抽取100個樣本 # f = g[0,0]+(g[0,1]*x) #線性函數,利用x抽取的等距樣本繪制線性直線 # # fig, ax = plt.subplots() #返回圖表以及圖表相關的區域,為空代表繪制區域為111--->一行一列圖表,選中第一個 # ax.plot(x,f,'r',label="Prediction") #繪制直線 # ax.scatter(data.Population,data.Profit,label='Training Data') #繪制散點圖 # ax.legend(loc=4) #顯示標簽位置 # ax.set_xlabel("Population") # ax.set_ylabel("Profit") # ax.set_title("Predicted Profit vs Population Size") # plt.show() # print(g,cost[-1]) # print(computeCost(X,y,g)) # data.plot(kind='scatter',x='Population',y="Profit",figsize=(12,8)) # plt.show()
二:多變量線性回歸
該練習包括一個房屋價格數據集,其中包含兩個變量(房屋大小、卧室數量)和目標(房子價格)。
2104,3,399900 1600,3,329900 2400,3,369000 1416,2,232000 3000,4,539900 1985,4,299900 1534,3,314900 1427,3,198999 1380,3,212000 1494,3,242500 1940,4,239999 2000,3,347000 1890,3,329999 4478,5,699900 1268,3,259900 2300,4,449900 1320,2,299900 1236,3,199900 2609,4,499998 3031,4,599000 1767,3,252900 1888,2,255000 1604,3,242900 1962,4,259900 3890,3,573900 1100,3,249900 1458,3,464500 2526,3,469000 2200,3,475000 2637,3,299900 1839,2,349900 1000,1,169900 2040,4,314900 3137,3,579900 1811,4,285900 1437,3,249900 1239,3,229900 2132,4,345000 4215,4,549000 2162,4,287000 1664,2,368500 2238,3,329900 2567,4,314000 1200,3,299000 852,2,179900 1852,4,299900 1203,3,239500
(一)讀取數據
path = 'E:\Python\MachineLearning\ex1data2.txt' data = pd.read_csv(path,header=None,names=['Size','Bedrooms','Price'])

(二)特征歸一化(新增預處理步驟)
有時不同特征之間數組的絕對值差距比較大。10000+,0.000+導致數值較大的將數值較小的特征掩蓋掉,並且會影響算法收斂的速度。
這里采用標准差標准化: x =(x - u)/σ u是均值 σ是標准差
data = (data-data.mean())/data.std()
(三)其他步驟同一,需要修改維度
def computeCost(X,y,theta): #輸入X是列向量,y也是列向量,theta是行向量 inner = np.power(((X*theta.T)-y),2) #X乘以theta的轉置就是假設函數 return np.sum(inner)/(2*len(X)) #求得代價函數 def gradientDescennt(X,y,theta,alpha,iters): #iters是迭代次數 temp = np.matrix(np.zeros(theta.shape)) #構建零值矩陣,暫存theta parameters = int(theta.ravel().shape[1]) #ravel計算需要求解的參數個數 功能將多維數組降至一維 cost = np.zeros(iters) #構建iters個0的數組 for i in range(iters): #進行迭代 error = (X*theta.T)-y #獲取差值 for j in range(parameters): #更新theta_j term = np.multiply(error,X[:,j]) #乘以x_i 因為x_0等於1,所以這個式包含theta_0,theta_1 temp[0,j] = theta[0,j] - (alpha/len(X))*np.sum(term) #更新theta_j theta = temp #更新全部theta值 cost[i] = computeCost(X,y,theta) #更新代價值 return theta, cost
data.insert(0,'Ones',1) cols = data.shape[1] #獲取列數 shape[0]是行數 X = data.iloc[:,0:cols-1] #獲取數據集 y = data.iloc[:,cols-1:cols] #獲取標簽值---目標變量 X = np.matrix(X.values) y = np.matrix(y.values) theta = np.matrix(np.array([0,0,0])) alpha = 0.01 iters = 1000 g,cost = gradientDescennt(X,y,theta,alpha,iters) #獲取迭代后的theta值,和代價最小值
(四)查看代價函數收斂圖
#進行繪圖 fig, ax = plt.subplots() #返回圖表以及圖表相關的區域,為空代表繪制區域為111--->一行一列圖表,選中第一個 ax.plot(np.arange(iters),cost,'r') ax.set_xlabel('Iterations') ax.set_ylabel('Cost') ax.set_title("Error vs. Training Epoch") plt.show()

多變量也是隨着迭代次數的增加,他的訓練誤差也是逐漸減小。
三:補充正規方程求θ
(一)求解θ
正規方程是通過求解下面的方程來找出使得代價函數最小的參數的:

假設我們的訓練集特征矩陣為 X(包含了x_0=1)並且我們的訓練集結果為向量 y,則利用正規方程解出向量 θ:

上標T代表矩陣轉置,上標-1 代表矩陣的逆。

(二)梯度下降與正規方程的比較:
梯度下降:
需要選擇學習率α,需要多次迭代,當特征數量n大時也能較好適用,適用於各種類型的模型
正規方程:
不需要選擇學習率α,一次計算得出,需要計算
,如果特征數量n較大則運算代價大,因為矩陣逆的計算時間復雜度為O(n3),通常來說當n小於10000 時還是可以接受的,只適用於線性模型,不適合邏輯回歸模型等其他模型
![]()
# 正規方程 def normalEqn(X, y): theta = np.linalg.inv(X.T@X)@X.T@y#X.T@X等價於X.T.dot(X) return theta
final_theta2=normalEqn(X, y)#感覺和批量梯度下降的theta的值有點差距
final_theta2
梯度下降得到的結果是matrix([[-3.24140214, 1.1272942 ]])和上面得到的值有出入。
