多个二分类实现多分类
导入包和准备数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 用来加载.mat数据
from scipy.io import loadmat
# 加载数据
data = loadmat('ex3data1.mat')
data
# ((5000, 400), (5000, 1))
data['X'].shape, data['y'].shape
# 输出数据图像
plt.rcParams['figure.figsize'] = (15.0, 8.0)
for i in range(10):
plt.subplot(1,10,i+1)
index = i*500
plt.title(data['y'][index,0])
plt.imshow(data['X'][index].reshape((20,20)).astype('uint8'))
plt.axis('off')
plt.show()
data是手写数字的数据集。data的详情:
数据展示:
Sigmoid、损失函数
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def cost(theta, X, y, learningRate):
# INPUT:参数值theta,数据X,标签y,学习率
# OUTPUT:当前参数值下的交叉熵损失
# STEP1:将theta, X, y转换为numpy类型的矩阵
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
# STEP2:根据公式计算损失函数(不含正则化)
sig = sigmoid(X@theta.T)
cross_cost = (-y.T@np.log(sig)-(1-y).T@np.log(1-sig))/len(y)
# STEP3:根据公式计算损失函数中的正则化部分
reg = np.sum(np.power(theta[0,1:], 2))*learningRate/(2*len(y))
# STEP4:把上两步当中的结果加起来得到整体损失函数
whole_cost = cross_cost[0,0]+reg
return whole_cost
刚开始的时候认为第一步的转化为np矩阵是冗余的,但是得到的准确率一直很低,找了很久的原因,才发现初始化的时候y.shape是(5000,1),而X@theta.T是(5000, 401)@ (401,)=(5000,)。这时候-y*np.log(sig)是(5000, 1)*(5000, )=(5000,5000),而不是我认为的(5000,)。
总而言之就是:转化为矩阵是有必要的或者直接全部reshape也可以,因为你不能确保传进来的数据是什么形式的。(5000, 1)与(5000, )的差别很大的。
梯度函数
def gradient(theta, X, y, learningRate):
# INPUT:参数值theta,数据X,标签y,学习率
# OUTPUT:当前参数值下的梯度
# STEP1:将theta, X, y转换为numpy类型的矩阵
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
# STEP3:计算预测的误差
error = sigmoid(X@theta.T)-y
# STEP4:根据上面的公式计算梯度
regularized_term = (learningRate/len(y))* theta
# 不用对theta0进行正则化
regularized_term[0,0]=0
grad = (error.T@X)/len(y)+regularized_term
return np.array(grad).ravel()
梯度下降
逻辑回归是二分类算法,想要实现N分类就要使用N个二分类,每一个二分类只对应一个类(是这个类:1,不是这个类:0)
from scipy.optimize import minimize
# num_labels代表需要分多少类
def one_vs_all(X, y, num_labels, learning_rate):
rows = X.shape[0]
params = X.shape[1]
# 初始化