【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(θ)。一種方法是使用批量梯度下降演算法。在批量梯度下降,每個迭代執行update
,同時更新所有的j。
def computeCost(X, y, theta):
inner = np.power(((X * theta.T) - y), 2)
return np.sum(inner) / (2 * len(X))
每一步的梯度下降法,引數接近最優值,達到成本最低J(θ)。
Note:我們將每個示例作為一行儲存在X矩陣中。考慮截距項(),我們新增一個額外的第一列X作為,當作另一個“特性”。
在訓練集中新增一列,以便我們可以使用向量化的解決方案來計算代價和梯度。
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(批量梯度下降)
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(正規方程)
在課程視訊中,我們學過線性迴歸的封閉解是:
使用這個公式不需要進行任何特徵縮放,將在一次計算中得到一個精確的解:沒有像梯度下降法那樣的“直到收斂為止的迴圈”。雖然你不需要擴充套件功能,我們仍然需要對X矩陣新增一個列全為1的項, 讓X矩陣有一個截距項()。
正規方程是通過求解下面的方程來找出使得代價函式最小的引數的:。
假設我們的訓練集特徵矩陣為 X(包含了=1)並且我們的訓練集結果為向量 y,則利用正規方程解出向量 。
上標T代表矩陣轉置,上標-1 代表矩陣的逆。設矩陣,則:。
梯度下降與正規方程的比較:
梯度下降:需要選擇學習率α,需要多次迭代,當特徵數量n大時也能較好適用,適用於各種型別的模型
正規方程:不需要選擇學習率α,一次計算得出,需要計算,如果特徵數量n較大則運算代價大,因為矩陣逆的計算時間複雜度為,通常來說當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]])