Python 3.7
所用数据集链接:多分类所用数据集(ex3data1.mat),提取码:c3yy
目录
Mult-classification
题目:目前有一个矩阵文件,其中有5000个样本,每一个样本都是一张图像(20*20),图像上为0-9的某一个数字,现希望通过多分类算法训练使得机器能够识别出手写体对应数字
1.0 Package
先进包再说:
import numpy as np
# 数据处理
import pandas as pd
# 数据读取与加工,格式转换
import matplotlib.pyplot as plt
# 画图
from scipy.io import loadmat
# 这个第一次见,这是专门用来读取矩阵文件的函数(因为像素点是以矩阵文件格式保存的)
from scipy.optimize import minimize
# 高级优化函数(自从用这个以后再也不想自定义梯度下降)
1.1 Load data
第一步仍然是读取数据,代码如下:
def load_data(path):
# 定义函数,传入参数path
data=loadmat(path)
# 读取path指定路径的矩阵文件
x=data['X']
y=data['y']
# 根据索引区分x,y
return data,x,y
# 返回
data,x,y=load_data('ex3data1.mat')
#print(data)
print(x.shape)
# 查看x形状 (5000,400)
print(y.shape)
# 查看y形状 (5000,1)
print(np.unique(y))
# 去除y中重复元素看看y是什么样(其实就是看看一共分几类)
注意这里将每个样本拉直成一个400元素的向量(所以注意画图时候reshape以下) ,x矩阵如下:
其中每个
是一个400维向量
1.2 Visualization data
接下来可视化数据,话说矩阵文件可视化还是第一次尝试,不过思路类似,先可视化200个看看,代码如下:
def view_data():
# 定义函数
data_index=np.random.randint(0,5000,200)
# 在0到5000里随机取200个数,返回一个一维数组
data_sample=x[data_index,:]
# 将上述数组作为索引,在数据中随机挑选200个样本
fig,ax=plt.subplots(nrows=20,ncols=10,sharex=True,sharey=True,figsize=(12,12))
# 创建画布,指定对象(ax),注意此时的对象是一个矩阵,所以调用时候和之前不太一样
for i in range(20):
for j in range(10):
ax[i,j].matshow(data_sample[i+j*20].reshape((20,20)),cmap='gray_r')
# 将对象排列为20行10列,记得matshow里传入绘图对象时reshape
plt.xticks([])
plt.yticks([])
# 去掉标题,不然很难看
plt.show()
# 可视化
#view_data()
输出如下:
一些奇奇怪怪的手写体灰度图,下面数据预处理。
1.3 Data preprocess
代码如下:
def data_preprocess(x,y,data):
# 定义函数,传入参数
x = np.insert(x, 0, 1, axis=1)
# 第一列插一列1(为后续向量化)
y = y.flatten()
# 把y展开成一维数组,原因后面会看到
return x,y
x,y=data_preprocess(x,y,data)
theta=np.zeros((x.shape[1]))
# 顺便初始化Theta
#print(theta[1])
#print(theta)
print(theta.shape)
1.4 Sigmoid function
然后就是sigmoid函数,代码如下:
def sigmoid(z):
return 1/(1+np.exp(-z))
下面进入算法核心阶段。
1.5 Regularized costfunction
先放图:
其中:
为一个十维向量
代码如下:
def regularized_costfunction(theta,x,y,l):
# 定义函数
h=x@theta
# 注意这里x为二维数组,theta为一维数组,相乘后返回的是一维数组
J=(-y)*np.log(sigmoid(h))-(1-y)*np.log(1-sigmoid(h))
# 所以说要在前面把y展开成一维数组,是为了和h计算时方便(因为h是一维数组)
reg=theta[1:]@theta[1:]
# 仍然是那句话,theta_{0}不用正则化
cost=sum(J)/len(x)+reg*l/(2*len(x))
return cost
# 返回
cost=regularized_costfunction(theta,x,y,1)
# 此时的cost似乎是-17.05左右
1.6 Regularized gradient
先放图:
注意正则化从
开始
代码如下:
def regularized_gradient(theta,x,y,l):
# 定义函数
h=x@theta
G=x.T@(sigmoid(h)-y)
# 这些都一样
reg=theta[1:]
reg=np.insert(reg,0,1,axis=0)
# 这里之所以插入0是因为这里的reg是矩阵(或者说数组),而代价函数里是一个常数(两个向量相乘)
gradient=G/len(x)+reg*l/len(x)
return gradient
# 返回梯度,一个数组
1.7 Train model
终于要开始训练模型了,(这里是依次训练每一个逻辑回归器,再将它们分别的权重放在一个矩阵中),代码如下:
def training(x,y,l,c):
# 定义函数,这里c为总类数(10)
all_theta=np.zeros((c,x.shape[1]))
# 这个all_theta为(10,400),将来会装每一个分类器的权重
for i in range(1,c+1):
theta=np.zeros(x.shape[1])
y_i=np.array([1 if label ==i else 0 for label in y])
# 返回一个列表,寻找某一类样本的位置
result=minimize(fun=regularized_costfunction,x0=theta,args=(x,y_i,l),method='TNC',jac=regularized_gradient)
# 返回每一个样本的theta
all_theta[i-1,:]=result.x
# 加入到all_theta中
return all_theta
1.8 Model predict
开始利用模型预测:
def model_predict(x, all_theta):
# 定义函数
h = sigmoid(x @ all_theta.T)
# 计算每一个样本在每一个分类器里的可能性(也就是属于每一个类的可能性)
h_arg = np.argmax(h, axis=1)
# 概率最大的那个就是对应类
h_arg = h_arg + 1
# 加一是因为Python索引从0开始
return h_arg
1.9 Evalute model
看看预测结果怎么样:
all_theta = training(x, y, 1, 10)
# 返回theta矩阵
print('fin_theta:',all_theta)
def evalute_model(theta,x,y):
# 定义函数
y_pred = model_predict(x, theta)
# 返回模型预测列表
accuracy = [ 1 if i==j else 0 for (i,j) in zip (y_pred,y)]
# 返回列表,其中1表示预测准确(即预测标签和实际标签相符),0表示预测错误
accuracy= np.mean(accuracy)
# 计算精度
print ('accuracy = {0}%'.format(accuracy * 100))
evalute_model(all_theta,x,y)
输出如下:
已经很好了,再高就该注意是不是过拟合了(把
设为0,就能看到准确率在97%+,显然是出现了过拟合)
1.10 All
最后,给出完整代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.io import loadmat
from scipy.optimize import minimize
def load_data(path):
data=loadmat(path)
x=data['X']
y=data['y']
return data,x,y
data,x,y=load_data('ex3data1.mat')
#print(data)
print(x.shape)
print(y.shape)
#print(np.unique(y))
def view_data():
data_index=np.random.randint(0,5000,200)
data_sample=x[data_index,:]
fig,ax=plt.subplots(nrows=20,ncols=10,sharex=True,sharey=True,figsize=(12,12))
for i in range(20):
for j in range(10):
ax[i,j].matshow(data_sample[i+j*20].reshape((20,20)),cmap='gray_r')
plt.xticks([])
plt.yticks([])
plt.show()
view_data()
def data_preprocess(x,y,data):
x = np.insert(x, 0, 1, axis=1)
y = y.flatten()
return x,y
x,y=data_preprocess(x,y,data)
theta=np.zeros((x.shape[1]))
#print(theta[1])
#print(theta)
print(theta.shape)
def sigmoid(z):
return 1/(1+np.exp(-z))
def regularized_costfunction(theta,x,y,l):
h=x@theta
J=(-y)*np.log(sigmoid(h))-(1-y)*np.log(1-sigmoid(h))
reg=theta[1:]@theta[1:]
cost=sum(J)/len(x)+reg*l/(2*len(x))
return cost
cost=regularized_costfunction(theta,x,y,1)
print('cost:',cost)
def regularized_gradient(theta,x,y,l):
h=x@theta
G=x.T@(sigmoid(h)-y)
reg=theta[1:]
reg=np.insert(reg,0,1,axis=0)
gradient=G/len(x)+reg*l/len(x)
return gradient
def training(x,y,l,c):
all_theta=np.zeros((c,x.shape[1]))
for i in range(1,c+1):
theta=np.zeros(x.shape[1])
y_i=np.array([1 if label ==i else 0 for label in y])
result=minimize(fun=regularized_costfunction,x0=theta,args=(x,y_i,l),method='TNC',jac=regularized_gradient)
all_theta[i-1,:]=result.x
return all_theta
def model_predict(x, all_theta):
h = sigmoid(x @ all_theta.T)
h_arg = np.argmax(h, axis=1)
h_arg = h_arg + 1
return h_arg
all_theta = training(x, y, 1, 10)
print('fin_theta:',all_theta)
def evalute_model(theta,x,y):
y_pred = model_predict(x, theta)
accuracy = [ 1 if i==j else 0 for (i,j) in zip (y_pred,y)]
accuracy= np.mean(accuracy)
print ('accuracy = {0}%'.format(accuracy * 100))
evalute_model(all_theta,x,y)
这里模型应用的画需要一张图片,然后处理成20*20的灰度图像输进去看效果。
未经允许,请勿转载。
欢迎交流。