py實現多分類正則化邏輯迴歸手寫訓練集(精煉加註)

py實現多分類邏輯迴歸手寫訓練集(精煉)

這幾天再補吳恩達的作業,剛好以前的邏輯迴歸代碼還沒實現,這邊就先貼上來。
作業中只給到5000個訓練樣本,且0的標籤爲10。代碼中拿了4000個作爲訓練,1000個測試

import scipy.optimize as opt
import scipy.io as scio
import matplotlib.pyplot as plt
import numpy as np
'''***************************************************************
 * @Fun_Name    : def loadData(filename)
 * @Function    : 從數據中分離特徵和標籤,加入每個樣本的第一個特徵1,並且將其打亂,前4000個樣本做訓練集,後1000個訓練集
 * @Parameter   : 文件名
 * @Return      : 特徵 (5000400) 標籤 (50001) array
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 10:10 2020-06-08***'''
def loadData(filename , rand):
    mat = scio.loadmat(filename)                                          #得到數據類型爲字典
    labels = mat['y']                                                     #將header是y的放在數組中
    features = mat['X']                                                   #將header是X的放在數組中
    m = features.shape[0]                                                 #得到樣本數
    column = np.ones(m)                                                   #得到(m,)都爲1的列表
    features = np.insert(features,0,values=column,axis=1)                 #插入到樣本第一列
    # 將數據打亂 4000個訓練  1000個測試
    np.random.seed(rand)                                                  #rand隨機種子,當rand一致時,features和labels打亂順序一致,保證一一對應
    np.random.shuffle(features)                                           #打亂
    np.random.seed(rand)
    np.random.shuffle(labels)
    trainFeatures = features[0:4000,:]                                    #取前4000個作爲訓練樣本
    testFeatures = features[4000:5000,:]                                  #後1000個位測試樣本
    trainLabels = labels[0:4000]
    testLabels = labels[4000:5000]
    return trainFeatures ,testFeatures,trainLabels,testLabels
'''***************************************************************
 * @Fun_Name    : def visualizing(features , labels):
 * @Function    : 可視化,打亂後可用這個函數看看特徵和標籤是否對應
 * @Parameter   : 
 * @Return      : 
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 21:01 2020-06-08***'''
def visualizing(features , labels):
    featuresShow = np.delete(features,0,axis=1)                           #要還原圖象,要將特徵中第一列添加的1捨去
    m = featuresShow.shape[0]                                             #得到樣本個數
    image = featuresShow.reshape(m,20,20)                                 #將400->20,20維度
    for i in range(910,920):                                              #隨便抽10張出來對比下看看是否對應
        plt.imshow(image[i].T)                                            #轉置是爲了原圖是橫着的,轉置爲了視覺效果更好
        print(labels[i])
        plt.show()
'''***************************************************************
 * @Fun_Name    : def sigmoid(z):
 * @Function    : 不做解釋
 * @Parameter   : 
 * @Return      : 
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 21:10 2020-06-08***'''
def sigmoid(z):
    return 1/(1 + np.exp(-z))
'''***************************************************************
 * @Fun_Name    : def dealLabels(labels,N):
 * @Function    : 爲一對多訓練做準備
 * @Parameter   : labels 標籤 ,N訓練的數字 ,比如訓練2,那就將標籤=2改爲1,區域標籤改爲0
 * @Return      : 
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 21:11 2020-06-08***'''
def dealLabels(labels,N):
    deallabels = labels.copy()                                             #深拷貝
    one = np.nonzero(deallabels == N)                                      #找到deallabels == N的索引
    zero = np.nonzero(deallabels != N)                                     #找到deallabels != N的索引
    deallabels[one] = 1                                                    #將deallabels == N的標籤改爲1
    deallabels[zero] = 0
    return deallabels
'''***************************************************************
 * @Fun_Name    : def cost(theta , features , labels , lamda): 
 * @Function    : 計算損失函數 正則化 下面都是公式
 * @Parameter   : 
 * @Return      : 
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 21:14 2020-06-08***'''
def cost(theta , features , labels , lamda):
    m , n = features.shape
    theta = theta.reshape(n,1)
    A = sigmoid(np.dot(features, theta))
    cost1 = (- np.dot(labels,np.log(A)) - np.dot((1-labels),np.log(1-A)))/m
    cost2 = (lamda/(2*m))*np.dot(theta[1:n].T,theta[1:n])
    return (float)(cost1 + cost2)

'''***************************************************************
 * @Fun_Name    : def gradient(features , theta)
 * @Function    : 求梯度
 * @Parameter   : feature [5000,401] theta [401,1]
 * @Return      : 
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 11:29 2020-06-08***'''
def gradient(theta , features , labels , lamda):
    m , n= features.shape
    theta = theta.reshape(n, 1)
    A = sigmoid(np.dot(features, theta)).reshape(m,1)
    gradient1 = np.dot(features.T,(A - labels.T))/m
    gradient2 = (lamda / m) * theta
    gradient2[0] = 0
    return (gradient2 + gradient1)
'''***************************************************************
 * @Fun_Name    : def onevsall(trainFeatures,trainLabels,lamda = 0.01):
 * @Function    : 一對多訓練
 * @Parameter   : lamda正則化參數
 * @Return      : 
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 21:19 2020-06-08***'''
def onevsall(trainFeatures,trainLabels,lamda = 0.01):
    m, n = trainFeatures.shape
    theta = np.zeros(shape=[10, n])                                         #將theta變成10,n 每一行記錄一個數字訓練好的參數
    #theta[0]記錄的是數字1的訓練參數,1是2,2是3,..9的話是0
    for i in range(1,11):                                                   #改數據集中0的標籤值爲10 所以從1開始到10
        deallabels = dealLabels(trainLabels, i).T  # 1,4000                 #看上面註解
        theta[i-1] = opt.fmin_tnc(func=cost, x0=theta[i-1], fprime=gradient, args=(trainFeatures, deallabels, lamda))[0].reshape(1,n)   #優化的梯度下降算法
        print("第%d/10次訓練成功*****************************************************"%(i))
    return theta.T
'''***************************************************************
 * @Fun_Name    : def predict(theta,testFeatures,testLabels):
 * @Function    : 預測
 * @Parameter   : 
 * @Return      : 
 * @Creed       : Talk is cheap , show me the code
 ***********************xieqinyu creates in 21:22 2020-06-08***'''
def predict(theta,testFeatures,testLabels):
    m = testFeatures.shape[0]
    accury = 0
    Predict = np.dot(testFeatures,theta)                                    #每一行是每個樣本在1 2 3 4 5 6 7 8 9 10 的概率值
    temp = Predict.argmax(axis=1) + 1                                       #求取每行的最大值的索引 加1是因爲索引是0 1 2 3 4 5 6 7 8 9.0代表的是1 .......9代表十(實際上是0for i in range(m):
        if temp[i] == testLabels[i]:
            accury += 1
    print(float(accury/m))

trainFeatures ,testFeatures,trainLabels,testLabels  = loadData("ex3data1.mat",100)
predict(onevsall(trainFeatures,trainLabels,0.01),testFeatures,testLabels)




效果在正則化參數爲0.01的情況下準確率在0.892,有時間可以畫個lamda-cost圖找最優的正則化參數

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