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 : 特徵 (5000 ,400) 標籤 (5000 ,1) 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代表十(實際上是0)
for 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圖找最優的正則化參數