機器學習 | 吳恩達機器學習第三週程式設計作業(Python版)
實驗指導書 下載密碼:fja4
本篇部落格主要講解,吳恩達機器學習第三週的程式設計作業,作業內容主要是利用邏輯迴歸演算法(正則化)進行二分類。實驗的原始版本是用Matlab實現的,本篇部落格主要用Python來實現。
目錄
1.實驗包含的檔案
檔名稱 | 含義 |
ex2.py | 邏輯迴歸演算法(不帶正則化)主程式 |
ex2_reg.py | 邏輯迴歸演算法(帶正則化)主程式 |
ex2data1.txt | 第一個實驗的訓練資料集 |
ex2data2txt | 第二個實驗的訓練資料集 |
mapFeature.py | 在原始輸入特徵基礎上生成新的多項式特徵的程式 |
plotDecisionBoundary.py | 繪製決策邊界的程式 |
plotData.py |
視覺化待分類資料的程式 |
sigmoid.py | Sigmoid函式 |
costFunction.py | 計算邏輯迴歸(不帶正則化)代價函式的程式 |
predict.py | 邏輯迴歸測試函式 |
costFunctionReg.py | 計算邏輯迴歸(帶正則化)代價函式的程式 |
實驗任務:編寫紅色部分程式的關鍵程式碼。
2.使用邏輯迴歸演算法(不帶正則化)進行二分類
- 開啟主程式ex2.py
data = np.loadtxt('ex2data1.txt', delimiter=',') #讀取txt檔案 每一行以','分隔 X = data[:, 0:2] #前兩列為原始輸入特徵 分別兩門考試的成績 y = data[:, 2] #第三列是輸出變數(標籤) 二分類 0/1 1代表通過 0代表未通過 '''第1部分 視覺化訓練資料集''' print('Plotting Data with + indicating (y = 1) examples and o indicating (y = 0) examples.') plot_data(X, y) plt.axis([30, 100, 30, 100]) #設定x,y軸的取值範圍 plt.legend(['Admitted', 'Not admitted'], loc=1) #設定圖例 plt.xlabel('Exam 1 score') #x軸標題 考試1成績 plt.ylabel('Exam 2 score') #y軸標題 考試2成績
- 編寫視覺化程式plotData.py
def plot_data(X, y):
plt.figure()
postive=X[y==1] #分離正樣本
negtive=X[y==0] #分離負樣本
plt.scatter(postive[:,0],postive[:,1],marker='+',c='red',label='Admitted') #畫出正樣本
plt.scatter(negtive[:,0],negtive[:,1],marker='o',c='blue',label='Not Admitted') #畫出負樣本
- 檢視視覺化效果
- 計算邏輯迴歸的代價函式和梯度
'''第2部分 計算代價函式和梯度'''
(m, n) = X.shape #m樣本數 n原始輸入特徵數
X = np.c_[np.ones(m), X] #特徵矩陣X前加一列1 方便矩陣運算
#初始化模型引數為0
initial_theta = np.zeros(n + 1)
# 計算邏輯迴歸的代價函式和梯度
cost, grad = cf.cost_function(initial_theta, X, y)
np.set_printoptions(formatter={'float': '{: 0.4f}\n'.format}) #設定輸出格式
#與期望值進行比較 驗證程式的正確性
print('Cost at initial theta (zeros): {:0.3f}'.format(cost)) #0引數下的代價函式值
print('Expected cost (approx): 0.693')
print('Gradient at initial theta (zeros): \n{}'.format(grad)) #0引數下的梯度值
print('Expected gradients (approx): \n-0.1000\n-12.0092\n-11.2628')
# 用非零引數值計算代價函式和梯度
test_theta = np.array([-24, 0.2, 0.2])
cost, grad = cf.cost_function(test_theta, X, y)
#與期望值進行比較 驗證程式的正確性
print('Cost at test theta (zeros): {}'.format(cost))#非0引數下的代價函式值
print('Expected cost (approx): 0.218')
print('Gradient at test theta: \n{}'.format(grad))
print('Expected gradients (approx): \n0.043\n2.566\n2.647')#非0引數下的代價函式值
- 編寫sigmoid函式sigmoid.py
def sigmoid(z):
g = np.zeros(z.size)
g=1/(1+np.exp(-z))
return g
- 編寫計算代價函式和梯度的程式costFunction.py
def h(theta,X): #假設函式
return sigmoid(np.dot(X,theta))
def cost_function(theta, X, y):
m = y.size #樣本數
cost = 0
grad = np.zeros(theta.shape)
myh=h(theta,X) #得到假設函式值
term1=-y.dot(np.log(myh))
term2=(1-y).dot(np.log(1-myh))
cost=(term1-term2)/m
grad=(myh-y).dot(X)/m
return cost, grad
證明我們的程式碼是正確的。
- 訓練分類器,並用高階優化方法fmin_bfgs求解最優引數
'''第3部分 用高階優化方法fmin_bfgs求解最優引數'''
#可以把高階優化想像成梯度下降法 只不過不用人工設定學習率
'''
fmin_bfgs優化函式 第一個引數是計算代價的函式 第二個引數是計算梯度的函式 引數x0傳入初始化的theta值
maxiter設定最大迭代優化次數
'''
def cost_func(t): #單獨寫一個計算代價的函式 返回代價函式值
return cf.cost_function(t, X, y)[0]
def grad_func(t): #單獨寫一個計算梯度的函式 返回梯度值
return cf.cost_function(t, X, y)[1]
# 執行高階優化方法
theta, cost, *unused = opt.fmin_bfgs(f=cost_func, fprime=grad_func, x0=initial_theta, maxiter=400, full_output=True, disp=False)
#列印最優的代價函式值和引數值 與期望值比較 驗證正確性
print('Cost at theta found by fmin: {:0.4f}'.format(cost))
print('Expected cost (approx): 0.203')
print('theta: \n{}'.format(theta))
print('Expected Theta (approx): \n-25.161\n0.206\n0.201')
# 畫出決策邊界
pdb.plot_decision_boundary(theta, X, y)
plt.xlabel('Exam 1 score')
plt.ylabel('Exam 2 score')
可以發現我們的結果和期望值差不多:
呼叫已經寫好的plotDecisionBoundary.py畫出決策邊界:
- 用訓練好的分類器進行預測,並計算在訓練集上的準確率
'''第4部分 用訓練好的分類器進行預測,並計算分類器在訓練集上的準確率'''
#假設一個學生 考試1成績45 考試2成績85 預測他通過的概率
prob = sigmoid(np.array([1, 45, 85]).dot(theta))
#與期望值進行比較 驗證正確性
print('For a student with scores 45 and 85, we predict an admission probability of {:0.4f}'.format(prob))
print('Expected value : 0.775 +/- 0.002')
# 計算分類器在訓練集上的準確率
p = predict.predict(theta, X)
#與期望值進行比較 驗證正確性
print('Train accuracy: {}'.format(np.mean(y == p) * 100))
print('Expected accuracy (approx): 89.0')
- 編寫預測程式predict.py
def predict(theta, X):
m = X.shape[0] #樣本數
p = np.zeros(m) #每個樣本預測的標籤
p=sigmoid(X.dot(theta)) #每個樣本屬於正類的概率
p[p>=0.5]=1 #概率大於等於0.5 認為屬於正類 標籤為1 否則為0
p[p<0.5]=0
return p
發現我們的結果和期望值差不多:
3.邏輯迴歸演算法(不帶正則化)進行二分類完整專案程式碼
下載連結 下載密碼:546j
4.利用邏輯迴歸演算法(帶正則化)進行二分類
使用邏輯迴歸進行分類時,一種方案是直接使用原始輸入特徵進行運算;另一種是當輸入特徵比較少或分類效果不理想時時,可以考慮在原始輸入特徵的基礎上擴充一些新特徵,再進行邏輯迴歸。本小節的實驗就屬於第二種情況,該資料集視覺化後會發現線性不可分,所以僅用兩個原始輸入特徵是不可行的,需要擴充套件一些新特徵。
擴充的新特徵多一些沒關係,訓練過程中會自動篩選對分類效果貢獻大的特徵,體現在求解的最優引數上,一般不重要的特徵,前面的引數都接近於0.
- 開啟主程式ex2_reg.py
data = np.loadtxt('ex2data2.txt', delimiter=',') #載入txt格式訓練資料集 每一行用','分隔
X = data[:, 0:2] #前兩列是原始輸入特徵(2)
y = data[:, 2] #最後一列是標籤 0/1
plot_data(X, y) #視覺化訓練集
plt.xlabel('Microchip Test 1')
plt.ylabel('Microchip Test 2')
plt.legend(['y = 1', 'y = 0'])#圖例
input('Program paused. Press ENTER to continue')
'''第1部分 增加新的多項式特徵,計算邏輯迴歸(正則化)代價函式和梯度'''
X = mf.map_feature(X[:, 0], X[:, 1])
initial_theta = np.zeros(X.shape[1])
lmd = 1 #正則化懲罰項係數
# 計算引數為0時的代價函式值和梯度
cost, grad = cfr.cost_function_reg(initial_theta, X, y, lmd)
#與期望值比較 驗證正確性
np.set_printoptions(formatter={'float': '{: 0.4f}\n'.format})
print('Cost at initial theta (zeros): {}'.format(cost))
print('Expected cost (approx): 0.693')
print('Gradient at initial theta (zeros) - first five values only: \n{}'.format(grad[0:5]))
print('Expected gradients (approx) - first five values only: \n 0.0085\n 0.0188\n 0.0001\n 0.0503\n 0.0115')
input('Program paused. Press ENTER to continue')
test_theta = np.ones(X.shape[1])
# 計算引數非0(1)時的代價函式值和梯度
cost, grad = cfr.cost_function_reg(test_theta, X, y, lmd)
#與期望值比較 驗證正確性
print('Cost at test theta: {}'.format(cost))
print('Expected cost (approx): 2.13')
print('Gradient at test theta - first five values only: \n{}'.format(grad[0:5]))
print('Expected gradients (approx) - first five values only: \n 0.3460\n 0.0851\n 0.1185\n 0.1506\n 0.0159')
- 編寫視覺化程式plotData.py
def plot_data(X, y):
plt.figure()
postive=X[y==1] #取出正樣本
negtive=X[y==0] #取出負樣本
plt.scatter(postive[:,0],postive[:,1],marker='x',c='red',label='y=1')
plt.scatter(negtive[:,0],negtive[:,1],marker='o',c='blue',label='y=0')
- 檢視已經寫好的特徵對映程式mapFeature.py
在原始輸入特徵(兩個)基礎上增加新的多項式特徵:
def map_feature(x1, x2): #生成新的多項式特徵
degree = 6
x1 = x1.reshape((x1.size, 1))
x2 = x2.reshape((x2.size, 1))
result = np.ones(x1[:, 0].shape) #result初始為一個列向量 值全為1
for i in range(1, degree + 1):
for j in range(0, i + 1):
result = np.c_[result, (x1**(i-j)) * (x2**j)] #不斷拼接新的列 擴充特徵矩陣
return result
- 編寫邏輯迴歸(正則化)的代價函式和梯度計算程式costFunctionReg.py
注意不懲罰第一個引數。
def h(theta,X): #假設函式
return sigmoid(X.dot(theta))
def cost_function_reg(theta, X, y, lmd):
m = y.size
cost = 0
grad = np.zeros(theta.shape)
myh=h(theta,X) #假設函式值
term1=-y.dot(np.log(myh))
term2=(1-y).dot(np.log(1-myh))
term3=(lmd/(2*m))*(theta[1:].dot(theta[1:])) #不懲罰第一項
cost=(term1-term2)/m+term3
grad=(myh-y).dot(X)/m
grad[1:]+=(lmd/m)*theta[1:]
return cost, grad
與期望值進行比較,差不多,說明我們的程式是正確的:
- 資料集視覺化效果
- 訓練與預測
'''第2部分 嘗試不同的懲罰係數[0,1,10,100],分別利用高階優化演算法求解最優引數,分別計算訓練好的分類器在訓練集上的準確率,
並畫出決策邊界
'''
initial_theta = np.zeros(X.shape[1])
# Set regularization parameter lambda to 1 (you should vary this)
lmd = 1 #需要改變這個值
# Optimize
def cost_func(t):
return cfr.cost_function_reg(t, X, y, lmd)[0]
def grad_func(t):
return cfr.cost_function_reg(t, X, y, lmd)[1]
theta, cost, *unused = opt.fmin_bfgs(f=cost_func, fprime=grad_func, x0=initial_theta, maxiter=400, full_output=True, disp=False)
print('Plotting decision boundary ...')
pdb.plot_decision_boundary(theta, X, y)
plt.title('lambda = {}'.format(lmd))
plt.xlabel('Microchip Test 1')
plt.ylabel('Microchip Test 2')
p = predict.predict(theta, X)
print('Train Accuracy: {:0.4f}'.format(np.mean(y == p) * 100))
print('Expected accuracy (with lambda = 1): 83.1 (approx)')
- 編寫預測函式
def predict(theta, X):
m = X.shape[0]
p = np.zeros(m)
p=sigmoid(X.dot(theta))
p[p>=0.5]=1
p[p<0.5]=0
return p
- 嘗試不同的懲罰係數值
時:
視覺化決策邊界,檢視分類效果:
與期望值進行比較,差不多,說明我們的程式是正確的:
時:
相當於不進行正則化。
視覺化決策邊界,檢視分類效果:
雖然此時分類效果看起來更好,在訓練集上的準確率更高,但是很有可能出現過擬合,模型泛化能力比較差。
時:
視覺化決策邊界,檢視分類效果:
此時,正則化懲罰係數有些大,分類效果不太好以及在訓練集上的準確率不太高,應該稍微減小一下。
時:
視覺化決策邊界,檢視分類效果:
此時,正則化懲罰係數有些過大,分類效果很不好以及在訓練集上的準確率很低,應該大幅度減小一下。
綜上,在訓練過程中,需要新增正則化懲罰項防止過擬合,但懲罰係數要合理設定,過大過小都不行。
5.邏輯迴歸演算法(正則化)進行二分類完整專案程式碼
下載連結 下載密碼:73we