1. 程式人生 > >【Andrew Ng】 機器學習Exercise1——Linear Regression

【Andrew Ng】 機器學習Exercise1——Linear Regression

1、單變數線性迴歸

在本部分練習中,您將使用一個變數實現線性迴歸,以預測食品卡車的利潤。假設你是一家連鎖餐廳的執行長,正在考慮在不同的城市開設一家新分店。這個連鎖店已經在不同的城市有了卡車,你可以從城市得到利潤和人口的資料。

您希望使用這些資料來幫助您選擇下一個要擴充套件到的城市。

檔案ex1data1.txt包含線性迴歸問題的資料集。第一列是一個城市的人口第二列是那個城市的食品卡車的利潤。利潤為負數表示虧損。

 

1.1 Plotting the Data

在開始任何任務之前,通過視覺化來理解資料通常是有用的。對於這個資料集,您可以使用散點圖來視覺化資料,因為它只有兩個屬性可以繪圖(利潤和人口)。(現實生活中你會遇到的許多其他問題都是多維的,不能用二維圖來表示。)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

path =  'ex1data1.txt'
data = pd.read_csv(path, header=None, names=['Population', 'Profit'])

data.head()
Out[1]: 
   Population   Profit
0      6.1101  17.5920
1      5.5277   9.1302
2      8.5186  13.6620
3      7.0032  11.8540
4      5.8598   6.8233

data.describe()
Out[2]: 
       Population     Profit
count   97.000000  97.000000
mean     8.159800   5.839135
std      3.869884   5.510262
min      5.026900  -2.680700
25%      5.707700   1.986900
50%      6.589400   4.562300
75%      8.578100   7.046700
max     22.203000  24.147000

看下資料長什麼樣子

data.plot(kind='scatter', x='Population', y='Profit', figsize=(12,8))
plt.show()

 

1.2 Gradient Descent

在這一部分中,您將符合線性迴歸引數θ資料集使用梯度下降法。

 

1.2.1 Update Equations(更新方程)

線性迴歸的目標是使成本函式最小化

J\left ( \theta \right ) = \frac{1}{2m} \sum \left ( h_{\theta }\left ( x^{\left ( i \right )} \right ) - y^{\left ( i \right )}\right )^{2}

假設h_{\theta }\left ( x \right )是由線性模型

h_{\theta }\left ( x \right ) = \theta ^{T}x = \theta _{0} + \theta _{1}x_{1}

回想一下,你的模型的引數是\theta _{j}值。這些值將最小化成本調整J(θ)。一種方法是使用批量梯度下降演算法。在批量梯度下降,每個迭代執行update

\theta _{j} : \theta _{j} - \alpha \frac{1}{2m}\sum_{i=1}^{m}\left ( h_{\theta }\left ( x^{\left ( i \right )} \right ) - y^{\left ( i \right )} \right )x_{j}^{i} ,同時更新所有\theta _{j}的j。

def computeCost(X, y, theta):
    inner = np.power(((X * theta.T) - y), 2)
    return np.sum(inner) / (2 * len(X))

每一步的梯度下降法,引數\theta _{j}接近最優值,達到成本最低J(θ)。

Note:我們將每個示例作為一行儲存在X矩陣中。考慮截距項(\theta _{0}),我們新增一個額外的第一列X作為\theta _{0},當作另一個“特性”。

在訓練集中新增一列,以便我們可以使用向量化的解決方案來計算代價和梯度。

data.insert(0, 'Ones', 1)

data.head()
Out[3]: 
   Ones  Population   Profit
0     1      6.1101  17.5920
1     1      5.5277   9.1302
2     1      8.5186  13.6620
3     1      7.0032  11.8540
4     1      5.8598   6.8233

區分訓練資料X和目標變數y

# set X (training data) and y (target variable)
cols = data.shape[1]
X = data.iloc[:,0:cols-1]#X是所有行,去掉最後一列
y = data.iloc[:,cols-1:cols]#X是所有行,最後一列

觀察下 X (訓練集) and y (目標變數)是否正確.

X.head()#head()是觀察前5行
Out[4]: 
   Ones  Population
0     1      6.1101
1     1      5.5277
2     1      8.5186
3     1      7.0032
4     1      5.8598

y.head()
Out[5]: 
    Profit
0  17.5920
1   9.1302
2  13.6620
3  11.8540
4   6.8233

代價函式是應該是numpy矩陣,所以我們需要轉換X和Y,然後才能使用它們。 我們還需要初始化theta。

theta 是一個(1,2)矩陣

X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array([0,0]))

theta
Out[6]: matrix([[0, 0]])

看下緯度

X.shape, theta.shape, y.shape
Out[7]: ((97, 2), (1, 2), (97, 1))

計算代價函式 (theta初始值為0).

computeCost(X, y, theta)
Out[8]: 32.072733877455676

 

1.2.2 Batch Gradient Descent(批量梯度下降)

\theta _{j} : \theta _{j} - \alpha \frac{\partial }{\partial \theta _{j}}J\left ( \theta \right )

def gradientDescent(X, y, theta, alpha, iters):
    temp = np.matrix(np.zeros(theta.shape))  #theta.shape 是一行兩列。生成一個一行兩列以0填充的矩陣
    parameters = int(theta.ravel().shape[1])  #ravel() 將多維陣列降位一維。得到具體引數數量(共有多少列)
    cost = np.zeros(iters)
    
    for i in range(iters):
        error = (X * theta.T) - y
        
        for j in range(parameters):
            term = np.multiply(error, X[:,j])  #multiply 陣列和矩陣對應位置相乘,輸出與相乘陣列/矩陣的大小一致
            temp[0,j] = theta[0,j] - ((alpha / len(X)) * np.sum(term))
            
        theta = temp
        cost[i] = computeCost(X, y, theta)
        
    return theta, cost

