Python機器學習的練習一:簡單線性迴歸
檢查資料
在練習的第一部分,我們的任務是利用簡單的線性迴歸去預測食品交易的利潤。假設你是一個餐廳的CEO,最近考慮在其他城市開一家新的分店。連鎖店已經在各個城市有交易,並且你有各個城市的收益和人口資料,你想知道城市的人口對一個新的食品交易的預期利潤影響有多大。
首先檢查“ex1data1”檔案中的資料。“txt”在“我的儲存庫”的“資料”目錄中。首先匯入一些庫。
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
現在開始執行,使用Pandas把資料載入到資料幀裡,並且使用“head”函式顯示前幾行。
path= os.getcwd()+ 'dataex1data1.txt'
data= pd.read_csv(path, header=None, names=['Population','Profit'])
data.head()
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 |
Pandas提供的另外一個有用的函式是”describe”函式,它能在資料集上計算一些基本統計資料,這有助於在專案的探索性分析階段獲得資料的“feel”。
data.describe()
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 |
檢查有相關的統計資料可能會有幫助,但有時需要找到方法使它視覺化。這個資料集只有一個因變數,我們可以把它放到散點圖中以便更好地瞭解它。我們可以使用pandas為它提供的“plot”函式,這實際上只是matplotlib的一個包裝器。
data.plot(kind='scatter', x='Population', y='Profit', figsize=(12,8))
我們可以清楚地看到,隨著城市規模的增加,利潤呈線性增長。現在讓我們進入有趣的部分——從零開始實現python中的線性迴歸演算法。
實現簡單的線性迴歸
線性迴歸是建立因變數和一個或多個自變數之間關係的一種方法(如果只有一個自變數就是簡單線性迴歸;如果是多個自變數就是多重線性迴歸)。我們試圖使用引數theta建立資料X的線性模型,它描述了資料的方差,給出新的資料點,我們可以在不知道實際結果的情況下準確地預測。
在實現過程中,我們使用叫做梯度下降的優化技術尋找引數theta。如果你熟悉線性迴歸,你可能會意識到有另一種方法可以找到線性模型的最優引數,就是做“正態方程”,它可以用一系列矩陣運算來解決這個問題。然而,這種方法的問題就是在大資料集中不能很好地擴充套件,相比之下,我們可以使用梯度下降和其他優化方法的變體來擴充套件到無限大小的資料集,因此對於機器學習問題,梯度下降更實用。
理論知識已經足夠了,下面我們寫一些程式碼。我們首先要寫的就是成本函式,成本函式通過計算模型引數和實際資料點之間的誤差來計算模型預測的誤差,從而評估模型的質量。例如,如果給定城市的人口數量是4,但是我們預測是7,我們的誤差就是 (7-4)^2 = 3^2 = 9(假設為L2或“最小二乘法”損失函式)。我們為X中的每個資料點執行此操作,並對結果求和以獲取成本。下面是函式:
def computeCost(X, y, theta):
inner= np.power(((X* theta.T)- y),2)
return np.sum(inner)/ (2 * len(X))
注意,這裡沒有迴圈。我們利用numpy的linear algrebra功能將結果計算為一系列矩陣運算。這比不優化的“for”迴圈的效率要高得多。
為了使這個成本函式與我們上面建立的pandas資料框架無縫對接,我們需要做一些操作。首先,在開始插入一列1s的資料幀使矩陣運算正常工作。然後把資料分離成自變數X和因變數y。
# append a ones column to the front of the data set
data.insert(0,'Ones',1)
# set X (training data) and y (target variable)
cols= data.shape[1]
X= data.iloc[:,0:cols-1]
y= data.iloc[:,cols-1:cols]
最後把資料框架轉換為numpy矩陣並例項化引數matirx。
# convert from data frames to numpy matrices
X= np.matrix(X.values)
y= np.matrix(y.values)
theta= np.matrix(np.array([0,0]))
在除錯矩陣運算時要檢視正在處理的矩陣的形狀。矩陣乘法看起來像(i x j)*(j x k)=(i x k),其中i、j和k是矩陣相對維度的形狀。
X.shape, theta.shape, y.shape
((97L, 2L), (1L, 2L), (97L, 1L))
除錯一下成本函式。引數已經被初始化為0,所以解不是最優的,但是我們可以看看它是否有效。
computeCost(X, y, theta)
32.072733877455676
目前為止一切都很順利。現在我們需要使用練習文字中定義的更新規則來定義一個函式,來對引數theta執行梯度下降。這是梯度下降的函式:
def gradientDescent(X, y, theta, alpha, iters):
temp= np.matrix(np.zeros(theta.shape))
parameters= int(theta.ravel().shape[1])
cost= np.zeros(iters)
for iin range(iters):
error= (X* theta.T)- y
for jin range(parameters):
term= np.multiply(error, X[:,j])
temp[0,j]= theta[0,j]- ((alpha/ len(X))* np.sum(term))
theta= temp
cost[i]= computeCost(X, y, theta)
return theta, cost
梯度下降的就是計算出每一個迭代的誤差項的梯度,以找出適當的方向來移動引數向量。換句話說,就是計算對引數的修改以減少錯誤,從而使我們的解決方案更接近最佳解決方案。
我們再一次依賴於numpy和線性代數求解,你可能注意到我的實現不是100%的優化,事實上,有完全去除內迴圈和一次性更新所有引數的方法。我把它留給讀者去完成。
現在我們已經有了一種評估解決方案的方法,並且找到一個好的解決方案,把它應用到我們的資料集中。
# initialize variables for learning rate and iterations
alpha= 0.01
iters= 1000
# perform gradient descent to "fit" the model parameters
g, cost= gradientDescent(X, y, theta, alpha, iters)
g
矩陣x([[-3.24140214, 1.1272942 ]])
注意我們已經初始化了一些新的變數。梯度下降函式中有叫做alpha和iters的引數。alpha是學習速率-它是引數更新規則中的一個因素,它幫助決定演算法收斂到最優解的速度。iters是迭代次數。沒有嚴格的規則去規定如何初始化這些引數,但是通常會涉及到試錯法。
現在有一個引數向量描述資料集的最優線性模型,一個快速評估迴歸模型的方法就是觀察資料集上的解決方案的總誤差:
computeCost(X, y, g)
4.5159555030789118
這要比32好很多。
檢視結果
我們將使用matplotlib來視覺化我們的解決方案。我們在資料的散點圖上覆蓋一條線表示我們的模型,看它是否合適。我們使用numpy的“linspace”函式在我們的資料範圍內建立一系列均勻間隔的點,然後用我們的模型“評估”這些點,看預期的利潤會是多少。我們把它變成線形圖。
x= np.linspace(data.Population.min(), data.Population.max(),100)
f= g[0,0]+ (g[0,1]* x)
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')
我們的解決方案看起來是資料集的最優線性模型。梯度體系函式會在每個訓練迭代中輸出一個成本向量,我們可以出繪製出線形圖。
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')
成本一直在降低——這就是凸優化問題的一個示例。如果你要繪製問題的整個解決方案空間,它看起來會像一個碗的形狀,“盆地”表示最優解。
本文為編譯文章,作者John Wittenauer,原網址為
http://www.johnwittenauer.net/machine-learning-exercises-in-python-part-1/