吳恩達機器學習編程作業:logistic 迴歸 (python)

吳恩達機器學習編程作業:logistic 迴歸 (python)

參考代碼:

https://blog.csdn.net/zy1337602899/article/details/84777396
初次寫機器學習的代碼,大部分參照了鏈接文章中的代碼,稍有改動

源代碼

// An highlighted block
import matplotlib.pyplot as plt
import numpy as np
import scipy.optimize as opt
from sklearn.metrics import classification_report
import pandas as pd
from sklearn import linear_model

#獲取原始數據
def raw_data(path):
    data = pd.read_csv(path, names=['exam1','exam2','admit'])
    return data

#繪製原始數據
def draw_data(data):
    accept = data[data['admit'] == 1]
    refuse = data[data['admit'] == 0]
    plt.scatter(accept['exam1'], accept['exam2'], c='g', label='admit')
    plt.scatter(refuse['exam1'], refuse['exam2'], c='r', label='refuse')
    plt.title('admission')
    plt.xlabel('exam1')
    plt.ylabel('exam2')
    return plt
#sigmoid函數
def sigmoid(z):
    return 1/(1 + np.exp(-z))
#代價函數
def cost_function(theta,x,y):
    m=x.shape[0]
    #print(theta_T.shape)
    first = -y.dot(np.log(sigmoid(x.dot(theta))))
    second = (1 -y).dot(np.log(1 - sigmoid(x.dot(theta))))
    #dot運算的過程中已經做了sum工作
    #因爲有部分運算是內積  a1b1+a2b2+...+ anbn
    return (first - second)/m

def gradient_descent(theta,x,y):
    m=x.shape[0]
    b = sigmoid(x.dot(theta))
    #print(b)
    return (b - y).dot(x)
def predict(theta,x):
    h = sigmoid(x.dot(theta.T))
    return[1 if x >= 0.5 else 0 for x in h]
#決策邊界
def boundary(theta,data):
    x1 = np.arange(20,100,0.01)

    x2 = -(theta[0] + theta[1]*x1)/theta[2]
    plt = draw_data(data)
    plt.title("boundary")
    plt.plot(x1,x2)
    plt.show()
    pass

def main():
    data=raw_data('F:\jupyterProject\Logistic Regression Exercise\ex2data1.txt')
    # print(data.head())
    # plt=draw_data(data)
    # plt.show()
    x1=data['exam1']
    x2=data['exam2']
    x=np.c_[np.ones(x1.shape[0]),x1,x2]
    y=data['admit']
    # 不要將theta初始化爲1,初始化爲1的話,h(x)會過大,sigmoid近似返回1,log(1-h(x))無意義
    theta=np.zeros(x.shape[1])
    times = 200000
    learningRate = 0.12
    #print(theta[0].shape)
    cost_data=np.ones(20001)
    #print(gradient_descent(theta,x,y))
    #minimize是已封裝好的計算 fun 最小值的方法
    #theta_right=opt.minimize(fun=cost_function,x0=theta,args=(x,y),method='tnc',jac=gradient_descent)
    #循環20萬次
    for i in range(times): 
        #cost_data[i] = cost_function(theta,x,y)
        a = gradient_descent(theta,x,y)
        theta= theta - learningRate * a
        #print(a)
    print(theta)
    boundary(theta,data)
    #再循環20萬次,對比效果
    for i in range(times): 
        #cost_data[i] = cost_function(theta,x,y)
        a = gradient_descent(theta,x,y)
        theta= theta - learningRate * a
        #print(a)
    print(theta)
    boundary(theta,data)
    #plt.scatter(range(1000),cost_data[:1000], c='k', label='boundary')
main()

效果對比

1.使用 scipy.optimize.minimize方法計算使得costfunction最小的theta,得到如下邊界:
theta:[-25.14325329 0.20608863 0.2013236 ]
在這裏插入圖片描述
圖片來源:https://blog.csdn.net/zy1337602899/article/details/84777396

2.自己根據課程中老師講到的repeat部分編寫的代碼進行的計算(20萬次迭代):
theta:[-73747.32582717 617.25196212 602.09900877]
在這裏插入圖片描述
3.迭代40萬次:
theta:[-66277.53154909 571.89400675 561.94143501]
在這裏插入圖片描述
可以看到相比20萬次迭代,直觀上有了更好的劃分效果

踩的坑 && 總結

1.不熟悉numpy中的dot運算,一度以爲cost_function和gradient_descent中需要(實際上不需要sum):

 return sum(first - second)/m
 return sum((b - y).dot(x))

輸出部分數據的結構幫助我們理解dot的運算過程

#gradien_descent部分的運算
q = (sigmoid(x.dot(theta))-y)
w = q.dot(x)
print(q.shape)
print(x.shape)
print(w.shape)

output:
(100,)
(100, 3)
(3,)

x是 100×3的矩陣,theta 是個一維行向量,其shape爲(3,),我們可以認爲 x.dot(theta) 運算時自動把theta變成了 3×1的矩陣,這樣得到一個 100×1的矩陣,但是theta實際上不是矩陣,所以得到的結果也不是一個矩陣,而是一個有100個數值的一維行向量,即q。
q是一個一維行向量,x 是100×3的矩陣,這裏認爲dot運算時把q看作1×100的矩陣,得到一個一維行向量(1×3),當然最後的輸出是(3,)格式的數據,這3個數值分別是3個參數的梯度值。由於嫌編輯公式麻煩,具體的由公式推算出代碼的過程就附上一份手寫的吧。在這裏插入圖片描述

2.關於迭代更新theta
原博中給出的方法是利用已有的scipy.optimize.minimize方法,自己寫好損失函數和梯度函數,作爲參數傳進去,直接獲得最優的theta值,但是爲了體驗一波佛系調參的過程,我嘗試着自己寫theta的更新代碼,關鍵的代碼也就是手寫部分的最後一行,一直重複這一過程就行。最初我一直將迭代次數設置在1萬至5萬,總是出不來好的效果,決策邊界偏得離譜,也不停的修改學習率,都是白搭。後來我索性將迭代次數改爲了20萬次,沒想到這次直接出來了比較好的效果,嗯,果然是佛系。
3.尚未解決的問題
我嘗試畫出cost_function的變化曲線

for i in range(times): 
#每迭代100次記錄一次損失函數值
        if(i % 100 == 0):
            cost_data[int(i/100)] = cost_function(theta,x,y)
        a = gradient_descent(theta,x,y)
        theta= theta - learningRate * a
        #print(a)
plt.scatter(range(10000),cost_data[:10000], c='k', label='boundary')

但是得到的結果卻是這樣的:
在這裏插入圖片描述
很悲傷。
不過程序給報了個warring :RuntimeWarning: divide by zero encountered in log
那麼是不是 sigmoid(x.dot(theta))的結果太小,導致log()的參數趨近於零了呢,這個問題等我研究明白了再回來填坑,或者有大神知道怎麼回事的話還請帶一帶本小白。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章