初始化一些附加變數 - 學習速率α和要執行的迭代次數。

alpha = 0.01  #學習率
iters = 1000  #迭代次數

現在讓我們執行梯度下降演算法來將我們的引數θ適合於訓練集。

g, cost = gradientDescent(X, y, theta, alpha, iters)

g
out[9]: matrix([[-3.24140214,  1.1272942 ]])

最後,我們可以使用我們擬合的引數計算訓練模型的代價函式(誤差)。

computeCost(X, y, g)
out[10]: 4.5159555030789118

現在我們來繪製線性模型以及資料,直觀地看出它的擬合。

x = np.linspace(data.Population.min(), data.Population.max(), 100)  ##linspace 在指定的間隔內返回均勻間隔的數字
f = g[0, 0] + (g[0, 1] * x)  #一次函式 f = a + bx

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.Population, data.Profit, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()

 

1.2.3 Visualize Cost Data(代價資料視覺化)

由於梯度方程式函式也在每個訓練迭代中輸出一個代價的向量,所以我們也可以繪製。

請注意,代價總是降低 - 這是凸優化問題的一個例子。

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iters), cost, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()

可以看到從第二輪代價資料變換很大,接下來平穩了

 

2、多變數線性迴歸

在這一部分中,您將使用多個變數實現線性迴歸來預測房價。假設你正在出售你的房子,你想知道一個好的市場價格是多少。一種方法是首先收集最近售出的房屋的資訊,並建立一個房價模型。

path =  'ex1data2.txt'
data2 = pd.read_csv(path, header=None, names=['Size', 'Bedrooms', 'Price'])
data2.head()

Out[11]: 
   Size  Bedrooms   Price
0  2104         3  399900
1  1600         3  329900
2  2400         3  369000
3  1416         2  232000
4  3000         4  539900

通過觀察價值,注意房子的大小差不多是臥室數量的1000倍。當特徵按數量級不同時,首先進行特徵縮放可以使梯度下降更快地收斂。

這個對於pandas來說很簡單

data2 = (data2 - data2.mean()) / data2.std()
data2.head()

Out[12]: 
       Size  Bedrooms     Price
0  0.130010 -0.223675  0.475747
1 -0.504190 -0.223675 -0.084074
2  0.502476 -0.223675  0.228626
3 -0.735723 -1.537767 -0.867025
4  1.257476  1.090417  1.595389

現在我們重複第1部分的預處理步驟,並對新資料集執行線性迴歸程式。

# add ones column
data2.insert(0, 'Ones', 1)

# set X (training data) and y (target variable)
cols = data2.shape[1]
X2 = data2.iloc[:,0:cols-1]
y2 = data2.iloc[:,cols-1:cols]

# convert to matrices and initialize theta
X2 = np.matrix(X2.values)
y2 = np.matrix(y2.values)
theta2 = np.matrix(np.array([0,0,0]))

# perform linear regression on the data set
g2, cost2 = gradientDescent(X2, y2, theta2, alpha, iters)

# get the cost (error) of the model
computeCost(X2, y2, g2)

Out[13]: 0.13070336960771892

我們也可以快速檢視這一個的訓練程序。

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iters), cost2, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()

我們也可以使用scikit-learn的線性迴歸函式,而不是從頭開始實現這些演算法。 我們將scikit-learn的線性迴歸演算法應用於第1部分的資料,並看看它的表現。

from sklearn import linear_model
model = linear_model.LinearRegression()
model.fit(X, y)

Out[14]: LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)

scikit-learn model的預測表現

x = np.array(X[:, 1].A1)
f = model.predict(X).flatten()

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.Population, data.Profit, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()

 

3、Normal Equations(正規方程)

在課程視訊中,我們學過線性迴歸的封閉解是:

\theta = \left ( X^{T}X \right )^{-1} X^{T} \vec{y}

使用這個公式不需要進行任何特徵縮放,將在一次計算中得到一個精確的解:沒有像梯度下降法那樣的“直到收斂為止的迴圈”。雖然你不需要擴充套件功能,我們仍然需要對X矩陣新增一個列全為1的項, 讓X矩陣有一個截距項(\theta _{0})。

正規方程是通過求解下面的方程來找出使得代價函式最小的引數的:\frac{\partial }{\partial \theta _{j}} J\left ( \theta _{j} \right ) = 0

假設我們的訓練集特徵矩陣為 X(包含了x_{0}=1)並且我們的訓練集結果為向量 y,則利用正規方程解出向量 \theta = \left ( X^{T}X \right )^{-1} X^{T}y 。

上標T代表矩陣轉置,上標-1 代表矩陣的逆。設矩陣A = X^{T}X,則:\left ( X^{T}X \right )^{-1} = A^{-1}

梯度下降與正規方程的比較:

梯度下降:需要選擇學習率α,需要多次迭代,當特徵數量n大時也能較好適用,適用於各種型別的模型

正規方程:不需要選擇學習率α,一次計算得出,需要計算\left ( X^{T} X\right )^{-1},如果特徵數量n較大則運算代價大,因為矩陣逆的計算時間複雜度為O\left ( n3 \right ),通常來說當n小於10000 時還是可以接受的,只適用於線性模型,不適合邏輯迴歸模型等其他模型

# 正規方程
def normalEqn(X, y):
    theta = np.linalg.inv([email protected])@[email protected]#[email protected]等價於X.T.dot(X)
    return theta
final_theta2=normalEqn(X, y)#感覺和批量梯度下降的theta的值有點差距
final_theta2

Out[15]: 
matrix([[-3.89578088],
        [ 1.19303364]])
#梯度下降得到的結果是matrix([[-3.89578088,  1.19303364]])