机器学习入门实践--线性模型-多分类问题(python)

本文不涉及细节理论,只做必要性的介绍,侧重代码实现。

线性模型-多分类问题的理论分析

只有二分类是完全不够用的,因此需要其他的算法来解决多分类问题。

多分类分为OvO(One vs One)和OvR(One vs Rest).

  • OvO:一对一,例如n个分类,两两一组使用二分类,最后选出二分类出来最多的情况,需要n(n-1)/2个分类器
  • OvR:一对多,例如n个分类,一次性比较这n个分类中的概率,找出概率最大的分类情况.

这里主要讨论OvR分类器.

例如识别数字0-9有10种情况。

多分类问题模型是从二分类延申出来的。类比二分类即可学习。

1.确定拟合函数h(x)

从单样本开始
对 于 一 组 样 本 { x , y = j } j ∈ [ 1 , k ] 来 说 。 对 于 x 的 预 测 结 果 可 能 有 多 个 , 如 何 确 定 最 终 的 结 果 呢 ? 判 断 概 率 P ( y = j ∣ θ , x ) , 那 个 概 率 更 大 , 就 预 测 那 个 值 用 h θ ( x ) 表 示 就 是 : 预 测 结 果 h θ ( x ) = { P ( y = 1 ∣ θ , x ) P ( y = 2 ∣ θ , x ) . . . P ( y = k ∣ θ , x ) 从 中 选 择 合 适 的 那 个 概 率 如 何 确 定 概 率 分 布 呢 一 个 x 和 θ 只 能 确 定 一 个 值 , 因 此 x 不 变 的 情 况 下 , 改 变 θ 可 以 获 得 不 同 的 概 率 值 即 我 们 对 每 种 预 测 结 果 都 拟 合 一 个 θ , 判 断 在 那 种 θ 下 的 拟 合 程 度 最 高 即 可 , 判 断 y = j 的 θ 记 为 θ ( j ) P ( y = l ∣ θ , x ) = e θ ( l ) x ∑ j = 1 k e θ ( j ) x 即 : h θ ( x ) = { P ( y = 1 ∣ θ , x ) P ( y = 2 ∣ θ , x ) . . . P ( y = k ∣ θ , x ) = 1 ∑ j = 1 k e θ ( j ) x [ e θ ( 1 ) x e θ ( 2 ) x . . . e θ ( k ) x ] \begin{aligned} & 对于一组样本\{x,y=j\}j\in[1,k]来说。\\ & 对于x的预测结果可能有多个,如何确定最终的结果呢?\\ & 判断概率P(y=j|\theta,x),那个概率更大,就预测那个值\\ & 用h_\theta(x)表示就是:\\ & 预测结果h_\theta(x)= \left\{\begin{matrix} P(y=1|\theta,x)\\ P(y=2|\theta,x)\\ ...\\ P(y=k|\theta,x) \end{matrix}\right.从中选择合适的那个概率\\ & 如何确定概率分布呢\\ & 一个x和\theta只能确定一个值,因此x不变的情况下,改变\theta可以获得不同的概率值\\ & 即我们对每种预测结果都拟合一个\theta,判断在那种\theta下的拟合程度最高即可,判断y=j的\theta记为\theta^{(j)}\\ & P(y=l|\theta,x)=\frac{e^{\theta^{(l)}x}}{\sum_{j=1}^k e^{\theta^{(j)}x}}\\ & 即:\\ & h_\theta(x)= \left\{\begin{matrix} P(y=1|\theta,x)\\ P(y=2|\theta,x)\\ ...\\ P(y=k|\theta,x) \end{matrix}\right.=\frac{1}{\sum_{j=1}^k e^{\theta^{(j)}x}} \begin{bmatrix} e^{\theta^{(1)}x}\\ e^{\theta^{(2)}x}\\ ...\\ e^{\theta^{(k)}x} \end{bmatrix} \end{aligned} {x,y=j}j[1,k]xP(y=jθ,x)hθ(x)hθ(x)=P(y=1θ,x)P(y=2θ,x)...P(y=kθ,x)xθxθθ,θ,y=jθθ(j)P(y=lθ,x)=j=1keθ(j)xeθ(l)x:hθ(x)=P(y=1θ,x)P(y=2θ,x)...P(y=kθ,x)=j=1keθ(j)x1eθ(1)xeθ(2)x...eθ(k)x
对于多样本,我们只需要对每个样本都进行h(x)即可。
对 于 多 样 本 { ( x ( 1 ) , y ( 1 ) ) , . . . , ( x ( m ) , y ( m ) ) } h θ ( x ( i ) ) = { P ( y ( i ) = 1 ∣ θ , x ( i ) ) P ( y ( i ) = 2 ∣ θ , x ( i ) ) . . . P ( y ( i ) = k ∣ θ , x ( i ) ) = [ e θ ( 1 ) x ( i ) ∑ j = 1 k e θ ( j ) x ( i ) e θ ( 2 ) x ( i ) ∑ j = 1 k e θ ( j ) x ( i ) . . . e θ ( k ) x ( i ) ∑ j = 1 k e θ ( j ) x ( i ) ] = 1 ∑ j = 1 k e θ ( j ) x ( i ) [ e θ ( 1 ) x ( i ) e θ ( 2 ) x ( i ) . . . e θ ( k ) x ( i ) ] 对于多样本\{(x^{(1)},y^{(1)}),...,(x^{(m)},y^{(m)})\}\\ h_\theta(x^{(i)})= \left\{\begin{matrix} P(y^{(i)}=1|\theta,x^{(i)})\\ P(y^{(i)}=2|\theta,x^{(i)})\\ ...\\ P(y^{(i)}=k|\theta,x^{(i)}) \end{matrix}\right.= \begin{bmatrix} \frac{e^{\theta^{(1)}x^{(i)}}}{\sum_{j=1}^k e^{\theta^{(j)}x^{(i)}}}\\ \frac{e^{\theta^{(2)}x^{(i)}}}{\sum_{j=1}^k e^{\theta^{(j)}x^{(i)}}}\\ ...\\ \frac{e^{\theta^{(k)}x^{(i)}}}{\sum_{j=1}^k e^{\theta^{(j)}x^{(i)}}} \end{bmatrix}=\frac{1}{\sum_{j=1}^k e^{\theta^{(j)}x^{(i)}}} \begin{bmatrix} e^{\theta^{(1)}x^{(i)}}\\ e^{\theta^{(2)}x^{(i)}}\\ ...\\ e^{\theta^{(k)}x^{(i)}} \end{bmatrix} {(x(1),y(1)),...,(x(m),y(m))}hθ(x(i))=P(y(i)=1θ,x(i))P(y(i)=2θ,x(i))...P(y(i)=kθ,x(i))=j=1keθ(j)x(i)eθ(1)x(i)j=1keθ(j)x(i)eθ(2)x(i)...j=1keθ(j)x(i)eθ(k)x(i)=j=1keθ(j)x(i)1eθ(1)x(i)eθ(2)x(i)...eθ(k)x(i)

2.确定损失函数J(θ)

损失函数类比我们的二分类损失函数:

仍先从单样本看起
二 分 类 损 失 函 数 : C o s t ( θ ) = − log ⁡ ( h θ ( x ) ) i f   y = 1 C o s t ( θ ) = − log ⁡ ( 1 − h θ ( x ) ) i f   y = 0 多 分 类 损 失 函 数 : C o s t ( θ ( 1 ) ) = − log ⁡ ( h θ ( 1 ) ( x ) ) i f   y = 1 C o s t ( θ ( 2 ) ) = − log ⁡ ( h θ ( 2 ) ( x ) ) i f   y = 2 . . . C o s t ( θ ( k ) ) = − log ⁡ ( h θ ( k ) ( x ) ) i f   y = k 二分类损失函数:\\ Cost(\theta)=-\log(h_\theta(x))\qquad\quad if\ y=1\\ Cost(\theta)=-\log(1-h_\theta(x))\quad if\ y=0\\ 多分类损失函数:\\ Cost(\theta^{(1)})=-\log(h_{\theta^{(1)}}(x))\qquad if\ y=1\\ Cost(\theta^{(2)})=-\log(h_{\theta^{(2)}}(x))\qquad if\ y=2\\ ...\\ Cost(\theta^{(k)})=-\log(h_{\theta^{(k)}}(x))\qquad if\ y=k\\ :Cost(θ)=log(hθ(x))if y=1Cost(θ)=log(1hθ(x))if y=0:Cost(θ(1))=log(hθ(1)(x))if y=1Cost(θ(2))=log(hθ(2)(x))if y=2...Cost(θ(k))=log(hθ(k)(x))if y=k
对于二分类问题,我们可以使用y*log+(1-y)*log的方法来解决y=0y=1的情况,但是对于多分类,我们只能引入一个判断逻辑了。
J ( θ ) = C o s t ( θ ) = ∑ j = 1 k I { y = j } C o s t ( θ ( j ) ) = ∑ j = 1 k I { y = j } log ⁡ ( h θ ( j ) ( x ) ) 其 中 I { x } = { 0 i f   x = f a l s e 1 i f   x = t u r e 就 是 I { x } 的 条 件 为 真 , 值 为 1 , 否 则 为 0. J(\theta)=Cost(\theta)=\sum_{j=1}^k I\{y=j\}Cost(\theta^{(j)})=\sum_{j=1}^k I\{y=j\}\log(h_{\theta^{(j)}}(x))\\ 其中I\{x\}=\left\{\begin{matrix} 0 & if\ x=false\\ 1 & if\ x=ture\\ \end{matrix}\right.就是I\{x\}的条件为真,值为1,否则为0. J(θ)=Cost(θ)=j=1kI{y=j}Cost(θ(j))=j=1kI{y=j}log(hθ(j)(x))I{x}={01if x=falseif x=tureI{x}10.
对于多样本,只需要将单样本的代价函数加和起来即可:
J ( θ ) = − 1 m ∑ i = 1 m C o s t ( θ ) = − 1 m ∑ i = 1 m ∑ j = 1 k I { y ( i ) = j } C o s t ( θ ( j ) ) = − 1 m ∑ i = 1 m ∑ j = 1 k I { y ( i ) = j } log ⁡ ( h θ ( j ) ( x ( i ) ) ) = − 1 m ∑ i = 1 m ∑ j = 1 k I { y ( i ) = j } log ⁡ e θ ( j ) x ∑ l = 1 k e θ ( l ) x \begin{aligned} & J(\theta)=-\frac{1}{m}\sum_{i=1}^mCost(\theta)\\ &\quad =-\frac{1}{m}\sum_{i=1}^m\sum_{j=1}^k I\{y^{(i)}=j\}Cost(\theta^{(j)})\\ &\quad=-\frac{1}{m}\sum_{i=1}^m\sum_{j=1}^k I\{y^{(i)}=j\}\log(h_{\theta^{(j)}}(x^{(i)}))\\ &\quad=-\frac{1}{m}\sum_{i=1}^m\sum_{j=1}^k I\{y^{(i)}=j\}\log\frac{e^{\theta^{(j)}x}}{\sum_{l=1}^ke^{\theta^{(l)}x}}\\ \end{aligned} J(θ)=m1i=1mCost(θ)=m1i=1mj=1kI{y(i)=j}Cost(θ(j))=m1i=1mj=1kI{y(i)=j}log(hθ(j)(x(i)))=m1i=1mj=1kI{y(i)=j}logl=1keθ(l)xeθ(j)x

3.梯度下降求解

使用梯度下降求使得损失函数最小的θ。同步更新θ

考虑二分类梯度下降:
θ j : = θ j + α ∂ ∂ θ j J ( θ ) j ∈ [ 1 , n ] 是 特 征 的 个 数 \theta_j:=\theta_j+\alpha\frac{\partial}{\partial \theta_j}J(\theta)\\ j\in[1,n]是特征的个数 θj:=θj+αθjJ(θ)j[1,n]
二分类梯度下降可以使用矩阵乘法,同步更新。

对于多分类问题,只需要依次计算各各分类的θ即可
对 于 { x ( i ) , y ( i ) } 样 本 中 , 预 测 y ( i ) ∈ [ 1 , k ] 是 k 个 分 类 , j ∈ [ 1 , n ] 是 特 征 数 对 于 P ( y ( i ) = 1 ∣ x , θ ) 的 情 况 : θ j ( 1 ) : = θ j ( 1 ) + α ∂ ∂ θ j ( 1 ) J ( θ ) . . . 对 于 P ( y ( i ) = l ∣ x , θ ) 的 情 况 : θ j ( l ) : = θ j ( l ) + α ∂ ∂ θ j ( l ) J ( θ ) . . . 对 于 P ( y ( i ) = k ∣ x , θ ) 的 情 况 : θ j ( k ) : = θ j ( k ) + α ∂ ∂ θ j ( k ) J ( θ ) 对于\{x^{(i)},y^{(i)}\}样本中,预测y^{(i)}\in[1,k]是k个分类,j\in[1,n]是特征数\\ 对于P(y^{(i)}=1|x,\theta)的情况:\theta_j^{(1)}:=\theta_j^{(1)}+\alpha\frac{\partial}{\partial \theta_j^{(1)}}J(\theta)\\ ...\\ 对于P(y^{(i)}=l|x,\theta)的情况:\theta_j^{(l)}:=\theta_j^{(l)}+\alpha\frac{\partial}{\partial \theta_j^{(l)}}J(\theta)\\ ...\\ 对于P(y^{(i)}=k|x,\theta)的情况:\theta_j^{(k)}:=\theta_j^{(k)}+\alpha\frac{\partial}{\partial \theta_j^{(k)}}J(\theta)\\ {x(i),y(i)}y(i)[1,k]k,j[1,n]P(y(i)=1x,θ):θj(1):=θj(1)+αθj(1)J(θ)...P(y(i)=lx,θ):θj(l):=θj(l)+αθj(l)J(θ)...P(y(i)=kx,θ):θj(k):=θj(k)+αθj(k)J(θ)
求导:
θ j ( l ) : = θ j ( l ) + α ∂ ∂ θ j ( l ) J ( θ ) θ j ( l ) : = θ j ( l ) + α ∂ ( − 1 m ∑ i = 1 m ∑ p = 1 k I { y ( i ) = p } log ⁡ ( h θ ( p ) ( x ( i ) ) ) ) ∂ θ j ( l ) θ j ( l ) : = θ j ( l ) − α 1 m ∑ i = 1 m [ x ( i ) ∗ ( 1 ∗ I { y ( i ) = l } − e θ j ( l ) x ∑ p = 1 k e θ j ( p ) x ) ] θ j ( l ) : = θ j ( l ) − α 1 m ∑ i = 1 m [ x ( i ) ∗ ( I { y ( i ) = l } − P ( y ( i ) = l ∣ x ( i ) , θ ) ) ] \begin{aligned} & \theta_j^{(l)}:=\theta_j^{(l)}+\alpha\frac{\partial}{\partial \theta_j^{(l)}}J(\theta)\\ & \theta_j^{(l)}:=\theta_j^{(l)}+\alpha\frac{\partial(-\frac{1}{m}\sum_{i=1}^m\sum_{p=1}^k I\{y^{(i)}=p\}\log(h_{\theta^{(p)}}(x^{(i)})))}{\partial \theta_j^{(l)}}\\ & \theta_j^{(l)}:=\theta_j^{(l)}-\alpha\frac{1}{m}\sum_{i=1}^m[x^{(i)}*(1*I\{y^{(i)}=l\}-\frac{e^{\theta^{(l)}_j x}}{\sum_{p=1}^k e^{\theta^{(p)}_jx}})]\\ & \theta_j^{(l)}:=\theta_j^{(l)}-\alpha\frac{1}{m}\sum_{i=1}^m[x^{(i)}*(I\{y^{(i)}=l\}-P(y^{(i)}=l|x^{(i)},\theta))]\\ \end{aligned} θj(l):=θj(l)+αθj(l)J(θ)θj(l):=θj(l)+αθj(l)(m1i=1mp=1kI{y(i)=p}log(hθ(p)(x(i))))θj(l):=θj(l)αm1i=1m[x(i)(1I{y(i)=l}p=1keθj(p)xeθj(l)x)]θj(l):=θj(l)αm1i=1m[x(i)(I{y(i)=l}P(y(i)=lx(i),θ))]
这里的j表示的是第l种分类中底j个特征值.

通过l和j的组合,可以得到多分类问题l*j所有的θ权重.

下面就是完整的求导推导过程,如果不想看的可以直接跳到下一断,因为废话着实多

手动求导时,我习惯写作
θ ( l ) : = θ ( l ) + α ∂ ∂ θ ( l ) J ( θ ) \theta^{(l)}:=\theta^{(l)}+\alpha\frac{\partial}{\partial \theta^{(l)}}J(\theta)\\ θ(l):=θ(l)+αθ(l)J(θ)
省略了j,因为直接使用矩阵乘法,可以一步得出整个第l个分类的θ情况.还可避免变量过多导致的头昏眼花

下面有两种求导化简过程,(其实本质都一样,只是看那个更方便理解一点)

完整求导推导

首先将求导公式变为这个式子:
∂ J ( θ ) ∂ θ ( l ) = ∂ ∂ θ ( l ) ( log ⁡ e θ ( l ) x ∑ p = 1 k e θ ( p ) x ) \frac{\partial J(\theta)}{\partial \theta^{(l)}}=\frac{\partial}{\partial\theta^{(l)}}(\log\frac{e^{\theta^{(l)}x}}{\sum_{p=1}^k e^{\theta^{(p)}x}})\\ θ(l)J(θ)=θ(l)(logp=1keθ(p)xeθ(l)x)
化简过程:

机器学习入门实践--线性模型-多分类问题(python)_第1张图片

化简到这一步后,就可以比较方便的求导了

之后,我把I{y=j}省略了,其实每一项都是要乘进去的.

第一种求导方法

直接求导,用分式求导法.

机器学习入门实践--线性模型-多分类问题(python)_第2张图片

第二种求导方法

先拆开,再求导

机器学习入门实践--线性模型-多分类问题(python)_第3张图片

求完导后,即可考虑算法步骤了

4.算法步骤

算法步骤参考之前的二分类算法
S t e p 1 : 随 机 一 个 θ 矩 阵 S t e p 2 : 重 复 进 行 梯 度 下 降 求 取 θ 确 定 步 长 α 同 步 更 新 θ j ( l ) : = θ j ( l ) + α ∂ ∂ θ j ( l ) J ( θ ) S t e p 3 : 找 打 合 适 的 θ 终 止 循 环 \begin{aligned} & Step1:随机一个\theta矩阵\\ & Step2:重复进行梯度下降求取\theta\\ & \qquad 确定步长\alpha\\ & \qquad 同步更新\theta_j^{(l)}:=\theta_j^{(l)}+\alpha\frac{\partial}{\partial \theta_j^{(l)}}J(\theta)\\ & Step3:找打合适的\theta终止循环 \end{aligned} Step1:θStep2:θαθj(l):=θj(l)+αθj(l)J(θ)Step3:θ

线性模型-多分类问题的python实践

根据以上分析,参考二分类问题的代码,依次进行功能实现.

1.拟合函数h(x)实现

在一个空白目录下,新建文件softmaxRegressionTrain.py文件

直接矩阵乘法求出分子矩阵,然后矩阵乘法求出分母矩阵,然后相除即可.

import numpy as np

def forecastFunction(theta,x):
    '''
    forecastFunction()函数将输入的x求预测
    输入:theta模型(k*n)的矩阵
         x变量(m*n)的矩阵
    输出:预测值矩阵(m*k)
    '''
    m=np.shape(x)[0]
    a=np.exp((x*(theta.T)))#得到预测值分子矩阵(m*k)
    sum=a*np.mat(np.ones((k,1)))#得到分母矩阵(m*1)
    for i in range(m):
        a[i]=a[i]/sum[i]
    return a

自行测试,输如果用theta全1的矩阵,应该结果全是一样的.

2.代价函数J(θ)实现

在拟合函数下继续写代价函数

直接将上面的公式翻译一下即可,非常简单

def errCost(fc,y):
    '''
    errCost()函数,通过预测输出和样本输出来计算代价
    输入:fc一个m*k的预测矩阵
         y是一个(m*1)的样本矩阵
    输出:代价值
    '''
    m=np.shape(fc)[0]
    k=np.shape(fc)[1]
    sumCost=0.0
    for i in range(m):
        if (fc[i,y[i]])>0:
            sumCost+=np.log(fc[i,y[i]])
        else:
            sumCost+=0
    return sumCost/m

3.使用梯度下降求解

根据前文算法步骤,直接计算即可

这里计算的时候,我先全设为(0-P),对于(1-P)的我单独加上去,清晰很多.

def loopGradientDescent(alpha,x,y,k,cnt):
    '''
    loopGradientDescent()函数,用来循环梯度下降求解
    输入:aplha步长
         x一个m*n的样本矩阵
         y一个m*1的样本输出矩阵
         k多分类数量
         cnt循环次数
    输出:一个k*n的矩阵
    '''
    m=np.shape(x)[0]
    n=np.shape(x)[1]
    theta=np.mat(np.ones((k,n)))
    for i in range(cnt):#迭代cnt次
        fc=forecastFunction(theta,x)#获取预测数据m*k
        sumCost=errCost(fc,y)#查看预测误差
        fc=(-1)*fc#先都按(0-fc)算
        for j in range(m):#符合条件的+1
            fc[j,y[j]]+=1
        theta=theta+(alpha/m)*(((x.T)*fc).T)#调用公式
        if i%200==0:
            print("第"+str(i)+"次迭代:")
            print("误差:"+str(sumCost))
            print("theta:")
            print(theta)
    return theta

以上就是softmax算法的所有代码了,我们将其补全(存取数据和模型)

4.存取数据与模型

数据随机使用我们之前写好的随机数据生成器,改一些参数就好了

机器学习入门实践–线性模型-分类算法-二分类问题(python)随机数据的代码,在这篇文章的中间 数据存取与模型存取的数据获取 段落地方.当然,也可以自己写随机数生成器.

继续接着上面的代码写

def loadData(fileName):
    '''
    loadData()通过文件名导入训练数据
    输出:返回一个x矩阵m*n的
         返回一个y矩阵m*1的
         返回一个y的标签数目len
    '''
    f=open(fileName)
    x=[]
    y=[]
    for line in f.readlines():
        tmpX=[]
        tmpX.append(1)
        lines=line.strip().split("\t")
        for i in range(len(lines)-1):
            tmpX.append(float(lines[i]))
        y.append(int(lines[-1]))
        x.append(tmpX)
    f.close()
    return np.mat(x),np.mat(y).T,len(set(y))

def saveModel(fileName,theta):
    '''
    saveModel()函数将模型存入本地
    输入:fileName文件名
         theta一个m*k的矩阵
    '''
    f=open(fileName,"w")
    m=np.shape(theta)[0]
    k=np.shape(theta)[1]
    for i in range(m):
        tmpT=[]
        for j in range(k):
            tmpT.append(str(theta[i,j]))
        f.write("\t".join(tmpT)+"\n")
    f.close()

if __name__=='__main__':
    #获取数据
    x,y,k=loadData("trainData")
    #获取模型
    theta=loopGradientDescent(0.001,x,y,k,5000)
    #保存模型
    saveModel("ModelData",theta)
    
'''样例输出
第0次迭代:
误差:[[-1.38629436]]
theta:
[[0.99995    1.00028712 1.00021154]
 [0.99998704 0.99975843 0.99844126]
 [1.00001667 0.99988445 1.00145407]
 [1.0000463  1.00007001 0.99989313]]
第200次迭代:
误差:[[-1.18197412]]
theta:
[[0.98882917 1.05378555 1.03128921]
 [1.01666191 0.95677654 0.87092004]
 [0.982151   0.97562871 1.08728472]
 [1.01235792 1.0138092  1.01050603]]
第400次迭代:
误差:[[-1.13961024]]
theta:
[[0.97628497 1.10045183 1.04581596]
 [1.04203359 0.91809883 0.82746232]
 [0.95704909 0.95514268 1.10339652]
 [1.02463234 1.02630666 1.02332519]]
 .....
 .....
 第4200次迭代:
误差:[[-0.89919939]]
theta:
[[0.76006369 1.4816234  1.09019137]
 [1.47815438 0.50354178 0.67924992]
 [0.52692209 0.8719239  1.18748345]
 [1.23485984 1.14291091 1.04307526]]
第4400次迭代:
误差:[[-0.89334303]]
theta:
[[0.75002682 1.49039632 1.09181997]
 [1.4966069  0.49248418 0.67460443]
 [0.50765156 0.87146402 1.19054465]
 [1.24571472 1.14565547 1.04303095]]
第4600次迭代:
误差:[[-0.88772988]]
theta:
[[0.74008448 1.49865807 1.09344813]
 [1.5147469  0.4820644  0.67002751]
 [0.48864235 0.87106069 1.19355832]
 [1.25652626 1.14821684 1.04296605]]
第4800次迭代:
误差:[[-0.88233867]]
theta:
[[0.73023336 1.50644708 1.09507391]
 [1.53259155 0.47224084 0.66552003]
 [0.46988391 0.8707044  1.19652528]
 [1.26729118 1.15060768 1.04288078]]
'''

我们已经将训练好的模型保存了下来

接下来就是使用训练好的模型了

模型的使用

新建一个文件test.py,用来使用我们的模型

1.使用流程分析

S t e p 1 : 导 入 我 们 训 练 好 的 逻 辑 回 归 模 型 ( 之 前 保 存 在 本 地 的 m o d e l D a t a 文 件 ) S t e p 2 : 导 入 测 试 集 数 据 , 我 们 要 拟 合 的 数 据 S t e p 3 : 按 照 回 归 模 型 对 数 据 进 行 预 测 S t e p 4 : 保 存 最 终 预 测 结 果 存 入 本 地 \begin{aligned} & Step1:导入我们训练好的逻辑回归模型(之前保存在本地的modelData文件)\\ & Step2:导入测试集数据,我们要拟合的数据\\ & Step3:按照回归模型对数据进行预测\\ & Step4:保存最终预测结果存入本地\\ \end{aligned} Step1:(modelData)Step2:Step3:Step4:

2.数据的导入

import numpy as np
import softmaxRegressionTrain as SRT

def loadModel(fileName):
	'''
        loadModel()函数,根据文件名提取出模型theta,并返回一个n*1的矩阵
	输入:fileName文件名
	输出:一个(k*n)的矩阵,作为模型
	'''
	f=open(fileName)
	theta=[]
	for line in f.readlines():#遍历文件每一行(这里只有一行)
		tmpt=[]
		lines=line.strip().split("\t")#格式化后,用\t分割字符串
		for x in lines:
			tmpt.append(float(x))#将每一行的每一个字符串转为浮点数保存入列表中
		theta.append(tmpt)#将该行的值
	f.close()
	return np.mat(theta)

def loadData(fileName,n):
        '''
        loadData()函数,通过文件名获取文件的数据,最后输出一个m*n的矩阵,作为样本
        输入:fileName文件名
        输出:一个(m*n)的矩阵,作为样本
        '''
        f=open(fileName)
        x=[]
        for line in f.readlines():
                tmpx=[]
                lines=line.strip().split("\t")
                if len(lines) != (n-1):#对于不合格的数据不要
                        continue
                tmpx.append(1)#先加入一个常数项
                for i in lines:#加入后续的特征值
                        tmpx.append(float(i))
                x.append(tmpx)
        f.close()
        return np.mat(x)

3.结果预测

直接使用我们的模型中的预测函数即可

def predict(x,theta):
    '''
    predict()调用训练模型来预测结果
    输出:一个m*k的矩阵,表示的概率
    '''
    y=SRT.forecastFunction(theta,x)
    return y

4.结果保存

def saveY(fileName,y):
    '''
    保存结果
    '''
    f=open(fileName,"w")
    m=np.shape(y)[0]
    k=np.shape(y)[1]
    for i in range(m):
        for j in range(k):
            f.write(str(y[i,j]))
            f.write("\t")
        f.write("\n")
    f.close()
   
if __name__=="__main__":
    #导入模型
    theta=loadModel("modelData")
    k=np.shape(theta)[0]
    n=np.shape(theta)[1]
    #导入数据
    x=loadData("testData",n)
    #预测结果
    y=predict(x,theta)
    #保存结果
    saveY("predictY",y)

补充: softmax算法参数冗余问题

在softmax regression算法种存在着参数冗余问题.(换句话说,有些参数,向量是没有用处的)

参考书中的解释
P ( y ( i ) = j ∣ X ( i ) ; θ ) = e ( θ j − ψ ) T X ( i ) ∑ l = 1 k e ( θ l − ψ ) T X ( i ) = e θ j T X ( i ) ∗ e − ψ T X ( i ) ∑ l = 1 k e θ j T X ( i ) ∗ e − ψ T X ( i ) = e θ j T X ( i ) ∑ l = 1 k e θ j T X ( i ) \begin{aligned} P(y^{(i)}=j|X^{(i)};\theta) & =\frac{e^{(\theta_j-\psi)^TX^{(i)}}}{\sum^{k}_{l=1}e^{(\theta_l-\psi)^TX^{(i)}}}\\ & =\frac{e^{\theta_j^T X^{(i)}}*e^{-\psi^T X^{(i)}}}{\sum^{k}_{l=1}e^{\theta_j^T X^{(i)}}*e^{-\psi^T X^{(i)}}}\\ & =\frac{e^{\theta_j^T X^{(i)}}}{\sum^{k}_{l=1}e^{\theta_j^T X^{(i)}}} \end{aligned} P(y(i)=jX(i);θ)=l=1ke(θlψ)TX(i)e(θjψ)TX(i)=l=1keθjTX(i)eψTX(i)eθjTX(i)eψTX(i)=l=1keθjTX(i)eθjTX(i)
参数Θ减去了向量ψ之后对预测结果没有什么影响.

意思就是,这个模型中,存在多组最优解,即使训练后,去除某些向量,也是可以得出去除向量后的最优解的.

总结

有了前面的二分类的基础,写多分类就简单多了.

其实和上一篇博客二分类一样,

  • 二分类是0,1,只需要一个theta就可区分,比较概率.选择高概率的结果.
  • 多分类是多个分类,需要多个theta区分,比较概率,选择高概率的结果

完整代码

完整代码放在了gitee中:机器学习入门实践: 机器学习入门实践

你可能感兴趣的:(机器学习入门实践,python,分类算法)