逻辑回归的多分类问题——识别手写数字

  • 了解.mat文件
  • 读取数据划分集合
  • 测试图片
  • 损失函数
  • 认识Scipy.iptimize.minimze优化函数
  • 梯度向量
  • 优化函数


了解.mat文件

.mat文件是属于matlab的文件,具体有什么特点和属性还不知道,但对于本题中我们需要去读取,要用到python中的Scipy库下的loadmat模块吧应该,去读取.mat文件。

读取数据划分集合

import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio

data = sio.loadmat('data/ex3data1.mat')
raw_X = data['X']
raw_y = data['y']

print(data,type(data))
print(raw_X.shape,raw_y.shape)
>>> ...
>>> <type dict>
>>> (5000, 400) (5000, 1)

用到的方法:

作用

代码

读取mat文件

data = sio.loadmat(‘data/ex3data1.mat’)

用到了scipy.io模块下的.loadmat方法,专门用于读取matlab类型的文件,返回的类型是字典dict,可以从jupyter中看到raw_X的类型是array数组类型,并且猜测这是图片的二进制数组格式,本质上就是一张张照片。
可以从raw_X的形状中得知,(5000,400)中的400原本应该是二维的20x20像素的图片,为便于保存拉伸为1x400,所以5000就是5k张照片。

测试图片

def plot_image(X):
    rdm = np.random.choice(5000,100)
    images = X[rdm,:]
    print(images.shape)
    fig,ax = plt.subplots(ncols=10,nrows=10,figsize=(8,8),sharex=True,sharey=True)
    for i in range(10):
        for j in range(10):
            ax[i,j].imshow(images[10 * i + j].reshape(20,20).T,cmap='gray_r')
    plt.xticks([])
    plt.yticks([])
    plt.show()

用到的方法:

作用

代码

获取区间内的随机整数

rdm = np.random.randint(5000)

获取区间内的多个随机整数

rdm = np.random.choice(5000)

显示图片

ax.imshow(image.reshape(20,20).T,cmap = ‘gray_r’)

图片的信息都存储在raw_X的每一行中,每行的数组都是一张图片,随机选取一行,获取图片的信息后还需要对其形状进行改变,因为此时获取的是(1,400)需要转换为(20,20)的,所以在ax.imshow()方法中改变了数组的形状,显示图片的方法是ax.imshow(),第一个参数是图片的数组信息,第二个参数是颜色和底色。

多分类lasso回归 多分类变量回归分析_损失函数

损失函数

def costFunction(theta,X,y,lamda):
    A = sigmoid(X @ theta)
    first = y * np.log(A)
    second = (1 - y) * np.log(1 - A)
    reg = theta[1:] @ theta[1:] * (lamda / (2*len(X)))
    return -np.sum(first + second) / len(X) + reg

本题的损失函数,相对于非线性分类问题中的损失函数差不多,公式用的一样。

多分类lasso回归 多分类变量回归分析_梯度下降_02

认识Scipy.iptimize.minimze优化函数

因为本题比较复杂,所以我们不用自己编写梯度下降函数而是调包使用现成的方法。

多分类lasso回归 多分类变量回归分析_多分类lasso回归_03


这个方法用于优化函数(这里要优化的函数就是costFunction损失函数)

梯度向量

我们不需要自己重新编写梯度下降方法,但是我们要提供给改方法梯度向量

多分类lasso回归 多分类变量回归分析_多分类lasso回归_04


这是梯度下降函数的公式,而梯度向量就是后面那一坨。

def gradient_reg(theta,X,y,lamda):
    reg = theta[1:] * (lamda / len(X))
    reg = np.insert(reg,0,values=0,axis=0)
    first = (X.T @ (sigmoid(X @ theta) -y )) / len(X)
    return first + reg

优化函数

from scipy.optimize import minimize
def one_vs_all(X,y,lamda,K):
    n = X.shape[1]
    theta_all = np.zeros((K,n))
    for i in range(1,K+1):
        theta_i = np.zeros(n,)
        
        res = minimize(fun=costFunction,
                       x0 = theta_i,
                       args=(X,y==i,lamda),
                       method='TNC',
                       jac = gradient_reg)
        print(res)
        theta_all[i-1,:] = res.x
    return theta_all

思考原理:我们已经知道了每张图片都是以(401,1)的形状存在于X集合中,其中400个包含图片信息的参数我们都当做了特征,一共400个特征值,1个常数项,所以一会的theta形状也要是(K,401),本题一共需要10个分类器,我们把每个分类器的参数theta都整合到一个theta_all当中。

类似这样:

多分类lasso回归 多分类变量回归分析_梯度下降_05


关于预测部分:

比如有一张图片,它的shape是(401,)比作p1,让theta_all和p1相乘会得到一个长度为10的一维数组。

res = theta_all @ p1
print(res)

>>>array([-16.14447   ,  -9.78841354,  -8.40606098, -16.03911719,
        -4.68367905, -14.52251444,  -9.24265692, -12.74947102,
        -9.37451931,   6.40369668])

这10个数的值就是代表该图片中的数字分别对应0~9的概率,数值越大,则预测越有把握。比如上述代码的值就是9,真实结果也是9。