多分类实际上就是二分类的拓展,需要训练多个分类器,最终选取分类出来概率最高的那个分类器就是预测结果。
import scipy.io as sio
import numpy as np
import matplotlib.pyplot as plt
def load_data():
data = sio.loadmat("ex3data1.mat")
X = data['X']#特征值
Y = data['y']#结果值
return X,Y#返回特征值和结果值
def random_show(X):#随机展示100张图片的函数
m = X.shape[0]#样本数
rand_index = np.random.randint(0,m,100)#随机生成0-m个整数
rand_img = X[rand_index,:] #取出随机抽取的100张图片
fig,ax = plt.subplots(figsize=(8,8),nrows=10,ncols=10,sharex=True,sharey=True)
#nrows ncols表示生成多少行 多少列子图 figsize表示生成8,8英寸大小figure
for i in range(10):
for j in range(10):
ax[i,j].imshow(rand_img[10*i+j].reshape(20,20).T,cmap="gray_r")
#每张图片被拉升成一条直线 需要进行维度转换 变为20*20像素的图片 ax[i,j]表示取出第i行j列个子图
plt.xticks([])#去除x轴刻度
plt.yticks([])#去除y轴刻度
plt.show()
def classifyData(Labelindex,y):
for i in range(y.shape[0]):
if y[i] == Labelindex:#如果结果是第i种分类器 则是正类 代表1
y[i] = 1
else:
y[i] = 0#反之代表父类
return y
def sigmoid(z):#定义激活函数
return 1/(1+np.exp(-z))
def costfunction(X,y,theta,lamda):#代价函数
m = X.shape[0]
A = sigmoid(X@theta)
first = y*np.log(A)
second = (1-y)*np.log(1-A)
res = np.sum(lamda*(np.power(theta[1:,0],2))/(2*m))#正则项
return -np.sum(first+second)/m + res
def grad_decent(X,y,theta,lamda,learning_rate,num,index):#梯度下降 index参数代表这是第几个分类器
m = X.shape[0]
for i in range(num):
A = sigmoid(X@theta)
res = np.append(theta[1:,[0]],[[0]],axis=0)
theta = theta - learning_rate*((X.T@(A-y))/m+res)
cost = costfunction(X,y,theta,lamda)
print("{}类别分类器,第{}次迭代,损失为{}".format(index,i,cost))
return theta
def test(final_theta,X,Y):#验证训练结果函数
m = X.shape[0]
predict_result = sigmoid(X@final_theta.T)
print(predict_result)
max_index = np.argmax(predict_result,axis=1)#选取概率值最大的那个分类器
count = 0
for i in range(m):
if max_index[i]+1 == Y[i]:#预测结果
count = count+1
print(count/m)
def main():
X,Y=load_data()
random_show(X)
X = np.append(np.ones((5000, 1)), X, axis=1)
final_theta = []
for i in range(10):#总共需要训练十个分类器
z = np.copy(Y)
y = classifyData(i+1,z)#将标签类别 传进去 分正类跟父类
thata = grad_decent(X, y, np.zeros((401, 1)), 0.1, 0.001, 1000, i+1)#梯度下降,训练分类器
final_theta.append(thata.ravel())#将训练结果保存到变量中
final_theta = np.array(final_theta)
test(final_theta,X,Y)#验证训练集
if __name__ == '__main__':
main()
参数 fun:要优化的代价函数 Method:运用的优化算法
jac:梯度向量
x0:初始参数 只能为(n,)维 一维矩阵
method:要最小化代价函数的方法 这里采用的是’TNC’方法
args():其他参数 传递给最小化函数,jac的其他参数 这里传递特征值,真实标签值,lambda
import scipy.io as sio
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
def load_data():#加载数据
data = sio.loadmat("ex3data1.mat")
X = data['X']#特征值
Y = data['y']#结果值
return X,Y#返回特征值和结果值
def random_show(X):#随机展示100张图片的函数
m = X.shape[0]#样本数
rand_index = np.random.randint(0,m,100)#随机生成0-m个整数
rand_img = X[rand_index,:] #取出随机抽取的100张图片
fig,ax = plt.subplots(figsize=(8,8),nrows=10,ncols=10,sharex=True,sharey=True)
#nrows ncols表示生成多少行 多少列子图 figsize表示生成8,8英寸大小figure sharex sharey为了让图更好看
for i in range(10):
for j in range(10):
ax[i,j].imshow(rand_img[10*i+j].reshape(20,20).T,cmap="gray_r")
#每张图片被拉升成一条直线 需要进行维度转换 变为20*20像素的图片 ax[i,j]表示取出第i行j列个子图
plt.xticks([])#去除x轴刻度
plt.yticks([])#去除y轴刻度
plt.show()
def sigmoid(z):#定义激活函数
return 1/(1+np.exp(-z))
# 这里 theta参数变为了一维矩阵的形式 所以在costfunction、梯度计算的时候不同于之前自己写的梯度下降了 要微调一下矩阵乘法计算
def costfunction(theta,X,y,lamda):#代价函数
m = X.shape[0]
A = sigmoid(X@theta)
first = y*np.log(A)
second = (1-y)*np.log(1-A)
res = np.sum(lamda*(np.power(theta[1:],2))/(2*m))#正则项
return -np.sum(first+second)/m + res
def grad(theta,X,y,lamda):#梯度的计算
m = X.shape[0]
A = sigmoid(X@theta)
jac = X.T@(A-y)/m
res = lamda*np.insert(theta[1:],obj=0,values=0)/m#正则化项
return jac+res#返回计算好的梯度
def test(X,y,final_theta):
A = sigmoid(X@final_theta.T)
max_index = np.argmax(A,axis=1)+1#要注意 这里返回的是预测最大的下标 下标是从0开始的 所以我们得全部+1
print("最终精度为:{}".format(np.mean(max_index == y)))
#np里true false形式矩阵 在求平均 就看成1 和 0
def main():
X,Y=load_data()
random_show(X)
X = np.append(np.ones((5000, 1)), X, axis=1)
final_theta = []
lamda = 0.1
y = Y.ravel()#需要处理成一维矩阵形式 不然后面加减会维度不匹配
for i in range(10):
theta = np.zeros((401,))
theta = minimize(fun=costfunction,args=(X,y==i+1,lamda),jac=grad,x0=theta,method='TNC')
#这里用到了一个小技巧 也就是y==i+1 它会把是第i+1类的标签置为true 不是的则置为false
#np矩阵 这种ture false矩阵与别的数进行加减运算 true会当作1 false当作0
final_theta.append(theta.x)#theta.x就是优化好的参数分类器 加到final_theta里
final_theta = np.array(final_theta)#变为二维矩阵
test(X,y,final_theta)#将所有分类器放进去验证
if __name__ == '__main__':
main()