Andrew Ng經典機器學習課程的Python實現2
在上一篇文章中,我們討論了單變數和多變數線性迴歸的Python實現方法。現在我們講邏輯迴歸。大家要注意,如何克服過度擬合的問題,這將是討論的重點。
基礎知識
強烈建議你先看第3周的視訊 ofollow,noindex" target="_blank"> 講座 ,首先應該對Python系統有個基本的瞭解。在這裡,我們將研究一個在業界最廣泛應用的機器學習演算法。
邏輯迴歸
在這部分練習中,你將建立一個邏輯迴歸模型來預測一個學生是否能被大學錄取。
場景描述:
假設你是一個大學某系的招生負責人,想根據兩門考試的成績來確定每個申請者的錄取概率。你有以前的歷史資料,可以用它作為邏輯迴歸的訓練資料集。對於每一個訓練的例子,你有申請人兩門考試的分數和相應的錄取決策。你的工作是建立一個分類模型,然後根據這兩門考試的成績來預測申請者的錄取概率。
首先要載入必需的庫:
importnumpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.optimize as opt # more on this later
下一步,讀入資料 ( 在 第3周 裡找到 )
data = pd.read_csv('ex2data1.txt', header = None)
X = data.iloc[:,:-1]
y = data.iloc[:,2]
data.head()
因此,我們有兩個獨立的特徵和一個因變數。這裡的“0”表示申請人不能被錄取,而“1”則表示能被錄取。
資料視覺化
在開始執行任何學習演算法之前,如果可能的話,最好一直進行資料的視覺化工作。
mask = y == 1
adm = plt.scatter(X[mask][0].values, X[mask][1].values)
not_adm = plt.scatter(X[~mask][0].values, X[~mask][1].values)
plt.xlabel('Exam 1 score')
plt.ylabel('Exam 2 score')
plt.legend((adm, not_adm), ('Admitted', 'Not admitted'))
plt.show()
執行
在開始呼叫實際成本函式之前,請回想一下,邏輯迴歸的假設是利用了S形函式。讓我們首先定義S形函式:
S型函式
def sigmoid(x):
return 1/(1+np.exp(-x))
請注意,我們在這裡寫的是向量化的程式碼。因此,x是個標量,也是個向量,還是個張量,其實並不重要。當然,編寫和理解向量化的程式碼需要花費一些心思。不過,在去掉了迴圈部分之後,這會使程式碼更加的高效和通用。
成本函式
以下是我們實現邏輯迴歸成本函式的程式碼:
defcostFunction(theta, X, y):
J = (-1/m) * np.sum(np.multiply(y, np.log(sigmoid(X @ theta)))
+ np.multiply((1-y), np.log(1 - sigmoid(X @ theta))))
return J
請注意,我們在上面的成本函式中使用了S形函式。
有多種程式設計方法來實現成本函式,不過更重要的是底層的數學思想,還有我們把它轉化成程式碼的能力。
梯度函式
def gradient(theta, X, y):
return ((1/m) * X.T @ (sigmoid(X @ theta) - y))
我們一定要注意,雖然這個梯度看起來與線性迴歸的梯度相同,然而實際上公式是不一樣的,因為線性迴歸和邏輯迴歸有不同的假設函式定義。
以下是通過初始的引數來進行函式呼叫的程式碼。
(m, n) = X.shape
X = np.hstack((np.ones((m,1)), X))
y = y[:, np.newaxis]
theta = np.zeros((n+1,1)) # intializing theta with all zeros
J = costFunction(theta, X, y)
print(J)
上面的程式碼執行之後,會給我們J的輸出值是0.693。
使用fmin_tnc來學習引數
在前面的任務中,我們通過執行梯度下降的演算法來找到線性迴歸模型的最優引數,然後寫了一個成本函式,並且計算了它的梯度,最後執行了梯度下降的操作步驟。這一次,我們不執行梯度下降步驟,而是從 scipy 庫中呼叫了一個內建的函式 fmin_tnc 。
fmin_tnc 是一個尋找非約束函式的最小值的優化求解函式。對於邏輯迴歸,你希望用引數 theta 來 優化成本函式。 優化中的約束經常是指對引數的約束。例如, theta 可能取值的約束範圍 theta ≤ 1 。然而邏輯迴歸就沒有這樣的限制,因為 theta 是允許採取任何實際值的。
具體來說,在給定固定的資料集(X和y的值)的情況下,你將使用 fmin_tnc 來找到邏輯迴歸的成本函式的最佳或者最優的引數 theta 。將把以下的輸入傳遞給 fmin_tnc :
· 我們想要優化的引數初始值;
· 當給定訓練集和特定 theta 值 時,用來給資料集(X,y)計算 theta 值 的邏輯迴歸成本和梯度的函式。
temp = opt.fmin_tnc(func = costFunction,
x0 = theta.flatten(),fprime = gradient,
args = (X, y.flatten()))
#the output of above function is a tuple whose first element #contains the optimized values of theta
theta_optimized = temp[0]
print(theta_optimized)
關於函式 flatten() 的註解 :
不幸的是, SciPy 的 sfmin_tnc 不能很好地使用行向量或者列向量,它期望的引數是陣列形式的。 flatten() 函式將行向量或者列向量縮小到陣列形式。
上面程式碼的執行結果應該是 [-25.16131862, 0.20623159, 0.20147149] 。
如果你正確地執行了 costFunction 函式, fmin_tnc 將在正確的優化引數上進行收斂,並返回最終的 theta 值。 值得 注意的是,通過使用fmin_tnc,你不必自己編寫任何迴圈程式,也不必像梯度下降那樣設定一個學習率。這都是由 fmin_tnc 來完成的,你只需要提供一個函式來計算成本和梯度。
讓我們使用這些優化了的 theta 值來計算成本。
J = costFunction(theta_optimized[:,np.newaxis], X, y)
print(J)
你會看到上面程式碼執行之後的輸出值是 0.203 ,這 可以 與使用初始的 theta 值 獲得的成本值0.693對比一下。
繪製決策邊界
然後,這個最終的 theta 值將被用來繪製訓練資料的決策邊界,從而會得到一個類似於下面的圖。
plot_x = [np.min(X[:,1]-2), np.max(X[:,2]+2)]
plot_y = -1/theta_optimized[2]*(theta_optimized[0]
+ np.dot(theta_optimized[1],plot_x))
mask = y.flatten() == 1
adm = plt.scatter(X[mask][:,1], X[mask][:,2])
not_adm = plt.scatter(X[~mask][:,1], X[~mask][:,2])
decision_boun = plt.plot(plot_x, plot_y)
plt.xlabel('Exam 1 score')
plt.ylabel('Exam 2 score')
plt.legend((adm, not_adm), ('Admitted', 'Not admitted'))
plt.show()
通過上面的結果,看起來我們的模型在區分那些被錄取的和沒有被錄取的學生的方面做得非常好。接下來要量化模型的精度,我們將為這個模型編寫一個稱為 accuracy 的函式。
def accuracy(X, y, theta, cutoff):
pred = [sigmoid(np.dot(X, theta)) >= cutoff]
acc = np.mean(pred == y)
print(acc * 100)
accuracy(X, y.flatten(), theta_ans[0], 0.5)
執行之後,應該會輸出一個結果為89%的精度值。
本文由北郵 @愛可可-愛生活 老師推薦, 阿里云云棲社群 組織翻譯。
文章原標題《Python Implementation of Andrew Ng’s Machine Learning Course (Part 2.1)》
作者:Srikar
譯者: 奧特曼 ,審校:袁虎。
文章為簡譯,更為詳細的內容,請檢視 原文